Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: simplify Adapter API #2361

Merged
merged 98 commits into from
Aug 15, 2021
Merged

feat: simplify Adapter API #2361

merged 98 commits into from
Aug 15, 2021

Conversation

balazsorban44
Copy link
Member

@balazsorban44 balazsorban44 commented Jul 12, 2021

In this PR, I am significantly simplifying the Adapter API. Hopefully, this will result in a better DX (as adding new adapters will require less boilerplate) and a better UX, as we will now merge database queries into single transactions where possible for fewer database calls and thus faster responses. 🔥

If you are using an official adapter, you won't need to do any changes.

  • Session methods
  • User methods
  • Verification token methods
  • Docs
  • Tests
  • - remove getAdapter
  • Create an experimental release and try with an adapter

Related issues: #779, #876

BREAKING CHANGE:

prisma-legacy is now gone. Use @next-auth/prisma-adapter. Any features from the old adapter will be migrated over to the new one eventually. This is done so we can require the same default set of options from all the built-in providers, rather than allowing ambiguity on what an official adapter has to support. The TypeORM adapter will probably be the only one migrated as-is, but in the future we would like to break it down to lighter-weight adapters that only support single databases.

Adapters no longer have to return a getAdapter() method, they can return the actual adapter methods instead. All the values previously being provided through the arguments of getAdapter will now be available in a more digestible format directly in the concerning methods. This behavior was created so that connections could be handled more efficiently. Our review has shown that currently, the TypeORM adapter is the only one that does not handle connections out-of-the-box, so we are going to look into how we can create a wrapper/util function to make it work in the new version. For all other adapters, this will be a huge gain, as with this new API, methods are actually overrideable without creating a whole new custom adapter! 🥳

Example:

function MySlightlyCustomAdapter(...args) {
  const adapter = AdapterFromSomeoneElse(...args)
  adapter.someMethodIWantToModify = (...args) => {
    // Much better implementation goes here.
  }
  return adapter
}

The following method names are changing:

- getSession
+ getSessionAndUser

This method now requires that you return both the user and the session as {user, session}. If any of these could not be retrieved, you will have to return null instead. (In other words, this must be a transaction.) This requires one less database call, improving the user session retrieval. Any expiry logic included in the Adapter before is now done in the core as well.

- createVerificationRequest
+ createVerificationToken

Better describes the functionality. This method no longer needs to call provider.sendVerificationRequest, we are moving this into the core. This responsibility shouldn't have fallen to the adapter in the first place.

createVerificationToken will now receive a VerificationToken object, which looks like this:

interface VerificationToken {
  identifier: string
  expires: Date
  token: string
}

The token provided is already hashed, so nothing has to be done, simply write it to your database. (Here we lift up the responsibility from the adapter to hash tokens)

- getVerificationRequest
+ useVerificationToken

Better describes the functionality. It now also has the responsibility to delete the used-up token from the database. Most ORMs should support retrieving the value while deleting it at the same time, so it will reduce the number of database calls.

- deleteVerificationRequest

This method is gone. See useVerificationToken.

Most of the method signatures have been changed, have a look at the TypeScript interface to get a better picture.

@vercel
Copy link

vercel bot commented Jul 12, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/nextauthjs/next-auth/4q1cdN9ZmakYQy9zBsorDP4LHYPc
✅ Preview: https://next-auth-git-feat-simplify-adapter-nextauthjs.vercel.app

@github-actions github-actions bot added adapters Changes related to the core code concerning database adapters core Refers to `@auth/core` test Related to testing TypeScript Issues relating to TypeScript labels Jul 12, 2021
@codecov-commenter
Copy link

codecov-commenter commented Jul 12, 2021

Codecov Report

Merging #2361 (8a2f8fa) into next (55132e5) will decrease coverage by 0.04%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##             next    #2361      +/-   ##
==========================================
- Coverage   11.56%   11.52%   -0.05%     
==========================================
  Files          85       84       -1     
  Lines        1314     1319       +5     
  Branches      370      378       +8     
==========================================
  Hits          152      152              
- Misses        966      970       +4     
- Partials      196      197       +1     
Impacted Files Coverage Δ
src/lib/errors.js 0.00% <0.00%> (ø)
src/lib/jwt.js 0.00% <ø> (ø)
src/lib/logger.js 21.05% <0.00%> (ø)
src/providers/email.js 0.00% <0.00%> (ø)
src/server/index.js 0.00% <0.00%> (ø)
src/server/lib/callback-handler.js 0.00% <0.00%> (ø)
src/server/lib/email/signin.js 0.00% <0.00%> (ø)
src/server/lib/oauth/callback.js 0.00% <0.00%> (ø)
src/server/lib/oauth/client-legacy.js 0.00% <0.00%> (ø)
src/server/lib/oauth/pkce-handler.js 0.00% <ø> (ø)
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 55132e5...8a2f8fa. Read the comment docs.

@vercel vercel bot temporarily deployed to Preview July 12, 2021 23:22 Inactive
@github-actions github-actions bot added the documentation Relates to documentation label Jul 12, 2021
@vercel vercel bot temporarily deployed to Preview July 12, 2021 23:45 Inactive
Comment on lines 9 to 11
export interface AdapterSession extends Omit<Session, "expires"> {
expires: Date
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Session["expires"] is a string by default so it can easily be passed to the client, but it makes more sense to retrieve it as Date from DB.

See: vercel/next.js#11498

import { Awaitable } from "./internals/utils"

export interface AdapterUser extends User {
emailVerified?: Date | null
Copy link
Member Author

@balazsorban44 balazsorban44 Jul 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

emailVerified is always set by createUser and can be updated by updateUser in the DB.

@vercel vercel bot temporarily deployed to Preview July 12, 2021 23:54 Inactive
@vercel vercel bot temporarily deployed to Preview July 13, 2021 00:07 Inactive
@vercel vercel bot temporarily deployed to Preview August 14, 2021 15:27 Inactive
@vercel vercel bot temporarily deployed to Preview August 14, 2021 15:28 Inactive
@vercel vercel bot temporarily deployed to Preview August 14, 2021 15:29 Inactive
@balazsorban44 balazsorban44 temporarily deployed to Preview August 14, 2021 15:29 Inactive
@vercel vercel bot temporarily deployed to Preview August 15, 2021 18:58 Inactive
Copy link
Member

@ndom91 ndom91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Copy link
Member

@ndom91 ndom91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@EarthlingDavey
Copy link

I noticed one minor thing then coding the neo4j adapter.

Most of the dates are instances of JS Date. All except account.expires, which is epoch.

Is this intentionally different, or something that should be changed?

mnphpexpert added a commit to mnphpexpert/next-auth that referenced this pull request Sep 2, 2024
BREAKING CHANGE:

`prisma-legacy` is now gone. Use `@next-auth/prisma-adapter`. Any features from the old adapter will be migrated over to the new one eventually. This is done so we can require the same default set of options from all the built-in providers, rather than allowing ambiguity on what an official adapter has to support.

The `TypeORM` adapter will probably be the only one migrated as-is, but in the future, we would like to break it down to lighter-weight adapters that only support single databases.

Adapters no longer have to return a `getAdapter()` method, they can return the actual adapter methods instead. All the values previously being provided through the arguments of `getAdapter` will now be available in a more digestible format directly in the concerning methods. This behavior was created so that connections could be handled more efficiently. Our review has shown that currently, the TypeORM adapter is the only one that does not handle connections out-of-the-box, so we are going to look into how we can create a wrapper/util function to make it work in the new version. For all other adapters, this will be a huge gain, as with this new API, methods are actually overrideable without creating a whole new custom adapter! 🥳

Example:

```js
function MySlightlyCustomAdapter(...args) {
  const adapter = AdapterFromSomeoneElse(...args)
  adapter.someMethodIWantToModify = (...args) => {
    // Much better implementation goes here.
  }
  return adapter
}
```

**The following method names are changing:**

```diff
- getSession
+ getSessionAndUser
```
This method now requires that you return both the user and the session as `{user, session}`. If any of these could not be retrieved, you will have to return `null` instead. (In other words, this must be a transaction.) This requires one less database call, improving the user session retrieval. Any expiry logic included in the Adapter before is now done in the core as well.

```diff
- createVerificationRequest
+ createVerificationToken
```
Better describes the functionality. This method no longer needs to call `provider.sendVerificationRequest`, we are moving this into the core. This responsibility shouldn't have fallen to the adapter in the first place.

`createVerificationToken` will now receive a `VerificationToken` object, which looks like this:
```ts
interface VerificationToken {
  identifier: string
  expires: Date
  token: string
}
```

The token provided is already hashed, so nothing has to be done, simply write it to your database. (Here we lift up the responsibility from the adapter to hash tokens)


```diff
- getVerificationRequest
+ useVerificationToken
```
Better describes the functionality. It now also has the responsibility to delete the used-up token from the database. Most ORMs should support retrieving the value while deleting it at the same time, so it will reduce the number of database calls.

``` diff
- deleteVerificationRequest
```
This method is gone. See `useVerificationToken`.

Most of the method signatures have been changed, have a look at the [TypeScript interface](https://github.com/nextauthjs/next-auth/blob/ba4ec5faa357457661ccf55a4981fcef0514dd9b/types/adapters.d.ts) to get a better picture.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
adapters Changes related to the core code concerning database adapters core Refers to `@auth/core` documentation Relates to documentation priority Priority fix or enhancement providers test Related to testing TypeScript Issues relating to TypeScript
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants