Compare commits

...

74 Commits

Author SHA1 Message Date
Balázs Orbán
e71118b996 chore: bump versions 2022-04-20 19:07:54 +02:00
Balázs Orbán
afdb3c8d7c fix: more strict default callback url handling 2022-04-20 18:52:24 +02:00
Raúl Marín
fd755bc29e fix(signin): set email sign-in input to "email" & "required"(#4352)
* fix(core\pages\signin.tsx): set type of built-in email sign-in input to email for browse validation
* fix(core\pages\signin.tsx): add required attribute to built-in sign-in email input

Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-15 19:12:01 +02:00
Yisu Kim
59daa0e43f fix(providers): add optional chaining to avoid nullish reference errors (#4365) 2022-04-14 16:35:54 +02:00
Simon Kirsten
58d06ed727 fix: Cleanup global __NEXTAUTH state after unmount (#4383) 2022-04-14 16:35:10 +02:00
Salah Eddine
82159d3e8f docs: remove auth from keycloack url (#4391)
in keycloak 17.0+ , There's a change in endpoints as per the official documentation (https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource) .
so the new url well be https://my-keycloak-domain.com/realms/My_Realm
2022-04-14 16:28:21 +02:00
Balázs Orbán
abb9fed7aa chore: bump versions 2022-04-14 11:09:32 +02:00
Balázs Orbán
5471c0f675 chore: use --no-workspaces
See: https://github.com/npm/cli/issues/4605#issuecomment-1076900100
2022-04-14 11:03:27 +02:00
Balázs Orbán
b2da0b38d4 chore: add --verbose 2022-04-14 10:54:20 +02:00
Balázs Orbán
b3b8d4be46 chore: log npm config list 2022-04-13 18:05:21 +02:00
Balázs Orbán
182e118d9b chore: else 2022-04-13 15:19:18 +02:00
Balázs Orbán
7183b06939 chore: write .npmrc 2022-04-13 15:18:35 +02:00
Balázs Orbán
bd10e87bf4 chore: more visible log 2022-04-13 15:08:14 +02:00
Balázs Orbán
d07abfe517 chore: log 2022-04-13 15:00:44 +02:00
Balázs Orbán
c1110cdc98 chore: don't write .npmrc 2022-04-13 14:35:57 +02:00
Balázs Orbán
8ed038d891 chore: revert 2022-04-12 17:05:40 +02:00
Balázs Orbán
b25425795b chore: CI=1 2022-04-12 17:01:16 +02:00
Balázs Orbán
ad1650a817 chore: no brackets 2022-04-12 16:52:09 +02:00
Balázs Orbán
a4a487a22a chore: NPM_TOKEN_PKG 2022-04-12 16:46:26 +02:00
Balázs Orbán
b30de36126 chore: remove cat 2022-04-12 16:36:38 +02:00
Balázs Orbán
41e4e515ad chore: cat .npmrc 2022-04-12 16:35:12 +02:00
Balázs Orbán
cde1f82e3c chore: revert 2022-04-12 16:26:55 +02:00
Balázs Orbán
c39782007b chore: pkg vs org? 2022-04-12 16:22:33 +02:00
Balázs Orbán
984a089c15 chore: ignore .npmrc 2022-04-12 16:10:04 +02:00
Balázs Orbán
26f8b8c1f1 chore: remove npm whoami 2022-04-12 16:09:27 +02:00
Balázs Orbán
afc9b43c53 chore: npm whoami 2022-04-12 16:03:02 +02:00
Balázs Orbán
cdbd9ac2e6 chore: manually upgrade dep version 2022-04-12 15:39:55 +02:00
Balázs Orbán
3d8cc316f1 chore: debug release script 2022-04-12 15:32:50 +02:00
Balázs Orbán
3b8c568f79 chore: trigger deploy 2022-04-12 15:22:57 +02:00
Balázs Orbán
16668d307d docs: revert 2022-04-12 14:17:00 +02:00
Balázs Orbán
6e15bdcb2d fix: update default callbacks.redirect 2022-04-12 14:14:35 +02:00
Yisu Kim
7a4bf038b1 Update callbacks.md (#4361)
missing async keyword
2022-04-09 22:23:26 +02:00
Francis Gulotta
11ad64f617 docs: add google oauth URI examples (#4347)
* docs: add google oauth URI examples

* Update docs/docs/providers/google.md

Co-authored-by: Lluis Agusti <hi@llu.lu>

Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-09 09:45:55 +02:00
Francis Gulotta
0a278b9297 docs: callbacks can now be relative (#4346)
* docs: callbacks can now be relative

since v4 anyway

* Update docs/docs/getting-started/client.md

Co-authored-by: Lluis Agusti <hi@llu.lu>

Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-09 09:45:19 +02:00
Francis Gulotta
8c8070f30b docs(client): fix type in signIn examples (#4308) 2022-04-07 12:58:06 +02:00
Christopher Reece
6442d089c1 docs(adapters): update providerAccount to account (#4329) 2022-04-07 12:45:41 +02:00
Francis Gulotta
63398d4c3f docs: Update JWT docs to reflect JWE changes in v4 (#4313)
* docs: Update JWT docs to reflect JWE changes in v4

This PR https://github.com/nextauthjs/next-auth/pull/3039 changed the defaults for JWT tokens to be encrypted by default (JWE). We have conflicting documentation across the docs site and readme.

Additionatlly this PR https://github.com/nextauthjs/next-auth/pull/3783 made providing a secret required in production via NEXTAUTH_SECRET or an option.

* Missed a reference

* Update docs/docs/faq.md

Co-authored-by: Nico Domino <yo@ndo.dev>

* Update docs/docs/faq.md

Co-authored-by: Nico Domino <yo@ndo.dev>

Co-authored-by: Nico Domino <yo@ndo.dev>
2022-04-05 12:48:06 +02:00
Oliver Terbu
0d54170e83 feat: added siwe tutorial (#4276)
Co-authored-by: Oliver Terbu <oliver@awoie.local>
2022-04-04 22:52:55 +02:00
Francis Gulotta
174f0d6aec chore(docs): fix Custom Client Session Handling example (#4310)
* docs: fix Custom Client Session Handling example

It made reference to a useEffect call that was no longer needed.

* Update docs/docs/getting-started/client.md

Co-authored-by: Lluis Agusti <hi@llu.lu>

Co-authored-by: Lluis Agusti <hi@llu.lu>
2022-04-04 22:11:59 +02:00
Francis Gulotta
f91b9dc03d docs: Add some more context to the adapters page (#4303)
Link the models to the adapters page to provide some context about what is passed into each function.

Co-authored-by: Nico Domino <yo@ndo.dev>
2022-04-02 12:48:19 +02:00
Sriram Jothiswaran
8763e4aeb9 chore(docs): update prisma mongodb connector required modifications (#4304)
* Update for Mongodb prisma connector 

In reference to https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#model-field-scalar-types, for scalar type String the native MongoDB type attribute is @db.String.

* Update prisma.md
2022-04-02 12:48:06 +02:00
Danny Luedke
e936c51575 Fix API directory (#4283)
Update the API directory from `pages/api/[...nextauth].ts` to `pages/api/auth/[...nextauth].ts`  so it matches the typescript example.
2022-03-29 22:44:24 +02:00
dependabot[bot]
8d7ba75bca chore(deps): bump minimist in /apps/playground-sveltekit (#4261)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-28 11:18:36 +02:00
dependabot[bot]
67038b4022 chore(deps): bump node-forge from 1.2.1 to 1.3.0 (#4262)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-28 11:18:24 +02:00
dependabot[bot]
5b7ce98a87 chore(deps): bump minimist from 1.2.5 to 1.2.6 (#4263)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-28 11:18:07 +02:00
Chandler GREFF
1c468f057d docs: fix return type in jwt decode example (#4273) 2022-03-28 11:17:52 +02:00
Nico Domino
ef22c5b835 chore(docs): add carbon ads to docs sidebar (#4250)
* chore(docs): add carbon ads to docs page

* fix: add carbon-wrap element

* fix: script in docusaurus config object

* fix: add _carbonads_js id

* fix: add script directly to sidebar

* fix: carbon ads style

* chore: bump ad container down a bit
2022-03-25 19:24:05 +01:00
Grégory D'Angelo
a912739b24 chore(docs): add full stack course (Next.js/NextAuth.js/Supabase/Prisma) (#4086)
* Add free course ""

* Adjust new entry formatting to comply with all the other resources in the page

Co-authored-by: Nico Domino <yo@ndo.dev>
2022-03-23 19:50:26 +01:00
Nico Domino
ae318788c3 chore(docs): fix broken tutorial links (#4241) 2022-03-23 19:32:24 +01:00
1000101
affa459fcc fix(docs): v3->v4 migration (#4039)
Co-authored-by: Nico Domino <yo@ndo.dev>
2022-03-23 19:18:23 +01:00
Nico Domino
b88a31ef1a chore(docs): add tutorial for avoiding corporate email scanning HEAD reqs (#3900)
* chore(docs): add tutorial for avoiding corporate email scanning HEAD requests breaking email invitations

* fix: move to internal guides section
2022-03-22 23:29:05 +01:00
Nico Domino
bc82d6555a chore(docs): add corporate proxy tutorial (#3931)
* chore(docs): add corporate proxy tutorial

* fix(docs): add details about provider proxy adjustments

* fix: add to internal guides section
2022-03-22 23:27:14 +01:00
Thang Vu
11954567c2 docs: fix markdown link in jwt options (#4197)
Co-authored-by: Nico Domino <yo@ndo.dev>
2022-03-22 22:55:21 +01:00
Thang Vu
6e28ccf84f chore(adapters): Add next-autth as devDependencies for adapters (#4226)
* Upgrade turborepo, add next-auth as dev deps

* Fix TS error

* Update adapters.json

* ignore linting
2022-03-21 21:26:37 +01:00
Deepak Prabhakara
f542b400ba updated port number (5000 is blocked by MacOS AirPlay) (#4221) 2022-03-19 09:30:21 +01:00
Piyush Priyadarshi
d1b76bc302 docs: remove unused negation operator (#4217) 2022-03-18 22:28:43 +01:00
Andreas Thomas
3f396be5d9 feat(deps): upgrade minimal peer dependency @upstash/redis@v1 (#4213)
BREAKING CHANGE

From now on, you will need a minimum version of `@upstash/redis@v1` installed if you want to use this adapter.

You can upgrade by running `npm i @upstash/redis@latest` or `yarn add @upstash/redis@latest`
2022-03-18 22:27:45 +01:00
Balázs Orbán
bf4916dd70 chore: manually bump versions 2022-03-17 19:24:08 +01:00
Balázs Orbán
5100784d72 chore: update tsconfig 2022-03-17 19:03:26 +01:00
Balázs Orbán
3853e16268 chore: downgrade turbo 2022-03-17 18:57:46 +01:00
Balázs Orbán
4c0cc9e614 chore: manually bump package versions
since the last automatic release failed to do so
2022-03-17 18:38:20 +01:00
Balázs Orbán
d0112aae61 chore: upgrade lock file 2022-03-17 16:49:37 +01:00
Balázs Orbán
e373ff2473 chore: exclude firebase 2022-03-17 15:03:39 +01:00
Balázs Orbán
6d6d0a8679 Merge branch 'main' of github.com:nextauthjs/next-auth 2022-03-17 13:51:39 +01:00
Balázs Orbán
8152752cc8 chore: exclude firebase from testing 2022-03-17 13:51:31 +01:00
Andreas Thomas
966381ac9b docs: pin @upstash/redis version to 0.2.1 (#4201)
Until we migrate to v1 there might be people installing the latest
version of @upstash/redis and then encountering errors.
With this they will at least get a warning.

This is obsolete and should be updated once
https://github.com/nextauthjs/next-auth/issues/4183 is resolved.

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2022-03-17 13:44:21 +01:00
Wayne Shih
8199c96b76 fix: update font-family stack (#4192) 2022-03-17 13:43:08 +01:00
Balázs Orbán
6a06b8e054 chore: ignore building firebase adapter 2022-03-17 13:41:58 +01:00
Thang Vu
68bab17914 fix: set module to commonjs for adapters (#4205)
* fix: set module to commonjs for adapters

* Update tsconfig.json

* Update tsconfig.json

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2022-03-17 13:36:25 +01:00
Nico Domino
47b4765941 docs: 1st party guides section (#4167)
* chore: simplify example-gatsby readme header

* chore(docs): move 1st party guides to own section
2022-03-16 00:01:29 +01:00
Simon Kirsten
6d45ad4840 fix: encode callbackUrl for custom sign-in page (#4174) 2022-03-15 23:57:52 +01:00
Alexandru Călin
e5e49aca1c docs(adapters): add dynamoDB cf ProjectionType (#4182) 2022-03-15 23:54:50 +01:00
Lluis Agusti
ea944ebb86 docs(oauth): use Mermaid for the diagram (#4147) 2022-03-15 23:54:19 +01:00
Balázs Orbán
ca8af7fcd5 chore: push tags before GitHub release 2022-03-15 23:13:08 +01:00
71 changed files with 2338 additions and 2466 deletions

View File

@@ -78,7 +78,7 @@ jobs:
yarn release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN_PKG: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN_PKG: ${{ secrets.NPM_TOKEN_PKG }}
NPM_TOKEN_ORG: ${{ secrets.NPM_TOKEN_ORG }}
release-pr:
name: Publish PR

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
# Misc
.DS_Store
.npmrc
.env
.env.local

View File

@@ -1,5 +1,7 @@
body {
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
padding: 0 1rem 1rem 1rem;
max-width: 680px;
margin: 0 auto;

View File

@@ -1,7 +1,7 @@
body {
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans,
sans-serif, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
padding: 0 1rem 1rem 1rem;
max-width: 680px;
margin: 0 auto;

View File

@@ -36,9 +36,9 @@
<style>
:global(body) {
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans,
sans-serif, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
padding: 0 1rem 1rem 1rem;
max-width: 680px;
margin: 0 auto;

View File

@@ -1201,9 +1201,9 @@ minimatch@^3.0.4:
brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
mkdirp@^0.5.1:
version "0.5.5"

View File

@@ -119,6 +119,8 @@ NextAuthTable:
KeyType: RANGE
GlobalSecondaryIndexes:
- IndexName: GSI1
Projection:
ProjectionType: ALL
KeySchema:
- AttributeName: GSI1PK
KeyType: HASH

View File

@@ -133,12 +133,22 @@ npx prisma migrate dev
### MongoDB
Prisma supports MongoDB, and so does NextAuth.js. Following the instructions of the [Prisma documentation](https://www.prisma.io/docs/concepts/database-connectors/mongodb) on the MongoDB connector, the only thing you have to change is making sure that the `id` fields are mapped correctly:
Prisma supports MongoDB, and so does NextAuth.js. Following the instructions of the [Prisma documentation](https://www.prisma.io/docs/concepts/database-connectors/mongodb) on the MongoDB connector, things you have to change are:
1. Make sure that the id fields are mapped correctly
```prisma
id String @id @default(auto()) @map("_id") @db.ObjectId
```
2. The Native database type attribute to `@db.String` from `@db.Text`.
```prisma
refresh_token String? @db.String
access_token String? @db.String
id_token String? @db.String
```
Everything else should be the same.
## Naming Conventions

View File

@@ -87,10 +87,11 @@ The default redirect callback looks like this:
```js title="pages/api/auth/[...nextauth].js"
...
callbacks: {
redirect({ url, baseUrl }) {
if (url.startsWith(baseUrl)) return url
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
else if (url.startsWith("/")) return new URL(url, baseUrl).toString()
if (url.startsWith("/")) return new URL(url, baseUrl).toString()
// Allows callback URLs on the same origin
else if (new URL(url).origin === baseUrl) return url
return baseUrl
}
}
@@ -104,7 +105,7 @@ The redirect callback may be invoked more than once in the same flow.
## JWT callback
This callback is called whenever a JSON Web Token is created (i.e. at sign
in) or updated (i.e whenever a session is accessed in the client). The returned value will be [signed and optionally encrypted](/configuration/options#jwt), and it is stored in a cookie.
in) or updated (i.e whenever a session is accessed in the client). The returned value will be [encrypted](/configuration/options#jwt), and it is stored in a cookie.
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `useSession()` will invoke this function, but only if you are using a [JWT session](/configuration/options#session). This method is not invoked when you persist sessions in a database.

View File

@@ -52,7 +52,7 @@ Sent when an account in a given provider is linked to a user in our user databas
The message object will contain:
- `user`: The user object from your adapter.
- `providerAccount`: The object returned from the provider.
- `account`: The object returned from the provider.
### session

View File

@@ -97,7 +97,7 @@ Default values for this option are shown below:
```js
session: {
// Choose how you want to save the user session.
// The default is `"jwt"`, an encrypted JWT (JWE) in the session cookie.
// The default is `"jwt"`, an encrypted JWT (JWE) stored in the session cookie.
// If you use an `adapter` however, we default it to `"database"` instead.
// You can still force a JWT session by explicitly defining `"jwt"`.
// When using `"database"`, the session cookie will only contain a `sessionToken` value,
@@ -123,7 +123,7 @@ session: {
#### Description
JSON Web Tokens can be used for session tokens if enabled with `session: { strategy: "jwt" }` option. JSON Web Tokens are enabled by default if you have not specified an adapter. JSON Web Tokens are encrypted (JWE) by default. We recommend you keep this behaviour. See the [Override JWT `encode` and `decode` methods] advanced option.(#override-jwt-encode-and-decode-methods)
JSON Web Tokens can be used for session tokens if enabled with `session: { strategy: "jwt" }` option. JSON Web Tokens are enabled by default if you have not specified an adapter. JSON Web Tokens are encrypted (JWE) by default. We recommend you keep this behaviour. See the [Override JWT `encode` and `decode` methods](#override-jwt-encode-and-decode-methods) advanced option.
#### JSON Web Token Options
@@ -495,7 +495,7 @@ jwt: {
async decode(params: {
token: string
secret: string
}: Promise<JWT | null>) {
}): Promise<JWT | null> {
// return a `JWT` object, or `null` if decoding failed
return {}
},

View File

@@ -21,8 +21,33 @@ Without going into too much detail, the OAuth flow generally has 6 parts:
5. The application requests the resource from the resource server (API) and presents the access token for authentication
6. If the access token is valid, the resource server (API) serves the resource to the application
<img src="https://i2.wp.com/blogs.innovationm.com/wp-content/uploads/2019/07/blog-open1.png" alt="OAuth Flow Diagram" /><br />
<small>Source: https://dzone.com/articles/open-id-connect-authentication-with-oauth20-author</small>
```mermaid
sequenceDiagram
participant Browser
participant App Server
participant Auth Server (Github)
Note left of Browser: User clicks on "Sign in"
Browser->>App Server: GET<br/>"api/auth/signin"
App Server->>App Server: Computes the available<br/>sign in providers<br/>from the "providers" option
App Server->>Browser: Redirects to Sign in page
Note left of Browser: Sign in options<br/>are shown the user<br/>(Github, Twitter, etc...)
Note left of Browser: User clicks on<br/>"Sign in with Github"
Browser->>App Server: POST<br/>"api/auth/signin/github"
App Server->>App Server: Computes sign in<br/>options for Github<br/>(scopes, callback URL, etc...)
App Server->>Auth Server (Github): GET<br/>"github.com/login/oauth/authorize"
Note left of Auth Server (Github): Sign in options<br> are supplied as<br/>query params<br/>(clientId, <br/>scope, etc...)
Auth Server (Github)->>Browser: Shows sign in page<br/>in Github.com<br/>to the user
Note left of Browser: User inserts their<br/>credentials in Github
Browser->>Auth Server (Github): Github validates the inserted credentials
Auth Server (Github)->>Auth Server (Github): Generates one time access code<br/>and calls callback<br>URL defined in<br/>App settings
Auth Server (Github)->>App Server: GET<br/>"api/auth/github/callback?code=123"
App Server->>App Server: Grabs code<br/>to exchange it for<br/>access token
App Server->>Auth Server (Github): POST<br/>"github.com/login/oauth/access_token"<br/>{code: 123}
Auth Server (Github)->>Auth Server (Github): Verifies code is<br/>valid and generates<br/>access token
Auth Server (Github)->>App Server: { access_token: 16C7x... }
App Server->>App Server: Generates session token<br/>and stores session
App Server->>Browser: You're now logged in!
```
For more details, check out Aaron Parecki's blog post [OAuth2 Simplified](https://aaronparecki.com/oauth-2-simplified/) or Postman's blog post [OAuth 2.0: Implicit Flow is Dead, Try PKCE Instead](https://blog.postman.com/pkce-oauth-how-to/).

View File

@@ -270,7 +270,7 @@ Ultimately if your request is not accepted or is not actively in development, yo
</summary>
<p>
NextAuth.js by default uses JSON Web Tokens for saving the user's session. However, if you use a [database adapter](/adapters/overview), the database will be used to persist the user's session. You can force the usage of JWT when using a database [through the configuration options](/configuration/options#session).
NextAuth.js by default uses JSON Web Tokens for saving the user's session. However, if you use a [database adapter](/adapters/overview), the database will be used to persist the user's session. You can force the usage of JWT when using a database [through the configuration options](/configuration/options#session). Since v4 all our JWT tokens are now encrypted by default with A256GCM.
</p>
</details>
@@ -285,11 +285,9 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
- Advantages of using a JWT as a session token include that they do not require a database to store sessions, this can be faster and cheaper to run and easier to scale.
- JSON Web Tokens in NextAuth.js are secured using cryptographic signing (JWS) by default and it is easy for services and API endpoints to verify tokens without having to contact a database to verify them.
- JSON Web Tokens in NextAuth.js are secured using cryptographic encryption (JWE) to store the included information directly in a JWT session token. You may then use the token to pass information between services and APIs on the same domain without having to contact a database to verify the included information.
- You can enable encryption (JWE) to store include information directly in a JWT session token that you wish to keep secret and use the token to pass information between services / APIs on the same domain.
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only-token so data in the JWT is not accessible to third party JavaScript running on your site.
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only cookie so data in the JWT is not accessible to third party JavaScript running on your site.
</p>
</details>
@@ -308,7 +306,7 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
- As with database session tokens, JSON Web Tokens are limited in the amount of data you can store in them. There is typically a limit of around 4096 bytes per cookie, though the exact limit varies between browsers, proxies and hosting services. If you want to support most browsers, then do not exceed 4096 bytes per cookie. If you want to save more data, you will need to persist your sessions in a database (Source: [browsercookielimits.iain.guru](http://browsercookielimits.iain.guru/))
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. If you wish to store more than ~4 KB of data you're probably at the point where you need to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing. However since this data needs to be transmitted on every request, if you wish to store more than ~4 KB of data you're probably at the point where you want to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
- Data stored in an encrypted JSON Web Token (JWE) may be compromised at some point.
@@ -316,9 +314,8 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
Avoid storing any data in a token that might be problematic if it were to be decrypted in the future.
- If you do not explicitly specify a secret for for NextAuth.js, existing sessions will be invalidated any time your NextAuth.js configuration changes, as NextAuth.js will default to an auto-generated secret.
- If you do not explicitly specify a secret for for NextAuth.js, existing sessions will be invalidated any time your NextAuth.js configuration changes, as NextAuth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
If using JSON Web Token you should at least specify a secret and ideally configure public/private keys.
</p>
</details>

View File

@@ -123,16 +123,14 @@ export default function App({
}
function Auth({ children }) {
const { data: session, status } = useSession({ required: true })
const isUser = !!session?.user
// if `{ required: true }` is supplied, `status` can only be "loading" or "authenticated"
const { status } = useSession({ required: true })
if (isUser) {
return children
if (status === 'loading') {
return <div>Loading...</div>
}
// Session is being fetched, or no user.
// If no user, useEffect() will redirect.
return <div>Loading...</div>
return children
}
```
@@ -312,11 +310,11 @@ You can specify a different `callbackUrl` by specifying it as the second argumen
e.g.
- `signIn(null, { callbackUrl: 'http://localhost:3000/foo' })`
- `signIn('google', { callbackUrl: 'http://localhost:3000/foo' })`
- `signIn(undefined, { callbackUrl: '/foo' })`
- `signIn('google', { callbackUrl: 'http://localhost:3000/bar' })`
- `signIn('email', { email, callbackUrl: 'http://localhost:3000/foo' })`
The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect-callback). By default it requires the URL to be an absolute URL at the same host name, or else it will redirect to the homepage. You can define your own [redirect callback](/configuration/callbacks#redirect-callback) to allow other URLs, including supporting relative URLs.
The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect-callback). By default it requires the URL to be an absolute URL at the same host name, or a relative url starting with a slash. If it does not match it will redirect to the homepage. You can define your own [redirect callback](/configuration/callbacks#redirect-callback) to allow other URLs.
### Using the `redirect: false` option
@@ -400,7 +398,7 @@ As with the `signIn()` function, you can specify a `callbackUrl` parameter by pa
e.g. `signOut({ callbackUrl: 'http://localhost:3000/foo' })`
The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect-callback). By default this means it must be an absolute URL at the same host name (or else it will default to the homepage); you can define your own custom [redirect callback](/configuration/callbacks#redirect-callback) to allow other URLs, including supporting relative URLs.
The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect-callback). By default, it requires the URL to be an absolute URL at the same host name, or you can also supply a relative URL starting with a slash. If it does not match it will redirect to the homepage. You can define your own [redirect callback](/configuration/callbacks#redirect-callback) to allow other URLs.
### Using the `redirect: false` option

View File

@@ -38,8 +38,7 @@ _Note: Email sign-in requires a database to be configured to store single-use ve
- Designed to be secure by default and encourage best practices for safeguarding user data
- Uses Cross-Site Request Forgery Tokens on POST routes (sign in, sign out)
- Default cookie policy aims for the most restrictive policy appropriate for each cookie
- When JSON Web Tokens are enabled, they are signed by default (JWS) with HS512
- Use JWT encryption (JWE) by setting the option `encryption: true` (defaults to A256GCM)
- When JSON Web Tokens are enabled, they are encrypted by default (JWE) with A256GCM
- Auto-generates symmetric signing and encryption keys for developer convenience
- Features tab/window syncing and keepalive messages to support short-lived sessions
- Attempts to implement the latest guidance published by [Open Web Application Security Project](https://owasp.org/)

View File

@@ -47,7 +47,7 @@ This will work in code editors with a strong TypeScript integration like VSCode
Let's look at `Session`:
```ts title="pages/api/[...nextauth].ts"
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
export default NextAuth({

View File

@@ -331,7 +331,7 @@ The way we save data with adapters have slightly changed. With the new Adapter A
- `user_id`/`userId` consistently named `userId`.
- `compound_id`/`compoundId` is removed from Account.
- `access_token`/`accessToken` is removed from Session.
- `email_verified`/`emailVerified` on User is consistently named `email_verified`.
- `email_verified`/`emailVerified` on User is consistently named `emailVerified`.
- `provider_id`/`providerId` renamed to `provider` on Account
- `provider_type`/`providerType` renamed to `type` on Account
- `provider_account_id`/`providerAccountId` on Account is consistently named `providerAccountId`
@@ -419,8 +419,8 @@ They are designed to be run directly against the database itself. So instead of
/* ACCOUNT */
ALTER TABLE accounts
CHANGE "access_token_expires" "expires_at" int
CHANGE "user_id" "userId" varchar(191)
ADD CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id)
CHANGE "user_id" "userId" varchar(255)
ADD CONSTRAINT fk_user_id FOREIGN KEY (userId) REFERENCES users(id)
RENAME COLUMN "provider_id" "provider"
RENAME COLUMN "provider_account_id" "providerAccountId"
DROP COLUMN "provider_type"
@@ -429,14 +429,14 @@ DROP COLUMN "compound_id"
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
ADD COLUMN "token_type" varchar(191) NULL
ADD COLUMN "scope" varchar(191) NULL
ADD COLUMN "id_token" varchar(191) NULL
ADD COLUMN "session_state" varchar(191) NULL
ADD COLUMN "token_type" varchar(255) NULL
ADD COLUMN "scope" varchar(255) NULL
ADD COLUMN "id_token" varchar(255) NULL
ADD COLUMN "session_state" varchar(255) NULL
/* Note: These are only needed if you're going to be using the old Twitter OAuth 1.0 provider. */
ADD COLUMN "oauth_token_secret" varchar(191) NULL
ADD COLUMN "oauth_token" varchar(191) NULL
ADD COLUMN "oauth_token_secret" varchar(255) NULL
ADD COLUMN "oauth_token" varchar(255) NULL
/* USER */
ALTER TABLE users
@@ -448,15 +448,16 @@ DROP COLUMN "updated_at"
/* SESSION */
ALTER TABLE sessions
RENAME COLUMN "session_token" "sessionToken"
CHANGE "user_id" "userId" varchar(191)
ADD CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id)
CHANGE "user_id" "userId" varchar(255)
ADD CONSTRAINT fk_user_id FOREIGN KEY (userId) REFERENCES users(id)
DROP COLUMN "access_token"
/* The following two timestamp columns have never been necessary for NextAuth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
/* VERIFICATION REQUESTS */
ALTER TABLE verification_requests
ALTER TABLE verification_requests RENAME verification_tokens
ALTER TABLE verification_tokens
DROP COLUMN id
/* The following two timestamp columns have never been necessary for NextAuth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
@@ -467,50 +468,84 @@ DROP COLUMN "updated_at"
```sql
/* ACCOUNT */
ALTER TABLE accounts RENAME COLUMN "user_id" TO "userId";
ALTER TABLE accounts RENAME COLUMN "provider_id" TO "provider";
ALTER TABLE accounts RENAME COLUMN "provider_account_id" TO "providerAccountId";
ALTER TABLE accounts RENAME COLUMN "access_token_expires" TO "expires_at";
ALTER TABLE accounts RENAME COLUMN "provider_type" TO "type";
/* Do conversion of TIMESTAMPTZ to BIGINT */
ALTER TABLE accounts ALTER COLUMN "expires_at" TYPE TEXT USING CAST(extract(epoch FROM "expires_at") AS BIGINT)*1000;
/* Keep id as SERIAL with autoincrement when using ORM. Using new v4 uuid format won't work because of incompatibility */
/* ALTER TABLE accounts ALTER COLUMN "id" TYPE TEXT; */
/* ALTER TABLE accounts ALTER COLUMN "userId" TYPE TEXT; */
ALTER TABLE accounts ALTER COLUMN "type" TYPE TEXT;
ALTER TABLE accounts ALTER COLUMN "provider" TYPE TEXT;
ALTER TABLE accounts ALTER COLUMN "providerAccountId" TYPE TEXT;
ALTER TABLE accounts ADD CONSTRAINT fk_user_id FOREIGN KEY ("userId") REFERENCES users(id);
ALTER TABLE accounts
CHANGE "access_token_expires" "expires_at" int
CHANGE "user_id" "userId" text
ADD CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id)
RENAME COLUMN "provider_id" "provider"
RENAME COLUMN "provider_account_id" "providerAccountId"
DROP COLUMN "provider_type"
DROP COLUMN "compound_id"
DROP COLUMN IF EXISTS "compound_id";
/* The following two timestamp columns have never been necessary for NextAuth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
ADD COLUMN "token_type" text NULL
ADD COLUMN "scope" text NULL
ADD COLUMN "id_token" text NULL
ADD COLUMN "session_state" text NULL
ALTER TABLE accounts
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
ALTER TABLE accounts
ADD COLUMN IF NOT EXISTS "token_type" TEXT NULL,
ADD COLUMN IF NOT EXISTS "scope" TEXT NULL,
ADD COLUMN IF NOT EXISTS "id_token" TEXT NULL,
ADD COLUMN IF NOT EXISTS "session_state" TEXT NULL;
/* Note: These are only needed if you're going to be using the old Twitter OAuth 1.0 provider. */
ADD COLUMN "oauth_token_secret" text NULL
ADD COLUMN "oauth_token" text NULL
/* ALTER TABLE accounts
ADD COLUMN IF NOT EXISTS "oauth_token_secret" TEXT NULL,
ADD COLUMN IF NOT EXISTS "oauth_token" TEXT NULL; */
/* USER */
ALTER TABLE users
RENAME COLUMN "email_verified" "emailVerified"
ALTER TABLE users RENAME COLUMN "email_verified" TO "emailVerified";
/* Keep id as SERIAL with autoincrement when using ORM. Using new v4 uuid format won't work because of incompatibility */
/* ALTER TABLE users ALTER COLUMN "id" TYPE TEXT; */
ALTER TABLE users ALTER COLUMN "name" TYPE TEXT;
ALTER TABLE users ALTER COLUMN "email" TYPE TEXT;
ALTER TABLE users ALTER COLUMN "image" TYPE TEXT;
/* Do conversion of TIMESTAMPTZ to BIGINT and then TEXT */
ALTER TABLE users ALTER COLUMN "emailVerified" TYPE TEXT USING CAST(CAST(extract(epoch FROM "emailVerified") AS BIGINT)*1000 AS TEXT);
/* The following two timestamp columns have never been necessary for NextAuth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
ALTER TABLE users
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
/* SESSION */
ALTER TABLE sessions
RENAME COLUMN "session_token" "sessionToken"
CHANGE "user_id" "userId" text
ADD CONSTRAINT fk_user_id FOREIGN KEY (user_id) REFERENCES users(id)
DROP COLUMN "access_token"
ALTER TABLE sessions RENAME COLUMN "session_token" TO "sessionToken";
ALTER TABLE sessions RENAME COLUMN "user_id" TO "userId";
/* Keep id as SERIAL with autoincrement when using ORM. Using new v4 uuid format won't work because of incompatibility */
/* ALTER TABLE sessions ALTER COLUMN "id" TYPE TEXT; */
/* ALTER TABLE sessions ALTER COLUMN "userId" TYPE TEXT; */
ALTER TABLE sessions ALTER COLUMN "sessionToken" TYPE TEXT;
ALTER TABLE sessions ADD CONSTRAINT fk_user_id FOREIGN KEY ("userId") REFERENCES users(id);
/* Do conversion of TIMESTAMPTZ to BIGINT and then TEXT */
ALTER TABLE sessions ALTER COLUMN "expires" TYPE TEXT USING CAST(CAST(extract(epoch FROM "expires") AS BIGINT)*1000 AS TEXT);
ALTER TABLE sessions DROP COLUMN IF EXISTS "access_token";
/* The following two timestamp columns have never been necessary for NextAuth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
ALTER TABLE sessions
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
/* VERIFICATION REQUESTS */
ALTER TABLE verification_requests
DROP COLUMN id
ALTER TABLE verification_requests RENAME TO verification_tokens;
/* Keep id as ORM needs it */
/* ALTER TABLE verification_tokens DROP COLUMN IF EXISTS id; */
ALTER TABLE verification_tokens ALTER COLUMN "identifier" TYPE TEXT;
ALTER TABLE verification_tokens ALTER COLUMN "token" TYPE TEXT;
/* Do conversion of TIMESTAMPTZ to BIGINT and then TEXT */
ALTER TABLE verification_tokens ALTER COLUMN "expires" TYPE TEXT USING CAST(CAST(extract(epoch FROM "expires") AS BIGINT)*1000 AS TEXT);
/* The following two timestamp columns have never been necessary for NextAuth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
ALTER TABLE verification_tokens
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
```
#### MongoDB

View File

@@ -0,0 +1,12 @@
---
id: basics
title: Basics
---
### [Securing pages and API routes](/tutorials/securing-pages-and-api-routes)
- How to restrict access to pages and API routes.
### [Usage with class components](/tutorials/usage-with-class-components)
- How to use `useSession()` hook with class components.

View File

@@ -0,0 +1,30 @@
---
id: fullstack
title: Fullstack
---
### [Refresh Token Rotation](/tutorials/refresh-token-rotation)
- How to implement refresh token rotation.
### [LDAP Authentication](/tutorials/ldap-auth-example)
- How to use the Credentials Provider to authenticate against an LDAP database. This approach can be used to authenticate existing user accounts against any backend.
### [Adding HTTP(S) Proxy Support](/tutorials/corporate-proxy)
- Add support for HTTP/HTTPS Proxy support to `openid-client` in order to use NextAuth.js behind a corporate proxy or other locked down network.
### [Using the Email Provider behind Corporate Email Scanning Services](/tutorials/avoid-corporate-link-checking-email-provider)
- An internal tutorial on modifying the catch-all API Route to gracefully handle `HEAD` requests.
## Database
### [Custom models with TypeORM](/adapters/typeorm#custom-models)
- How to use models with custom properties using the TypeORM adapter.
### [Creating a database adapter](/tutorials/creating-a-database-adapter)
- How to create a custom adapter, to use any database to fetch and store user / account data.

View File

@@ -0,0 +1,8 @@
---
id: testing
title: Testing
---
### [Testing with Cypress](/tutorials/testing-with-cypress)
- How to write tests using Cypress.

View File

@@ -30,7 +30,7 @@ import BoxyHQSAMLProvider from "next-auth/providers/boxyhq-saml"
...
providers: [
BoxyHQSAMLProvider({
issuer: "http://localhost:5000",
issuer: "http://localhost:5225",
clientId: "dummy", // The dummy here is necessary since we'll pass tenant and product custom attributes in the client code
clientSecret: "dummy", // The dummy here is necessary since we'll pass tenant and product custom attributes in the client code
})

View File

@@ -11,6 +11,11 @@ https://developers.google.com/identity/protocols/oauth2
https://console.developers.google.com/apis/credentials
The "Authorized redirect URIs" used when creating the credentials must include your full domain and end in the callback path. For example;
- For production: `https://{YOUR_DOMAIN}/api/auth/callback/google`
- For development: `http://localhost:3000/api/auth/callback/google`
## Options
The **Google Provider** comes with a set of default options:

View File

@@ -37,5 +37,5 @@ providers: [
```
:::note
`issuer` should include the realm  e.g. `https://my-keycloak-domain.com/auth/realms/My_Realm`
`issuer` should include the realm  e.g. `https://my-keycloak-domain.com/realms/My_Realm`
:::

View File

@@ -21,14 +21,6 @@ title: Tutorials and Explainers
- This tutorial walks one through adding NextAuth.js to an existing project. Including setting up the OAuth client id and secret, adding the API routes for authentication, protecting pages and API routes behind that authentication, etc.
#### [Securing pages and API routes](tutorials/securing-pages-and-api-routes)
- How to restrict access to pages and API routes.
#### [Usage with class components](tutorials/usage-with-class-components)
- How to use `useSession()` hook with class components.
#### [Adding social authentication support to a Next.js app](https://getstarted.sh/bulletproof-next/add-social-authentication) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
- A tutorial by Arunoda Susirpiala. Checkout [GetStarted](https://getstarted.sh/) for more examples.
@@ -49,8 +41,25 @@ title: Tutorials and Explainers
- A video tutorial by Xiaoru Li from Prisma.
#### [How to authenticate Next.js Apps with Sign-In With Ethereum (SIWE) & NextAuth.js](https://docs.login.xyz/integrations/nextauth.js) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
- Learn how to use Sign-In With Ethereum to authenticate your users with their existing Ethereum wallets - identifiers they personally control.
## Fullstack
#### [Build a FullStack App with Next.js, NextAuth.js, Supabase & Prisma](https://themodern.dev/courses/build-a-fullstack-app-with-nextjs-supabase-and-prisma-322389284337222224) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
In this [free course](https://themodern.dev/courses/build-a-fullstack-app-with-nextjs-supabase-and-prisma-322389284337222224), you'll learn how to build a full-stack app using the following technologies:
- **Next.js** - The React framework for building the UI of the app and the REST API
- **NextAuth.js** - For implementing passwordless and OAuth authentication
- **Supabase** - For persisting the app data into a PostgreSQL database and storing media files
- **Prisma** - For making it easy to read and write data from our app from and to the database
The app that we'll work on in this course is called ***SupaVacation***. It is an online marketplace for vacation rentals where users can browse through all the properties for rent, bookmark their favorite ones, and even rent their own properties.
> Here's [a live demo](https://supa-vacation.vercel.app/) of the app's final version. It is what your app should look likes after completing this course. Feel free to play with it to get an overview of all the features you'll be working on.
#### [Magic Link Authentication in Next.js with NextAuth and Fauna](https://alterclass.io/tutorials/magic-link-authentication-in-nextjs-with-nextauth-and-fauna) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
Learn how to implement passwordless/magic link authentication with database storage in your Next.js projects using NextAuth and Fauna DB.
@@ -75,22 +84,8 @@ This tutorial covers:
- This example shows how to implement a full-stack app in TypeScript with Next.js using Prisma Client as a backend. It also demonstrates how to implement authentication using NextAuth.js. By Nikolas Burk at Prisma.
## Testing
#### [Testing with Cypress](tutorials/testing-with-cypress)
- How to write tests using Cypress.
## Advanced
#### [Refresh Token Rotation](tutorials/refresh-token-rotation)
- How to implement refresh token rotation.
#### [LDAP Authentication](tutorials/ldap-auth-example)
- How to use the Credentials Provider to authenticate against an LDAP database. This approach can be used to authenticate existing user accounts against any backend.
#### [Add auth support to a Next.js app with a custom backend](https://arunoda.me/blog/add-auth-support-to-a-next-js-app-with-a-custom-backend) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
- A tutorial by Arunoda Susirpiala.
@@ -109,14 +104,6 @@ This tutorial covers:
## Database
#### [Custom models with TypeORM](adapters/typeorm#custom-models)
- How to use models with custom properties using the TypeORM adapter.
#### [Creating a database adapter](tutorials/creating-a-database-adapter)
- How to create a custom adapter, to use any database to fetch and store user / account data.
#### [Using NextAuth.js with Prisma and PlanetScale serverless databases](https://github.com/planetscale/nextjs-planetscale-starter)
#### [Using NextAuth.js with Prisma and PlanetScale serverless databases](https://github.com/planetscale/nextjs-planetscale-starter) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
- How to set up a PlanetScale database to fetch and store user / account data with the Prisma adapter.

View File

@@ -0,0 +1,40 @@
---
id: avoid-corporate-link-checking-email-provider
title: Allow Email Signups Behind Corporate Link Checker
---
If you use Office 365 or Outlook, or potentially other Email systems, you may notice your Email invitation Links not working.
This is because the invitation Email your User is receiving is being scanned by the Email provider. In the specific case of Outlook and their "SafeLink" feature, they send a HEAD request to each link in the Email. This request will trigger the NextAuth.js catch-all API Route with the users invitation token, in effect using it up.
Therefore, when the user wants to use it themselves, and clicks on the invitation link they will be greeted with an error message that the invitation is invalid.
## Workarounds
### Disable "SafeLink"
The first potential workaround is to simply disable this "SafeLink" feature for your organisation. Microsoft has more details on this [here](https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/safe-links?view=o365-worldwide#do-not-rewrite-the-following-urls-lists-in-safe-links-policies). Obviously this won't be an option for everyone as this is usually a part of corporate IT policy.
### Update NextAuth.js for 'HEAD' requests
The second option is to modify your `[...nextauth].js` catch-all API route a bit to gracefully handle these initial `HEAD` requests from the email service, without accidentally using up the invitation link.
This can be done by simply returning a `200` response on `HEAD` requests at the very top of the API route, before any other logic is executed.
For example
```jsx title="/pages/api/auth/[...nextauth].js"
import type { NextApiRequest, NextApiResponse } from "next"
import NextAuth from "next-auth"
export default async function auth(req: NextApiRequest, res: NextApiResponse) {
if(req.method === "HEAD") {
return res.status(200)
}
...
}
```
This should allow you to successfully use NextAuth.js's Email provider behind strict corporate IT settings.

View File

@@ -0,0 +1,83 @@
--
id: corporate-proxy
title: Add support for HTTP Proxy
--
Using NextAuth.js behind a corporate proxy is not supported out of the box. This is due to the fact that the underlying library we use, [`openid-client`](https://npm.im/openid-client), uses the built-in Node.js `http` / `https` libraries, which do not support proxys by default. (See: [`http` docs](https://nodejs.org/dist/latest-v16.x/docs/api/http.html), [`https` docs](https://nodejs.org/dist/latest-v16.x/docs/api/https.html)).
Therefore, we'll need to an additional proxy agent to the http client, such as `https-proxy-agent`. `openid-client` allows the user to set an `agent` for requests ([Source](https://github.com/panva/node-openid-client/blob/main/docs/README.md#customizing-individual-http-requests).
Thanks to [raphaelpc](https://github.com/raphaelpc) for the below diff, which when applied to `v4.2.1`, adds this agent support to the `client.js` file.
```diff
diff --git a/node_modules/next-auth/core/lib/oauth/client.js b/node_modules/next-auth/core/lib/oauth/client.js
index 77161bd..1082fba 100644
--- a/node_modules/next-auth/core/lib/oauth/client.js
+++ b/node_modules/next-auth/core/lib/oauth/client.js
@@ -7,11 +7,19 @@ exports.openidClient = openidClient;
var _openidClient = require("openid-client");
+var HttpsProxyAgent = require("https-proxy-agent");
+
async function openidClient(options) {
const provider = options.provider;
- if (provider.httpOptions) _openidClient.custom.setHttpOptionsDefaults(provider.httpOptions);
- let issuer;
+ let httpOptions = {};
+ if (provider.httpOptions) httpOptions = { ...provider.httpOptions };
+ if (process.env.http_proxy) {
+ let agent = new HttpsProxyAgent(process.env.http_proxy);
+ httpOptions.agent = agent;
+ }
+ _openidClient.custom.setHttpOptionsDefaults(httpOptions);
+ let issuer;
if (provider.wellKnown) {
issuer = await _openidClient.Issuer.discover(provider.wellKnown);
} else {
```
> For more details, see [this issue](https://github.com/nextauthjs/next-auth/issues/2509#issuecomment-1035410802)
After applying this patch, we can add the the proxy connecting string via the `http_proxy` environment variable.
### Provider
If you're having trouble with your provider when using the `https-proxy-agent`, you may be using a provider which requires an extra request to, for example, fetch the users profile picture. In cases like these, you'll have to add the proxy workaround to your provider config as well. Below is an example of how to do that with the `AzureAD` provider.
```diff
diff --git a/node_modules/next-auth/providers/azure-ad.js b/node_modules/next-auth/providers/azure-ad.js
index 73d96d3..536cd81 100644
--- a/node_modules/next-auth/providers/azure-ad.js
+++ b/node_modules/next-auth/providers/azure-ad.js
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
});
exports.default = AzureAD;
+const HttpsProxyAgent = require('https-proxy-agent');
+
function AzureAD(options) {
var _options$tenantId, _options$profilePhoto;
@@ -22,11 +24,15 @@ function AzureAD(options) {
},
async profile(profile, tokens) {
- const profilePicture = await fetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, {
+ let fetchOptions = {
headers: {
- Authorization: `Bearer ${tokens.access_token}`
- }
- });
+ Authorization: `Bearer ${tokens.access_token}`,
+ },
+ };
+ if (process.env.http_proxy) {
+ fetchOptions.agent = new HttpsProxyAgent(process.env.http_proxy);
+ }
+ const profilePicture = await fetch(`https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`, fetchOptions);
if (profilePicture.ok) {
const pictureBuffer = await profilePicture.arrayBuffer();
```

View File

@@ -7,6 +7,8 @@ Using a custom adapter you can connect to any database back-end or even several
## How to create an adapter
For more information about the data these methods need to manage see [models](/adapters/models).
_See the code below for practical example._
### Example code

View File

@@ -18,7 +18,7 @@
"lint:fix": "prettier --write .",
"generate-providers": "node ./scripts/generate-providers.js"
},
"dependencies": {
"dependencies": {
"@codesandbox/sandpack-react": "^0.13.12",
"@docusaurus/core": "^2.0.0-beta.17",
"@docusaurus/preset-classic": "^2.0.0-beta.17",

View File

@@ -74,5 +74,20 @@ module.exports = {
"warnings",
"errors",
"deployment",
{
type: "category",
label: "Guides",
collapsed: true,
items: [
"guides/basics",
"guides/fullstack",
"guides/testing",
],
},
{
type: "html",
value: '<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CEAI6K3N&placement=next-authjsorg" id="_carbonads_js"></script>',
defaultStyle: true
},
],
}

View File

@@ -26,9 +26,10 @@
--ifm-color-info: #1eb1fc;
--ifm-color-success: #1eb1fc;
--ifm-color-warning: #c94b4b;
--ifm-font-family-base: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell,
Noto Sans, sans-serif, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
--ifm-font-family-base: ui-sans-serif, system-ui, -apple-system,
BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans",
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
--ifm-background-color: #fff;
--ifm-footer-background-color: #f9f9f9;
--ifm-hero-background-color: #f5f5f5;
@@ -194,3 +195,92 @@ html[data-theme="dark"] hr {
.inline {
display: inline-block;
}
/* CarbonAds */
#carbonads * {
margin: initial;
padding: initial;
}
#carbonads {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial,
sans-serif;
}
#carbonads {
display: flex;
max-width: 330px;
background-color: hsl(0, 0%, 98%);
box-shadow: 0 1px 4px 1px hsla(0, 0%, 0%, 0.1);
z-index: 100;
margin-top: 30px;
}
#carbonads a {
color: inherit;
text-decoration: none;
}
#carbonads a:hover {
color: inherit;
}
#carbonads span {
position: relative;
display: block;
overflow: hidden;
}
#carbonads .carbon-wrap {
display: flex;
}
#carbonads .carbon-img {
display: block;
margin: 0;
line-height: 1;
}
#carbonads .carbon-img img {
display: block;
}
#carbonads .carbon-text {
font-size: 11px;
padding: 8px;
margin-bottom: 16px;
line-height: 1.5;
text-align: left;
}
#carbonads .carbon-poweredby {
display: block;
padding: 6px 8px;
background: #f1f1f2;
text-align: center;
text-transform: uppercase;
letter-spacing: 0.5px;
font-weight: 600;
font-size: 8px;
line-height: 1;
border-top-left-radius: 3px;
position: absolute;
bottom: 0;
right: 0;
}
html[data-theme="dark"] #carbonads .carbon-text {
color: #ddd;
}
html[data-theme="dark"] #carbonads > span {
background: #1a1a1a;
box-shadow: 0 0 1px hsl(0deg 0% 0% / 9%), 0 0 2px hsl(0deg 0% 0% / 9%),
0 0 4px hsl(0deg 0% 0% / 9%), 0 0 8px hsl(0deg 0% 0% / 9%);
}
html[data-theme="dark"] #carbonads .carbon-poweredby {
color: #aaa;
background: #1e2021;
}

View File

@@ -43,7 +43,7 @@
"semver": "7.3.5",
"stream-to-array": "2.3.0",
"ts-node": "10.5.0",
"turbo": "^1.1.4",
"turbo": "^1.1.6",
"typescript": "^4.5.2"
},
"engines": {

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/dgraph-adapter",
"version": "1.0.2",
"version": "1.0.3",
"description": "Dgraph adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -38,6 +38,7 @@
"@types/jsonwebtoken": "^8.5.5",
"@types/node-fetch": "^2.5.11",
"jest": "^27.0.6",
"next-auth": "^4.0.1",
"ts-jest": "^27.0.3"
},
"dependencies": {

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -1,7 +1,7 @@
{
"name": "@next-auth/dynamodb-adapter",
"repository": "https://github.com/nextauthjs/adapters",
"version": "1.0.2",
"version": "1.0.3",
"description": "AWS DynamoDB adapter for next-auth.",
"keywords": [
"next-auth",
@@ -37,6 +37,7 @@
"devDependencies": {
"@aws-sdk/client-dynamodb": "^3.36.1",
"@aws-sdk/lib-dynamodb": "^3.36.1",
"@shelf/jest-dynamodb": "^2.1.0"
"@shelf/jest-dynamodb": "^2.1.0",
"next-auth": "^4.0.1"
}
}

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/fauna-adapter",
"version": "1.0.2",
"version": "1.0.3",
"description": "Fauna Adapter for NextAuth",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -37,7 +37,8 @@
},
"devDependencies": {
"@fauna-labs/fauna-schema-migrate": "^2.1.3",
"faunadb": "^4.3.0"
"faunadb": "^4.3.0",
"next-auth": "^4.0.1"
},
"jest": {
"preset": "adapter-test/jest"

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -28,7 +28,7 @@
"access": "public"
},
"scripts": {
"build": "tsc",
"build:wip": "tsc",
"test:wip": "FIRESTORE_EMULATOR_HOST=localhost:8080 firebase emulators:exec --only firestore --project next-auth-test jest"
},
"peerDependencies": {
@@ -37,6 +37,7 @@
},
"devDependencies": {
"firebase": "^8.6.2",
"firebase-tools": "^9.11.0"
"firebase-tools": "^9.11.0",
"next-auth": "^4.0.1"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/mikro-orm-adapter",
"version": "1.0.1",
"version": "2.0.1",
"description": "MikroORM adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -37,7 +37,8 @@
},
"devDependencies": {
"@mikro-orm/core": "^5.0.2",
"@mikro-orm/sqlite": "^5.0.2"
"@mikro-orm/sqlite": "^5.0.2",
"next-auth": "^4.0.1"
},
"jest": {
"preset": "adapter-test/jest"

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/mongodb-adapter",
"version": "1.0.1",
"version": "1.0.3",
"description": "mongoDB adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -26,7 +26,8 @@
"next-auth": "^4.0.1"
},
"devDependencies": {
"mongodb": "^4.4.0"
"mongodb": "^4.4.0",
"next-auth": "^4.0.1"
},
"jest": {
"preset": "adapter-test/jest"

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/neo4j-adapter",
"version": "1.0.2",
"version": "1.0.3",
"description": "neo4j adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -38,7 +38,8 @@
},
"devDependencies": {
"@types/uuid": "^8.3.3",
"neo4j-driver": "^4.4.0"
"neo4j-driver": "^4.4.0",
"next-auth": "^4.0.1"
},
"dependencies": {
"uuid": "^8.3.2"

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -32,6 +32,7 @@
},
"devDependencies": {
"@types/pouchdb": "^6.4.0",
"next-auth": "^4.0.1",
"pouchdb": "^7.2.2",
"pouchdb-adapter-memory": "^7.2.2",
"pouchdb-find": "^7.2.2"

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/prisma-adapter",
"version": "1.0.1",
"version": "1.0.3",
"description": "Prisma adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -33,6 +33,7 @@
},
"devDependencies": {
"@prisma/client": "^3.10.0",
"next-auth": "^4.0.1",
"prisma": "^3.10.0"
},
"jest": {

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/sequelize-adapter",
"version": "1.0.1",
"version": "1.0.2",
"description": "Sequelize adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -33,6 +33,7 @@
"sequelize": "^6.6.5"
},
"devDependencies": {
"next-auth": "^4.0.1",
"sequelize": "^6.6.5"
},
"jest": {

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/typeorm-legacy-adapter",
"version": "1.0.1",
"version": "1.0.3",
"description": "TypeORM (legacy) adapter for next-auth.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -37,6 +37,7 @@
"sqlite": "tests/sqlite/test.sh"
},
"devDependencies": {
"next-auth": "^4.0.1",
"mssql": "^7.2.1",
"mysql": "^2.18.1",
"pg": "^8.7.1",

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",

View File

@@ -29,9 +29,12 @@ npm install next-auth @next-auth/upstash-redis-adapter @upstash/redis
```js
import NextAuth from "next-auth"
import { UpstashRedisAdapter } from "@next-auth/upstash-adapter"
import upstashRedisClient from "@upstash/redis"
import { Redis } from "@upstash/redis"
const redis = upstashRedisClient("UPSTASH_REDIS_REST_URL", "UPSTASH_REDIS_REST_TOKEN")
const redis = new Redis({
url:"UPSTASH_REDIS_REST_URL",
token:"UPSTASH_REDIS_REST_TOKEN",
})
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options

View File

@@ -1,6 +1,6 @@
{
"name": "@next-auth/upstash-redis-adapter",
"version": "1.1.0",
"version": "3.0.0",
"description": "Upstash adapter for next-auth. It uses Upstash's connectionless (HTTP based) Redis client.",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/adapters",
@@ -30,12 +30,13 @@
"dist"
],
"peerDependencies": {
"@upstash/redis": "^0.2.1",
"@upstash/redis": "^1.0.1",
"next-auth": "^4.0.1"
},
"devDependencies": {
"@upstash/redis": "^0.2.1",
"dotenv": "^10.0.0"
"@upstash/redis": "^1.0.1",
"dotenv": "^10.0.0",
"next-auth": "^4.0.1"
},
"dependencies": {
"uuid": "^8.3.2"

View File

@@ -1,6 +1,11 @@
import type { Account as AdapterAccount } from "next-auth"
import type { Adapter, AdapterUser, AdapterSession } from "next-auth/adapters"
import type { Upstash } from "@upstash/redis/src/types"
import type {
Adapter,
AdapterUser,
AdapterSession,
VerificationToken,
} from "next-auth/adapters"
import type { Redis } from "@upstash/redis"
import { v4 as uuid } from "uuid"
@@ -32,14 +37,15 @@ function isDate(value: any) {
return value && isoDateRE.test(value) && !isNaN(Date.parse(value))
}
export function reviveFromJson(json: string) {
return JSON.parse(json, (_, value) =>
isDate(value) ? new Date(value) : value
)
export function hydrateDates(json: object) {
return Object.entries(json).reduce((acc, [key, val]) => {
acc[key] = isDate(val) ? new Date(val as string) : val
return acc
}, {} as any)
}
export function UpstashRedisAdapter(
client: Upstash,
client: Redis,
options: UpstashRedisAdapterOptions = {}
): Adapter {
const mergedOptions = {
@@ -70,12 +76,15 @@ export function UpstashRedisAdapter(
}
const getAccount = async (id: string) => {
const response = await client.get(accountKeyPrefix + id)
if (!response.data) return null
return reviveFromJson(response.data)
const account = await client.get<AdapterAccount>(accountKeyPrefix + id)
if (!account) return null
return hydrateDates(account)
}
const setSession = async (id: string, session: AdapterSession) => {
const setSession = async (
id: string,
session: AdapterSession
): Promise<AdapterSession> => {
const sessionKey = sessionKeyPrefix + id
await setObjectAsJson(sessionKey, session)
await client.set(sessionByUserIdKeyPrefix + session.userId, sessionKey)
@@ -83,21 +92,24 @@ export function UpstashRedisAdapter(
}
const getSession = async (id: string) => {
const response = await client.get(sessionKeyPrefix + id)
if (!response.data) return null
return reviveFromJson(response.data)
const session = await client.get<AdapterSession>(sessionKeyPrefix + id)
if (!session) return null
return hydrateDates(session)
}
const setUser = async (id: string, user: AdapterUser) => {
const setUser = async (
id: string,
user: AdapterUser
): Promise<AdapterUser> => {
await setObjectAsJson(userKeyPrefix + id, user)
await client.set(`${emailKeyPrefix}${user.email as string}`, id)
return user
}
const getUser = async (id: string) => {
const response = await client.get(userKeyPrefix + id)
if (!response.data) return null
return reviveFromJson(response.data)
const user = await client.get<AdapterUser>(userKeyPrefix + id)
if (!user) return null
return hydrateDates(user)
}
return {
@@ -110,9 +122,11 @@ export function UpstashRedisAdapter(
},
getUser,
async getUserByEmail(email) {
const emailResponse = await client.get(emailKeyPrefix + email)
if (!emailResponse.data) return null
return await getUser(emailResponse.data)
const userId = await client.get<string>(emailKeyPrefix + email)
if (!userId) {
return null
}
return await getUser(userId)
},
async getUserByAccount(account) {
const dbAccount = await getAccount(
@@ -124,7 +138,7 @@ export function UpstashRedisAdapter(
async updateUser(updates) {
const userId = updates.id as string
const user = await getUser(userId)
return await setUser(userId, { ...user, ...updates })
return await setUser(userId, { ...(user as AdapterUser), ...updates })
},
async linkAccount(account) {
const id = `${account.provider}:${account.providerAccountId}`
@@ -158,10 +172,13 @@ export function UpstashRedisAdapter(
},
async useVerificationToken(verificationToken) {
const tokenKey = verificationTokenKeyPrefix + verificationToken.identifier
const tokenResponse = await client.get(tokenKey)
if (!tokenResponse.data) return null
const token = await client.get<VerificationToken>(tokenKey)
if (!token) return null
await client.del(tokenKey)
return reviveFromJson(tokenResponse.data)
return hydrateDates(token)
// return reviveFromJson(token)
},
async unlinkAccount(account) {
const id = `${account.provider}:${account.providerAccountId}`
@@ -177,17 +194,15 @@ export function UpstashRedisAdapter(
const user = await getUser(userId)
if (!user) return
const accountByUserKey = accountByUserIdPrefix + userId
const accountRequest = await client.get(accountByUserKey)
const accountKey = accountRequest.data
const accountKey = await client.get<string>(accountByUserKey)
const sessionByUserIdKey = sessionByUserIdKeyPrefix + userId
const sessionRequest = await client.get(sessionByUserIdKey)
const sessionKey = sessionRequest.data
const sessionKey = await client.get<string>(sessionByUserIdKey)
await client.del(
userKeyPrefix + userId,
`${emailKeyPrefix}${user.email as string}`,
accountKey,
accountKey as string,
accountByUserKey,
sessionKey,
sessionKey as string,
sessionByUserIdKey
)
},

View File

@@ -1,6 +1,6 @@
import upstashRedisClient from "@upstash/redis"
import { Redis } from "@upstash/redis"
import { runBasicTests } from "adapter-test"
import { reviveFromJson, UpstashRedisAdapter } from "../src"
import { hydrateDates, UpstashRedisAdapter } from "../src"
import "dotenv/config"
if (!process.env.UPSTASH_REDIS_URL || !process.env.UPSTASH_REDIS_KEY) {
@@ -8,35 +8,39 @@ if (!process.env.UPSTASH_REDIS_URL || !process.env.UPSTASH_REDIS_KEY) {
expect(true).toBe(true)
})
} else {
const client = upstashRedisClient(
process.env.UPSTASH_REDIS_URL,
process.env.UPSTASH_REDIS_KEY
)
const client = new Redis({
url: process.env.UPSTASH_REDIS_URL,
token: process.env.UPSTASH_REDIS_KEY,
})
runBasicTests({
adapter: UpstashRedisAdapter(client, { baseKeyPrefix: "testApp:" }),
db: {
async user(id: string) {
const { data } = await client.get(`testApp:user:${id}`)
return reviveFromJson(data)
const data = await client.get<object>(`testApp:user:${id}`)
if (!data) return null
return hydrateDates(data)
},
async account({ provider, providerAccountId }) {
const { data } = await client.get(
const data = await client.get<object>(
`testApp:user:account:${provider}:${providerAccountId}`
)
return reviveFromJson(data)
if (!data) return null
return hydrateDates(data)
},
async session(sessionToken) {
const { data } = await client.get(
const data = await client.get<object>(
`testApp:user:session:${sessionToken}`
)
return reviveFromJson(data)
if (!data) return null
return hydrateDates(data)
},
async verificationToken(where) {
const { data } = await client.get(
const data = await client.get<object>(
`testApp:user:token:${where.identifier}`
)
return reviveFromJson(data)
if (!data) return null
return hydrateDates(data)
},
},
})

View File

@@ -1,5 +1,5 @@
{
"extends": "tsconfig/base.json",
"extends": "tsconfig/adapters.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"

View File

@@ -77,8 +77,7 @@ NextAuth.js can be used with or without a database.
- Designed to be secure by default and encourage best practices for safeguarding user data
- Uses Cross-Site Request Forgery (CSRF) Tokens on POST routes (sign in, sign out)
- Default cookie policy aims for the most restrictive policy appropriate for each cookie
- When JSON Web Tokens are enabled, they are signed by default (JWS) with HS512
- Use JWT encryption (JWE) by setting the option `encryption: true` (defaults to A256GCM)
- When JSON Web Tokens are enabled, they are encrypted by default (JWE) with A256GCM
- Auto-generates symmetric signing and encryption keys for developer convenience
- Features tab/window syncing and session polling to support short lived sessions
- Attempts to implement the latest guidance published by [Open Web Application Security Project](https://owasp.org)

View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "4.2.1",
"version": "4.3.3",
"description": "Authentication for Next.js",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/next-auth.git",

View File

@@ -107,8 +107,8 @@ export async function NextAuthHandler<
if (pages.signIn) {
let signinUrl = `${pages.signIn}${
pages.signIn.includes("?") ? "&" : "?"
}callbackUrl=${options.callbackUrl}`
if (error) signinUrl = `${signinUrl}&error=${error}`
}callbackUrl=${encodeURIComponent(options.callbackUrl)}`
if (error) signinUrl = `${signinUrl}&error=${encodeURIComponent(error)}`
return { redirect: signinUrl, cookies }
}

View File

@@ -5,8 +5,8 @@ export const defaultCallbacks: CallbacksOptions = {
return true
},
redirect({ url, baseUrl }) {
if (url.startsWith(baseUrl)) return url
else if (url.startsWith("/")) return new URL(url, baseUrl).toString()
if (url.startsWith("/")) return `${baseUrl}${url}`
else if (new URL(url).origin === baseUrl) return url
return baseUrl
},
session({ session }) {

View File

@@ -36,6 +36,7 @@ export function oAuth1Client(options: InternalOptions<"oauth">) {
// Promisify getOAuth1AccessToken() for OAuth1
const originalGetOAuth1AccessToken =
oauth1Client.getOAuthAccessToken.bind(oauth1Client)
// eslint-disable-next-line @typescript-eslint/no-misused-promises
oauth1Client.getOAuthAccessToken = async (...args: any[]) => {
return await new Promise((resolve, reject) => {
originalGetOAuth1AccessToken(
@@ -52,6 +53,7 @@ export function oAuth1Client(options: InternalOptions<"oauth">) {
const originalGetOAuthRequestToken =
oauth1Client.getOAuthRequestToken.bind(oauth1Client)
// eslint-disable-next-line @typescript-eslint/no-misused-promises
oauth1Client.getOAuthRequestToken = async (params = {}) => {
return await new Promise((resolve, reject) => {
originalGetOAuthRequestToken(

View File

@@ -123,10 +123,11 @@ export default function SigninPage(props: SignInServerPageParams) {
<input
id={`input-email-for-${provider.id}-provider`}
autoFocus
type="text"
type="email"
name="email"
value={email}
placeholder="email@example.com"
required
/>
<button type="submit">Sign in with {provider.name}</button>
</form>

View File

@@ -43,9 +43,9 @@ body {
background-color: var(--color-background);
margin: 0;
padding: 0;
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans,
sans-serif, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
h1 {

View File

@@ -99,7 +99,7 @@ export function proxyLogger(
}
;(metadata as any).client = true
const url = `${basePath}/_log`
const body = new URLSearchParams({ level, code, ...metadata })
const body = new URLSearchParams({ level, code, ...(metadata as any) })
if (navigator.sendBeacon) {
return navigator.sendBeacon(url, body)
}

View File

@@ -82,9 +82,9 @@ export default function Kakao<P extends Record<string, any> = KakaoProfile>(
profile(profile) {
return {
id: profile.id,
name: profile.kakao_account?.profile.nickname,
name: profile.kakao_account?.profile?.nickname,
email: profile.kakao_account?.email,
image: profile.kakao_account?.profile.profile_image_url,
image: profile.kakao_account?.profile?.profile_image_url,
}
},
options,

View File

@@ -359,6 +359,12 @@ export function SessionProvider(props: SessionProviderProps) {
}
__NEXTAUTH._getSession()
return () => {
__NEXTAUTH._lastSync = 0
__NEXTAUTH._session = undefined
__NEXTAUTH._getSession = () => {}
}
}, [])
React.useEffect(() => {

View File

@@ -2,6 +2,17 @@
"extends": "tsconfig/base.json",
"compilerOptions": {
"emitDeclarationOnly": true,
"strictNullChecks": true,
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"strict": false,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"stripInternal": true,
"skipDefaultLibCheck": true,
"baseUrl": ".",
"outDir": "."
},

View File

@@ -0,0 +1,8 @@
{
"extends": "./base.json",
"compilerOptions": {
"target": "ES2019",
"module": "commonjs",
"strict": true
}
}

View File

@@ -1,20 +1,9 @@
{
"compilerOptions": {
"strictNullChecks": true,
"target": "es2019",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"declaration": true,
"stripInternal": true,
"skipLibCheck": true,
"skipDefaultLibCheck": true
"skipLibCheck": true
}
}

View File

@@ -1,3 +1,4 @@
import { createHash } from "crypto"
import type { Commit, PackageToRelease } from "./types"
import { debug, pkgJson, execSync } from "./utils"
@@ -17,13 +18,16 @@ export async function publish(options: {
`Dry run, npm publish for package ${pkg.name} will show the wrong version (${pkg.oldVersion}). In normal run, it would be ${pkg.newVersion}`
)
} else {
console.log(`Writing version to package.json for package ${pkg.name}`)
console.log(
`Writing version ${pkg.newVersion} to package.json for package ${pkg.name}`
)
await pkgJson.update(pkg.path, { version: pkg.newVersion })
console.log("package.json file has been written, publishing...")
}
let npmPublish = `npm publish --access public --registry=https://registry.npmjs.org`
// We use different tokens for `next-auth` and `@next-auth/*` packages
if (pkg.name === "next-auth") {
process.env.NPM_TOKEN = process.env.NPM_TOKEN_PKG
} else {
@@ -34,12 +38,13 @@ export async function publish(options: {
console.log(`Dry run, skip npm publish for package ${pkg.name}...`)
npmPublish += " --dry-run"
} else {
const npmrc =
'echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc'
execSync(npmrc, { cwd: pkg.path })
execSync(
"echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc",
{ cwd: pkg.path }
)
}
execSync(npmPublish, { cwd: pkg.path })
execSync(`${npmPublish} --no-workspaces`, { cwd: pkg.path })
}
if (dryRun) {
@@ -63,6 +68,7 @@ export async function publish(options: {
} else {
console.log(`Creating git tag...`)
execSync(`git tag ${gitTag}`)
execSync("git push --tags")
console.log(`Creating GitHub release notes...`)
execSync(`gh release create ${gitTag} --notes '${changelog}'`)
}

3938
yarn.lock

File diff suppressed because it is too large Load Diff