Compare commits

..

176 Commits

Author SHA1 Message Date
Thang Vu
39ecfbd255 chore(release): bump version [skip ci] 2023-10-18 21:07:53 +07:00
Thang Vu
a39d35b341 feat: tweak default sign-in page (#8888) 2023-10-18 20:52:54 +07:00
Balázs Orbán
1cee92563f docs: Update sidebars.js 2023-10-16 15:04:51 +01:00
Balázs Orbán
e3845270c6 docs: add sponsor 2023-10-10 15:59:08 +02:00
Thang Vu
2510f74809 chore(release): bump version [skip ci] 2023-10-02 18:57:37 +07:00
Thang Vu
27b2519b84 fix(next): returns correct status for signing in with redirect: false for route handler (#8775)
* fix: returns status for signing in with credentials provider `redirect: false`

* chore: format cookie.ts
2023-10-02 18:48:36 +07:00
Ahmed Abdelbaset
5f15b0704a docs: fix typo (#8767)
fix typo
2023-10-02 01:03:25 +01:00
Balázs Orbán
e4573ffff5 docs: typo 2023-10-02 01:37:14 +02:00
Balázs Orbán
4ce1951a2b docs: close admonition 2023-10-02 01:34:55 +02:00
Balázs Orbán
c95531d651 docs: mention auth() convention under getServerSession 2023-10-02 01:32:35 +02:00
Balázs Orbán
654d52bb56 docs: mention getServerSession under SessionProvider 2023-10-02 01:27:35 +02:00
Herbie Vine
b72d7be9be docs: set decode fn not jwt obj (#8742)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-09-29 15:36:32 +02:00
Balázs Orbán
76fcc4e70c chore: don't sync example from v4 branch 2023-09-27 12:49:25 +02:00
Balázs Orbán
4cacf504dd docs: clarify pages in middleware 2023-09-26 13:23:04 +02:00
Balázs Orbán
50eb23f626 fix: update security policy link 2023-09-25 11:30:27 +02:00
Balázs Orbán
d813c00b3e fix(ts): fix typo 2023-09-20 19:48:30 +01:00
Soheil Nazari
fc4448a85a docs: add extra tips for next app router (#8227)
* Update example.md

* Update example.md

* Update example.md

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

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

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

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-20 13:46:47 +07:00
Thang Vu
16f781c091 chore: update email 2023-09-16 12:07:27 +07:00
Jared Wyce
ebfdaece0e fix: remove trailing ? from signIn URL (#8466)
* fix: 🎣 avoid phishing categorization by VPNs

* Update packages/next-auth/src/react/index.tsx

* Update packages/next-auth/src/react/index.tsx

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-06 12:55:03 +07:00
Devdat Kumar
64a190e549 docs: Update adapters.md (#8397)
"Drizzle" and "Kysely" links have been added to the list, and the list has been sorted.

https://next-auth.js.org/adapters
2023-08-24 10:23:41 +01:00
Arif Shanji
e11f898c10 docs: typo (#8366) 2023-08-21 13:53:35 +02:00
Balázs Orbán
dcb11da2e2 docs: update error page
closes #8174
2023-08-18 09:22:25 +01:00
Thang Vu
9f900befe6 chore(release): bump version [skip ci] 2023-08-16 14:43:26 +07:00
Gabriel Villenave
09c2a89df8 fix: use default submodules export in package.json (#8330)
Use `default` submodules export in `package.json` to ensure compatibility, as specified in https://nodejs.org/api/packages.html#conditional-exports
2023-08-16 09:33:07 +02:00
Balázs Orbán
20c3fe3331 fix(ts): correctly expose next-auth/adapters
Fixes https://github.com/nextauthjs/next-auth/issues/8283#issuecomment-1675939280
2023-08-12 16:37:18 +02:00
Manuel Cattelan
e26f500d18 docs(providers): add warning for gitlab provider (#8292) 2023-08-11 13:56:56 +02:00
Balázs Orbán
494d16e54d chore(release): bump version [skip ci] 2023-08-11 13:43:03 +02:00
Balázs Orbán
5a8aa2e5e5 feat(providers): add Passage by 1Password 2023-08-11 13:39:52 +02:00
Balázs Orbán
05ff6ae221 fix(ts): correctly export submodule types 2023-08-11 11:31:35 +02:00
Jonathan Edenström
1fbc684f53 fix: sort cookie chunks correctly (#8284) 2023-08-10 12:17:41 +01:00
Balázs Orbán
124be4fb1f chore(release): bump version [skip ci] 2023-08-08 19:21:49 +02:00
Balázs Orbán
3b0128c3ca fix(ts): match next-auth/adapter & @auth/core/adapters 2023-08-08 19:20:30 +02:00
Balázs Orbán
36b97aafb8 docs: amplify note 2023-08-08 18:00:41 +02:00
Thang Vu
175d37499b chore(release): bump version [skip ci] 2023-08-06 22:52:13 +07:00
Thang Vu
08a6835a70 fix: don't return res.end() in api handler (#8244)
Move #8069 to v4 branch
co-authored by @maritz

Co-authored-by: maritz <159633+maritz@users.noreply.github.com>
2023-08-06 22:38:57 +07:00
Thang Vu
448a11ff0a chore: add turbo env vars 2023-08-06 21:47:08 +07:00
Thang Vu
f39f9708bd fix(ts) : add missing function overload for Route Handler (#8236)
Pick up https://github.com/nextauthjs/next-auth/pull/8211 & tweak some changes

Co-authored-by: Max Quinn <max.t.quinn@gmail.com>
2023-08-05 19:57:29 +07:00
Matt Azlin
6d98b8b33c docs: fixing broken link in documentation (#8208) 2023-08-03 16:11:11 +02:00
Balázs Orbán
ef7ec044c5 docs: clarify getServerSession 2023-08-03 16:05:32 +02:00
Balázs Orbán
e89e3143d7 docs: move unstable_getServerSession 2023-08-03 16:03:48 +02:00
Noam Al Rifaï
12f0795a0a docs: Typo fixed (#8206) 2023-08-03 16:01:58 +02:00
Trent
9e0036bc73 docs(providers): mention HTTP-based Email guide (#8214)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-08-03 15:57:57 +02:00
MohammadAli Saeidi
27aa5ef09b docs: Update object key "email" to "username" (#8113) 2023-07-25 14:45:38 +02:00
Thang Vu
903bd6fac9 fix: remove RSC warning in getServerSession (#8108) 2023-07-25 12:13:51 +02:00
Ricardo van Noort
998b7a0db4 docs: Update upgrade-to-v4.md (#8123) 2023-07-25 12:12:57 +02:00
Thang Vu
465644f9e4 fix(ts): SignInResponse.error type (#8109)
Co-authored-by: smcg468 <49883535+smcg468@users.noreply.github.com>
2023-07-22 12:39:23 +07:00
GhibliMagic
d12bd5a799 doc: Add a guide on sending magic links to existing users only (#7663) 2023-07-22 11:57:52 +07:00
Tony Worm
3897d47db2 docs: Update refresh-token-rotation.md - fix example client code filename (#8088) 2023-07-20 01:09:06 +02:00
Doug
e44dccc42d docs(providers): updated docs with missing account attribute (#8084) 2023-07-19 15:24:41 +02:00
Balázs Orbán
733a81bd3a chore(release): bump version [skip ci] 2023-07-18 22:53:27 +02:00
Balázs Orbán
f06f3bbc96 chore(release): bump version [skip ci] 2023-07-18 15:53:30 +02:00
Thang Vu
aea27a1fa8 fix: remove unused TS types 2023-07-16 22:32:55 +07:00
Thang Vu
bd37c55241 fix(ts): adapter interface (#8054) 2023-07-16 20:47:18 +07:00
Rexford Essilfie
169a5230db fix(ts): add overloads to withAuth middleware (#7999)
* fix(ts): add overloads to withAuth middleware

* fix: allow extends Request on returned middleware handler

* chore: simplify return type for withAuth returning middleware

* chore: remove withAuth overloads generics

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-07-12 10:49:50 +07:00
Francis Gulotta
f48eb0478e fix(providers): fix nodemailer/required types (#7950)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-07-11 12:57:37 +02:00
Stephen Cronin
b25a090c17 docs: fix getServerSession API Routes example (#7978)
* Fix Next.js getServerSession API Routes example

Example API code threw an error in Next.js. Fixed the example to work.

* Update docs/docs/configuration/nextjs.md

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-07-09 14:03:02 +02:00
Matt Jared
0167e9368b docs: Update example.md (#7879) 2023-06-27 14:29:17 +02:00
Mikalai S
dcb576f01b docs: Mention a possible cause of ResourceNotFound issue (#7758) 2023-06-09 14:56:55 +02:00
Balázs Orbán
9417822a41 Update oauth.ts
Closes #7608

Co-authored-by: aaazzz <akrm@hey.com>
2023-06-01 11:17:23 +01:00
Balázs Orbán
14f8f0cb58 docs: rephrase
Closes #7531

Co-authored-by: Trey Speakman
 <100887275+treyspeakman@users.noreply.github.com>
2023-05-19 00:58:27 +01:00
Nick Radford
212272a839 docs: Update sub-bullet about vercel deployment specifics (#7537) 2023-05-14 12:59:49 +02:00
Balázs Orbán
a8e8b7542c docs: Update initialization.md 2023-05-11 23:30:53 +01:00
browny
14cecb9b73 docs: update react docs link (#7521) 2023-05-11 14:45:39 +02:00
Ivan Medina
28bec0fbcc docs: Update client.md (#7458) 2023-05-06 12:09:10 +01:00
Thang Vu
bc683a5b72 chore: merge changes back to v4 (#7430)
* docs: Remove --save from install command (#7277)

Remove --save from install command

--save is no longer needed on npm install.

* chore: fix "Contributing guide" link (#7279)

* fix: detect origin when `instanceof Request` check fails (#7303)

* docs: Update Clerk sponsorship URL (#7305)

- Change Clerk URL from `https://clerk.dev` to `https://clerk.com`

- Fix alt from copy/paste

* chore: bump react types

* fix(docs): fix default `maxAge` formula (#7406)

* Update pnpm-lock.yaml

* sync package.json change

---------

Co-authored-by: Chris Hayes <6013871+Christopher-Hayes@users.noreply.github.com>
Co-authored-by: Raul <57044803+Leprekus@users.noreply.github.com>
Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nick Parsons <nparsons08@gmail.com>
Co-authored-by: Victor <saptefrativictor@gmail.com>
2023-05-04 20:05:33 +01:00
Sebastián Iturra
e7b8597f73 docs: Update email.md (#7391) 2023-04-28 13:53:27 +01:00
Kjetil Hårtveit
5c89a21bfa docs: mention caching in App Router (#7206)
I spent at least a day figuring out why my tRPC caches were all [MISSing](https://vercel.com/docs/concepts/edge-network/caching#miss) even though I set the correct Cache-Control headers (my stack: NextAuth, NextJS, tRPC, Vercel). I wish information could be placed where appropriate so that others don't need to debug like I had too.

I realise it's a bit convoluted as tRPC suggested I could fetch the session in the context and then use it throughout my routers. It was not obvious to me that this caused all the public caches to fail, even on query procedures that were not using the session. The caches were MISSing because `getServerSession` refreshes the cookies via the `set-cookie` header and [Vercel won't allow this](https://vercel.com/docs/concepts/functions/serverless-functions/edge-caching). I'm not saying the refreshing of cookies is wrong, it's a nice feature, and it's kind of handy this implicitly means Vercel doesn't cache. 

So how I got here has many causes and it's futile to find anyone to "blame". The factors are:
- tRPC suggests `getSession()` in their [documentation for context](https://trpc.io/docs/server/context). 
- I see tRPC does not suggest `getSession()` in the page for [caching](https://trpc.io/docs/server/caching) which is correct but wasn't obvious to me what I had done wrong.
- my misunderstanding about the link between session and personalized data (it makes sense to me now but it wasn't that obvious to see the link: get session means no public cache)
2023-04-26 13:05:01 +01:00
Andreas Jagiella
6e9c8b5b3c docs(providers): mention non-standard properties (#7290)
~ needed database entries
~ type of redirect uri
2023-04-26 13:03:08 +01:00
Ilya
91a9e5f601 docs(providers): update default vk provider version and options link (#7354)
Update version by default and options link

Now by default VK provider uses `5.131` version.
And provider options link changed to .ts.
2023-04-26 12:58:09 +01:00
Balázs Orbán
cb916f4848 docs: Update typescript.md
closes #7288
2023-04-17 21:01:11 +01:00
muoi
8259cd4fc6 docs : fix typo (#7258)
Update link to Kakao Provider options
2023-04-17 10:35:15 +01:00
Dorijan Hašpl
7a8c0068c4 docs: mention Route Handler initialization in getting started (#7213)
Updated the Getting Started documentation file (section about adding NextAuth API routes) to refer to another documentation section where the NextAuth API routes are handled using the new App Router and Route Handlers
2023-04-12 11:39:09 +01:00
Balázs Orbán
6edb6ddaaf fix: respect protocol too, when host is trusted (#7214)
* fix: respect protocol too when host is trusted

* simplify
2023-04-12 11:30:20 +01:00
Balázs Orbán
0711d32a00 chore(release): bump version [skip ci] 2023-04-09 11:54:51 +02:00
Balázs Orbán
c261af4695 feat: support Route Handlers (#6777)
* feat: support Route Handlers

* update dev app

* init NextAuth via Route Handler in dev app

* import as type

* fix labeler

* default secret to `NEXTAUTH_SECRET`

* handle redirects

* support advanced init in Route Handlers

* use port 3000 for docs dev

* document initialization with Route Handlers

* upgrade to latest `next`

* upgrade to 13.3.0

* remove workaround

* cleanup
2023-04-09 10:51:49 +01:00
Balázs Orbán
d69f311ddc chore(release): bump version [skip ci] 2023-04-03 12:15:24 +02:00
Julius Marminge
ec8a34308b fix(ts): revert session callback type changes (#7136)
Fixes https://github.com/t3-oss/create-t3-app/issues/1328
2023-04-03 12:14:24 +02:00
Balázs Orbán
c0bf2f15fb chore(release): bump version [skip ci] 2023-04-02 11:30:53 +02:00
Thang Vu
d8901777bf fix: revert #6814 (#7125) 2023-04-02 11:27:52 +02:00
Balázs Orbán
319f2ce165 fix(ts): mark id in updateUser as always defined
Closes #7027
2023-03-29 14:16:58 +02:00
Balázs Orbán
2d907f0004 feat: make it possible to update the session (#7056) 2023-03-29 05:43:48 +02:00
JakobSchlichting
2954588be7 docs: fix typo (#7094) 2023-03-29 05:39:57 +02:00
Balázs Orbán
4026183411 docs: fix adapters links 2023-03-27 01:48:23 +02:00
Abdulaziz Askaraliev
86d031faba fix(providers): add types for yandex provider (#7073)
* fix(providers): yandex add types

* chore(providers): yandex added comments

* Update yandex.ts

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-03-27 00:39:54 +01:00
Thomas Knickman
1e3745d22a chore(docs): update broken links (#7069)
fix(docs): update broken links
2023-03-26 21:51:05 +02:00
Balázs Orbán
feaeda9e2a chore: release with declaration maps 2023-03-25 16:18:38 +01:00
Balázs Orbán
e127600ad4 chore: fix tests 2023-03-25 15:37:17 +01:00
Balázs Orbán
cb3137133c docs: fix title 2023-03-25 13:46:35 +01:00
Balázs Orbán
b3eaf6329e docs: fix broken links 2023-03-25 13:22:56 +01:00
Peter
8aa1789697 fix(oauth): allow jwks_uri to be set for non-wellKnown (#7014)
fix(oauth): allow jwks_uri to be set for non-wellKnown flow by passing jwks_endpoint

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-03-25 18:57:22 +07:00
Balázs Orbán
a7601d0b45 chore: redirect rest of the adapters 2023-03-24 01:57:41 +01:00
Balázs Orbán
bb8d826bc7 Update sidebars.js 2023-03-20 20:43:03 +00:00
Balázs Orbán
f787809cd4 Update overview.md 2023-03-20 20:36:47 +00:00
Balázs Orbán
7789fa17b5 Delete pouchdb.md 2023-03-20 20:36:34 +00:00
Balázs Orbán
740c505901 Update vercel.json 2023-03-20 20:36:06 +00:00
Balázs Orbán
1e579cbaa6 Merge branch 'v4' of github.com:nextauthjs/next-auth into v4 2023-03-16 03:21:37 +01:00
Balázs Orbán
65aacbe97a docs: fix links 2023-03-16 03:21:33 +01:00
Balázs Orbán
7dbfa5da4d docs: fix sidebar, remove duplicates 2023-03-16 03:13:36 +01:00
Balázs Orbán
98bd774b75 Update vercel.json 2023-03-16 01:51:34 +00:00
Norbert Hüthmayr
3661ca68b0 doca: Prevent Stalled Request Warning (#6967)
Added call to end()

Missing end causes `stalled request` warning
2023-03-16 01:30:12 +01:00
Balázs Orbán
7ba986b01e Update vercel.json 2023-03-09 11:34:27 +00:00
Balázs Orbán
e638ec5eb1 chore: redirect to new reference page 2023-03-09 11:25:25 +00:00
Abheek Dhawan
7327468697 docs: remove incorrect space in MikroORM (#6886) 2023-03-08 16:56:26 +00:00
Balázs Orbán
9a9c24897d docs: redirect prisma 2023-03-05 17:20:30 +01:00
Balázs Orbán
e362653819 chore: format 2023-03-05 16:08:35 +01:00
Balázs Orbán
a92e348ed3 chore: remove duplicate articles 2023-03-05 15:56:43 +01:00
Balázs Orbán
ab0857a99e chore: correct ts import 2023-03-02 20:32:28 +01:00
Balázs Orbán
50b117dfbb chore(release): bump version [skip ci] 2023-03-02 20:08:55 +01:00
Balázs Orbán
e6590ffc20 fix: unify checks 2023-03-02 20:08:28 +01:00
Balázs Orbán
26c846594f chore(release): bump version [skip ci] 2023-03-02 01:53:44 +01:00
Balázs Orbán
2432ce9001 fix: throw error on missing state 2023-03-02 01:50:05 +01:00
Anthony Jocks
0a689b4f4e docs: typo in faq.md (#6826) 2023-02-28 12:53:44 +01:00
Thang Vu
2fb34bab51 feat: priortize NEXTAUTH_URL_INTERNAL (#6814) 2023-02-25 18:51:16 +00:00
Olabode Lawal-Shittabey
d0e7689d07 docs: fix typo on 'nextjs#getserversession' page (#6790) 2023-02-23 14:56:58 +01:00
Balázs Orbán
c004659174 docs: add IDS6 documentation 2023-02-22 02:00:56 +00:00
Tom
c212e96f83 docs(providers): fix broken sudo pipe in hostname example (#6769)
`sudo echo > /etc/hosts` attempts to write to /etc/hosts as a non-priv user, which will fail. `echo | sudo tee /etc/hosts` works.
2023-02-22 01:49:05 +00:00
Balázs Orbán
d41f2a4a02 docs: fix typo 2023-02-21 18:28:05 +01:00
Raúl Marín
5ecf20a804 fix: Add missing logo to Default Signin Page (#6728)
fix(packages\next-auth\src\core\pages\signin.tsx): add missing logo
2023-02-17 10:23:10 +07:00
Steve Fuller
9e423f3252 docs: Update custom sign in getProvider example (#6706)
According to the function declaration for [getProviders()](https://github.com/nextauthjs/next-auth/blob/v4/packages/next-auth/src/react/index.tsx#L187) it doesn't accept any parameters. Therefore have removed passing of an argument in the doc example.

Using the documentation as is will result in multiple type errors as [referenced in an issue I've posted about](https://github.com/nextauthjs/next-auth/issues/6704)
2023-02-13 12:56:10 +00:00
Jiří Hofman
cf810f246a docs: fix wording for deployment on Vercel preview (#6705) 2023-02-13 12:50:14 +00:00
Balázs Orbán
05fe398b1a docs: redirect to new refresh token article 2023-02-10 11:59:18 +01:00
Balázs Orbán
8659c02366 docs: stop encouraging adding providers to legacy 2023-02-10 02:01:10 +01:00
Balázs Orbán
2e039643b6 docs: fix path
closes #6663
2023-02-10 01:59:41 +01:00
Balázs Orbán
3943f9b7b2 fix(next-auth): remove engines requirement on openid-client (#6654) 2023-02-09 01:52:50 +01:00
Balázs Orbán
f2e85c2113 chore: redirect to more up-to-date docs 2023-02-05 15:13:14 +01:00
Robin
c53c868288 docs: update pages configuration example to typescript (#6596)
* Update examples to TS

* docs: update files names to corresponding TSX

having jsx syntax, file needs to be jsx/tsx.

* Apply suggestions from code review

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-02-03 13:59:36 +00:00
Balázs Orbán
0bc4fcb51a docs: clarify token and user in session callback
closes #6602
2023-02-03 13:52:12 +00:00
Ojoechem Chinonso
139c2edb50 docs: redirect from custom sign in page if signed in (#6589)
* Add success handler to getServerSideProps

This change adds a code that gives the user a sense of direction on what to do if the OAuth sign in is successful.

* Update docs/docs/configuration/pages.md

This is noted

Co-authored-by: Balázs Orbán <info@balazsorban.com>

* Update getSession to getServerSession

Change the getSession in getServerSideProps to the new getServerSession

* Apply suggestions from code review

* Apply suggestions from code review

* Apply suggestions from code review

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-02-03 12:59:22 +00:00
Balázs Orbán
4e94d89554 chore(release): bump version 2023-02-02 02:16:28 +01:00
Balázs Orbán
43d66fcb23 fix(ts): stop using typeof + generic together (#6595) 2023-02-02 02:15:43 +01:00
Thang Vu
bfcf1a3604 chore(release): bump version [skip ci] 2023-01-31 19:25:50 +07:00
Thang Vu
5b1555ed97 feat: redesign all default pages
sync from core via #5825

Co-Authored-By: Rein Undheim <46612252+Gawdfrey@users.noreply.github.com>
2023-01-31 17:40:46 +07:00
Vu Van Dung
0ed07b31b6 fix(ts): correctly type unstable_getServerSession (#6560)
* fix: type of unstable_getServerSession

Signed-off-by: Vu Van Dung <me@joulev.dev>

* Apply suggestions from code review

---------

Signed-off-by: Vu Van Dung <me@joulev.dev>
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-01-30 12:10:26 +00:00
OrJDev
2311be7589 docs: Remove the unstable note. (#6537) 2023-01-28 15:15:09 +01:00
Balázs Orbán
e847b3466f chore(release): bump version [skip ci] 2023-01-28 13:24:50 +01:00
Balázs Orbán
8df6d5b469 feat: make generateSessionToken awaitable (#6536)
Co-authored-by: @HommeSauvage
2023-01-28 12:19:32 +00:00
Balázs Orbán
0bcaeca369 feat: remove unstable_ prefix getServerSession (#6535)
* feat: remove `unstable_` prefix from `getServerSession`

* fix test

* fix lint
2023-01-28 12:12:00 +00:00
Balázs Orbán
4f5ddbcb76 fix(oauth1): pass oauth_token_secret (#6534)
* Pass oauth_token_secret in OAuth 1.0 calls

* simplify

* simplify

---------

Co-authored-by: dawidos234 <dawidos234@gmail.com>
2023-01-28 09:44:23 +00:00
Balázs Orbán
0cbeb4055e chore(release): bump version 2023-01-24 14:03:59 +01:00
Balázs Orbán
5a128db369 fix(providers): add slash to default logo urls
fixes #6495
2023-01-24 14:03:40 +01:00
Balázs Orbán
c385cf8c7c chore(release): bump version [skip ci] 2023-01-24 02:47:03 +01:00
Balázs Orbán
53fa46744c chore: match core 2023-01-24 02:40:29 +01:00
StachowiakDawid
451eaaabd2 fix: Allow adding own logo to provider (#6465) 2023-01-24 02:35:30 +01:00
Balázs Orbán
f54424c216 fix(next-auth): remove engines 2023-01-24 02:24:45 +01:00
Balázs Orbán
09bcc1d504 fix(providers): default image to null for Azure AD
Fixes #6482
2023-01-24 02:24:35 +01:00
Chiemerie Arum
6ecf9cb93d docs(client): Improve grammar (#6444)
Improve grammar
2023-01-20 11:14:40 +00:00
Judicael
ba2711d279 docs: Remove Demo Identity server 4 (#6354)
Since the demo is not working anymore (removed), we should remove the demo identity server from the docs
2023-01-10 12:05:59 +00:00
Balázs Orbán
03881bf98f chore: fix sync GH Action pat 2023-01-07 08:29:07 +01:00
Balázs Orbán
230164f751 chore: bump version [skip release] 2023-01-07 08:22:24 +01:00
Balázs Orbán
fecf5e0a1c chore: bump monorepo release script 2023-01-07 08:21:32 +01:00
Balázs Orbán
400d0f1842 fix: move logos 2023-01-07 08:18:35 +01:00
Luis Cadillo
39657bf06c docs: remove outdated nested middleware info (#5181)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2022-12-31 09:36:53 +00:00
Nicholas
d1dd8d95c4 chore(docs): fix middleware verbiage (#5981)
* Make documentation easier to understand

* Apply suggestions from code review

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

Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2022-12-31 08:33:36 +00:00
Jesús Ferretti
554ec439c9 fix(docs): import NextAuth correctly (#6206)
fix(docs): fix typo
2022-12-27 23:50:33 +01:00
Iswar Mondal
8e4db3899a docs: Replaced the word peer dependency (#6197) 2022-12-27 14:27:31 +01:00
Rob Hyrkiel
444b99ee96 docs: fix broken links related to issue #6157 (#6183) 2022-12-26 11:45:10 +01:00
Nico Domino
f12b527300 chore(docs): fix aloglia docusaurus.config.js settings (v4) (#6160)
chore(docs): fix docusaurus algolia config
2022-12-23 12:39:47 +01:00
Balázs Orbán
ac48211967 chore: fix edit link
Mentioned in #6142
2022-12-22 15:48:39 +00:00
Balázs Orbán
2bd60f6626 chore(release): bump version 2022-12-22 00:56:48 +01:00
Balázs Orbán
a83573ed2f fix(next-auth): revert to 4.17 to fix host issues but keep other fixes (#6132)
* fix(next-auth): revert to 4.17 and replay other fixes

* revert line change

* replay some TS changes to reduce diff

* fix tests

* revert more renames

* revert renames

* fix test, cleanup
2022-12-21 23:48:38 +00:00
Mark Scerri
6242aa7ecb fix: incorrect signin redirect url on session required (#5976)
Fixes https://github.com/nextauthjs/next-auth/issues/5296
2022-12-19 14:26:02 +01:00
Balázs Orbán
54cbbadc8f chore: run release on v4 branch 2022-12-19 13:24:26 +00:00
Balázs Orbán
fd4af6512e chore: remove new stuff from v4 branch 2022-12-17 20:42:10 +01:00
ndom91
6482e359b7 fix: update aloglia index name for next-auth-v4 2022-12-15 21:51:32 +01:00
Balázs Orbán
64aac2efc0 docs: fix links 2022-12-13 23:42:47 +01:00
Balázs Orbán
df37a24c23 docs: remove unreleased 2022-12-13 23:33:00 +01:00
ndom91
8bcdf8e818 chore: empty2 2022-12-13 23:15:07 +01:00
ndom91
dd765a1b45 chore: empty 2022-12-13 23:13:36 +01:00
Balázs Orbán
e7af366a3b chore(release): bump package version(s) [skip ci] 2022-12-13 22:04:43 +01:00
Balázs Orbán
3bdf7f56f0 fix(core): update README 2022-12-13 21:57:30 +01:00
Balázs Orbán
b00a694a4f fix(frameworks): update @auth/sveltekit README 2022-12-13 21:56:53 +01:00
Balázs Orbán
6ffecfb87d chore(release): bump package version(s) [skip ci] 2022-12-13 21:53:56 +01:00
Balázs Orbán
22c29361e5 feat(frameworks): Introduce SvelteKit Auth 2022-12-13 21:48:15 +01:00
Balázs Orbán
b157554a5f chore: move 2022-12-13 21:33:27 +01:00
Balázs Orbán
08fed7eddd chore: empty commit 2022-12-13 21:21:22 +01:00
Thang Vu
b5e1b19771 feat(frameworks): Introduce SvelteKit Auth (#6041)
* WIP use `Request` and `Response` for core

* bump Next.js

* rename ts types

* refactor

* simplify

* upgrade Next.js

* implement body reader

* use `Request`/`Response` in `next-auth/next`

* make linter happy

* revert

* fix tests

* remove workaround for middleware return type

* return session in protected api route example

* don't export internal handler

* fall back host to localhost

* refactor `getBody`

* refactor `next-auth/next`

* chore: add `@edge-runtime/jest-environment`

* fix tests, using Node 18 as runtime

* fix test

* remove patch

* upgrade/add dependencies

* type and default import on one line

* don't import all adapters by default in dev

* simplify internal endpoint config

Instead of passing url and params around as a string and an object,
we parse them into a `URL` instance.

* assert if both endpoint and issuer config is missing

* allow internal redirect to be `URL`

* mark clientId as always internally, fix comments

* add web-compatible authorization URL handling

* fix type

* fix neo4j build

* remove new-line

* reduce file changes in the PR

* simplify types

* refactor `crypto` usage

In Node.js, inject `globalThis.crypto` instead of import

* add `next-auth/web`

* refactor

* send header instead of body to indicate redirect response

* fix eslint

* fix tests

* chore: upgrade dep

* fix import

* refactor: more renames

* wip core

* support OIDC

* remove `openid-client`

* temprarily remove duplicate logos

* revert

* move redirect logic to core

* feat: add sveltekit auth

* wip fix css

* revert Logo component

* output ESM

* fix logout

* deprecate OAuth 1,  simplify internals, improve defaults

* refactor providers, test facebook

* fix providers

* target es2020

* fix CSS

* fix AuthHandler, add getServerSession

* update lock file

* make logos optional

* sync with `next-auth`

* clean up `next-auth/edge`

* sync

* Sync (#2)

* fix(core): properly construct url (#5984)

* chore(release): bump package version(s) [skip ci]

* fix(core): add protocol if missing

* fix(core): throw error if no action can be determined

* test(core): fix test

* chore(release): bump package version(s) [skip ci]

* chore(docs): add new tutorial (#5604)

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

* fix(core): handle `Request` -> `Response` regressions  (#5991)

* fix(next): don't override `Content-Type` by `unstable_getServerSession`

* fix(core): handle `,` while setting `set-cookie`

* chore(release): bump package version(s) [skip ci]

* fix(sequelize): increase sequelize `id_token` column length (#5929)

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

* fix(core): correct status code when returning redirects (#6004)

* fix(core): correctly set status when returning redirect

* update tests

* forward other headers

* update test

* remove default 200 status

* fix(core): host detection/NEXTAUTH_URL (#6007)

* rename `host` to `origin` internally

* rename `userOptions` to `authOptions` internally

* use object for `headers` internally

* default `method` to GET

* simplify `unstable_getServerSession`

* allow optional headers

* revert middleware

* wip getURL

* revert host detection

* use old `detectHost`

* fix/add some tests wip

* move more to core, refactor getURL

* better type auth actions

* fix custom path support (w/ api/auth)

* add `getURL` tests

* fix email tests

* fix assert tests

* custom base without api/auth, with trailing slash

* remove parseUrl from assert.ts

* return 400 when wrong url

* fix tests

* refactor

* fix protocol in dev

* fix tests

* fix custom url handling

* add todo comments

* chore(release): bump package version(s) [skip ci]

* update lock file

* fix(next): correctly bundle next-auth/middleware
fixes #6025

* fix(core): preserve incoming set cookies (#6029)

* fix(core): preserve `set-cookie` by the user

* add test

* improve req/res mocking

* refactor

* fix comment typo

* chore(release): bump package version(s) [skip ci]

* make logos optional

* sync with `next-auth`

* clean up `next-auth/edge`

* sync

Co-authored-by: Balázs Orbán <balazsorban44@users.noreply.github.com>
Co-authored-by: Thomas Desmond <24610108+thomas-desmond@users.noreply.github.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Cyril Perraud <perraud.cyril@gmail.com>

* merge

* clean up sveltekit auth handler

* upgrade playground to latest

* upgrade sveltekit auth to latest

* Some more refactoring

* feat: extract type to core and reuse in sveltekit

* remove uuid

* make secret required in dev

* remove todo comments

* pass through OAuth client options

* generate declaration map

* default env secret to AUTH_SECRET

* temporary Headers fix

* move pages to lib

* move errors to lib

* move pages/index to lib

* move routes to lib

* move init to lib

* move styles to lib

* move types to lib

* move utils to lib

* fix imports

* update ignore/clean patterns

* fix imports

* update styles ts

* update gitignore

* update exports field

* revert `next-auth`

* remove extra tsconfig files

* remove `private` from package.json

* revert

* feat sveltekit

* commit

* remove unused file, expose type

* remove nextauth_url, memoize locals.getSession

* move to dependency

* fix

* format

* fix post build

* simplify

* fix lock file

* add packages/frameworks

* update package.json

* update gitignore

* Delete .gitignore

* Update types.ts

* Update tsconfig.dev.json

* skip test

* format

* skip format/lint

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Balázs Orbán <balazsorban44@users.noreply.github.com>
Co-authored-by: Thomas Desmond <24610108+thomas-desmond@users.noreply.github.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: Cyril Perraud <perraud.cyril@gmail.com>
2022-12-13 20:10:53 +00:00
464 changed files with 4623 additions and 27650 deletions

View File

@@ -18,6 +18,7 @@ module.exports = {
parserOptions: {
project: [
path.resolve(__dirname, "./packages/**/tsconfig.eslint.json"),
path.resolve(__dirname, "./packages/frameworks/**/tsconfig.json"),
path.resolve(__dirname, "./apps/**/tsconfig.json"),
],
},

View File

@@ -54,7 +54,7 @@ upstash-redis:
xata:
- packages/adapter-xata/**
core:
legacy:
- packages/next-auth/src/**/*
style:

13
.github/sync.yml vendored
View File

@@ -1,13 +0,0 @@
nextauthjs/next-auth-example:
- source: apps/example-nextjs
dest: .
deleteOrphaned: true
- .github/FUNDING.yml
- LICENSE
nextauthjs/next-auth-gatsby-example:
- source: apps/example-gatsby
dest: .
deleteOrphaned: true
- .github/FUNDING.yml
- LICENSE

View File

@@ -7,6 +7,7 @@ on:
- "beta"
- "next"
- "3.x"
- "v4"
pull_request:
jobs:
@@ -31,11 +32,16 @@ jobs:
run: pnpm install
- name: Build
run: pnpm build
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
- name: Run tests
run: pnpm test
env:
UPSTASH_REDIS_URL: ${{ secrets.UPSTASH_REDIS_URL }}
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
# - name: Coverage
# uses: codecov/codecov-action@v1
# with:

View File

@@ -1,18 +0,0 @@
name: Sync Example Repositories
on:
push:
branches:
- main
workflow_dispatch:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Run GitHub File Sync
# Can update to v1 when https://github.com/BetaHuhn/repo-file-sync-action/issues/168 is resolved
uses: BetaHuhn/repo-file-sync-action@v1.16.5
with:
GH_PAT: ${{ secrets.SYNC_EXAMPLE_PAT }}
SKIP_PR: true

19
.gitignore vendored
View File

@@ -34,13 +34,9 @@ packages/next-auth/utils
packages/next-auth/core
packages/next-auth/jwt
packages/next-auth/react
packages/next-auth/adapters.d.ts
packages/next-auth/adapters.js
packages/next-auth/index.d.ts
packages/next-auth/index.js
packages/next-auth/*.d.ts*
packages/next-auth/*.js
packages/next-auth/next
packages/next-auth/middleware.d.ts
packages/next-auth/middleware.js
# Development app
apps/dev/src/css
@@ -85,4 +81,13 @@ packages/core/adapters.*
packages/core/index.*
packages/core/jwt
packages/core/lib
packages/core/providers
packages/core/providers
# SvelteKit
packages/frameworks-sveltekit/index.*
packages/frameworks-sveltekit/client.*
packages/frameworks-sveltekit/.svelte-kit
packages/frameworks-sveltekit/package
packages/frameworks-sveltekit/vite.config.js.timestamp-*
packages/frameworks-sveltekit/vite.config.ts.timestamp-*

View File

@@ -0,0 +1,220 @@
import NextAuth, { type NextAuthOptions } from "next-auth"
// import { NextRequest } from "next/server"
// Providers
import Apple from "next-auth/providers/apple"
import Auth0 from "next-auth/providers/auth0"
import AzureAD from "next-auth/providers/azure-ad"
import AzureB2C from "next-auth/providers/azure-ad-b2c"
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
// import Cognito from "next-auth/providers/cognito"
import Credentials from "next-auth/providers/credentials"
import Discord from "next-auth/providers/discord"
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
// import Email from "next-auth/providers/email"
import Facebook from "next-auth/providers/facebook"
import Foursquare from "next-auth/providers/foursquare"
import Freshbooks from "next-auth/providers/freshbooks"
import GitHub from "next-auth/providers/github"
import Gitlab from "next-auth/providers/gitlab"
import Google from "next-auth/providers/google"
// import IDS4 from "next-auth/providers/identity-server4"
import Instagram from "next-auth/providers/instagram"
// import Keycloak from "next-auth/providers/keycloak"
import Line from "next-auth/providers/line"
import LinkedIn from "next-auth/providers/linkedin"
import Mailchimp from "next-auth/providers/mailchimp"
// import Okta from "next-auth/providers/okta"
import Osu from "next-auth/providers/osu"
import Patreon from "next-auth/providers/patreon"
import Slack from "next-auth/providers/slack"
import Spotify from "next-auth/providers/spotify"
import Trakt from "next-auth/providers/trakt"
import Twitch from "next-auth/providers/twitch"
import Twitter from "next-auth/providers/twitter"
import Vk from "next-auth/providers/vk"
import Wikimedia from "next-auth/providers/wikimedia"
import WorkOS from "next-auth/providers/workos"
// // Prisma
// import { PrismaClient } from "@prisma/client"
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
// const client = globalThis.prisma || new PrismaClient()
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
// const adapter = PrismaAdapter(client)
// // Fauna
// import { Client as FaunaClient } from "faunadb"
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
// const client = globalThis.fauna || new FaunaClient(opts)
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
// const adapter = FaunaAdapter(client)
// // TypeORM
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
// const adapter = TypeORMLegacyAdapter({
// type: "sqlite",
// name: "next-auth-test-memory",
// database: "./typeorm/dev.db",
// synchronize: true,
// })
// // Supabase
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
// const adapter = SupabaseAdapter({
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
// })
export const authOptions: NextAuthOptions = {
// adapter,
// debug: process.env.NODE_ENV !== "production",
theme: {
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
brandColor: "#1786fb",
},
providers: [
Credentials({
credentials: { password: { label: "Password", type: "password" } },
async authorize(credentials) {
if (credentials.password !== "pw") return null
return {
name: "Fill Murray",
email: "bill@fillmurray.com",
image: "https://www.fillmurray.com/64/64",
id: "1",
foo: "",
}
},
}),
Apple({
clientId: process.env.APPLE_ID,
clientSecret: process.env.APPLE_SECRET,
}),
Auth0({
clientId: process.env.AUTH0_ID,
clientSecret: process.env.AUTH0_SECRET,
issuer: process.env.AUTH0_ISSUER,
}),
AzureAD({
clientId: process.env.AZURE_AD_CLIENT_ID,
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
tenantId: process.env.AZURE_AD_TENANT_ID,
}),
AzureB2C({
clientId: process.env.AZURE_B2C_ID,
clientSecret: process.env.AZURE_B2C_SECRET,
issuer: process.env.AZURE_B2C_ISSUER,
}),
BoxyHQSAML({
issuer: "https://jackson-demo.boxyhq.com",
clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com",
clientSecret: "dummy",
}),
// Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
Discord({
clientId: process.env.DISCORD_ID,
clientSecret: process.env.DISCORD_SECRET,
}),
DuendeIDS6({
clientId: "interactive.confidential",
clientSecret: "secret",
issuer: "https://demo.duendesoftware.com",
}),
Facebook({
clientId: process.env.FACEBOOK_ID,
clientSecret: process.env.FACEBOOK_SECRET,
}),
Foursquare({
clientId: process.env.FOURSQUARE_ID,
clientSecret: process.env.FOURSQUARE_SECRET,
}),
Freshbooks({
clientId: process.env.FRESHBOOKS_ID,
clientSecret: process.env.FRESHBOOKS_SECRET,
}),
GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
Gitlab({
clientId: process.env.GITLAB_ID,
clientSecret: process.env.GITLAB_SECRET,
}),
Google({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
// IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
Instagram({
clientId: process.env.INSTAGRAM_ID,
clientSecret: process.env.INSTAGRAM_SECRET,
}),
// Keycloak({ clientId: process.env.KEYCLOAK_ID, clientSecret: process.env.KEYCLOAK_SECRET, issuer: process.env.KEYCLOAK_ISSUER }),
Line({
clientId: process.env.LINE_ID,
clientSecret: process.env.LINE_SECRET,
}),
LinkedIn({
clientId: process.env.LINKEDIN_ID,
clientSecret: process.env.LINKEDIN_SECRET,
}),
Mailchimp({
clientId: process.env.MAILCHIMP_ID,
clientSecret: process.env.MAILCHIMP_SECRET,
}),
// Okta({ clientId: process.env.OKTA_ID, clientSecret: process.env.OKTA_SECRET, issuer: process.env.OKTA_ISSUER }),
Osu({
clientId: process.env.OSU_CLIENT_ID,
clientSecret: process.env.OSU_CLIENT_SECRET,
}),
Patreon({
clientId: process.env.PATREON_ID,
clientSecret: process.env.PATREON_SECRET,
}),
Slack({
clientId: process.env.SLACK_ID,
clientSecret: process.env.SLACK_SECRET,
}),
Spotify({
clientId: process.env.SPOTIFY_ID,
clientSecret: process.env.SPOTIFY_SECRET,
}),
Trakt({
clientId: process.env.TRAKT_ID,
clientSecret: process.env.TRAKT_SECRET,
}),
Twitch({
clientId: process.env.TWITCH_ID,
clientSecret: process.env.TWITCH_SECRET,
}),
Twitter({
clientId: process.env.TWITTER_ID,
clientSecret: process.env.TWITTER_SECRET,
}),
// TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
Wikimedia({
clientId: process.env.WIKIMEDIA_ID,
clientSecret: process.env.WIKIMEDIA_SECRET,
}),
WorkOS({
clientId: process.env.WORKOS_ID,
clientSecret: process.env.WORKOS_SECRET,
}),
],
}
/**
* Advanced Initialization - route handler
*/
// const handler = async (
// req: NextRequest,
// routeContext: { params: { nextauth: string[] } }
// ): Promise<any> => {
// return NextAuth(req, routeContext, authOptions)
// }
const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

View File

@@ -1,6 +1,6 @@
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
export default async function Page() {
const session = await unstable_getServerSession()
const session = await getServerSession()
return <pre>{JSON.stringify(session, null, 2)}</pre>
}

View File

@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -21,16 +21,15 @@
"@prisma/client": "^3",
"@supabase/supabase-js": "^2.0.5",
"faunadb": "^4",
"next": "13.0.6",
"next": "13.4.12",
"next-auth": "workspace:*",
"@auth/core": "workspace:*",
"nodemailer": "^6",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@types/jsonwebtoken": "^8.5.5",
"@types/react": "^18.0.15",
"@types/react": "^18.0.37",
"@types/react-dom": "^18.0.6",
"fake-smtp-server": "^0.8.0",
"pg": "^8.7.3",

View File

@@ -1,39 +1,39 @@
import { AuthHandler, type AuthOptions } from "@auth/core"
import NextAuth, { NextAuthOptions } from "next-auth"
// Providers
import Apple from "@auth/core/providers/apple"
import Auth0 from "@auth/core/providers/auth0"
import AzureAD from "@auth/core/providers/azure-ad"
import AzureB2C from "@auth/core/providers/azure-ad-b2c"
import BoxyHQSAML from "@auth/core/providers/boxyhq-saml"
// import Cognito from "@auth/core/providers/cognito"
import Credentials from "@auth/core/providers/credentials"
import Discord from "@auth/core/providers/discord"
import DuendeIDS6 from "@auth/core/providers/duende-identity-server6"
// import Email from "@auth/core/providers/email"
import Facebook from "@auth/core/providers/facebook"
import Foursquare from "@auth/core/providers/foursquare"
import Freshbooks from "@auth/core/providers/freshbooks"
import GitHub from "@auth/core/providers/github"
import Gitlab from "@auth/core/providers/gitlab"
import Google from "@auth/core/providers/google"
// import IDS4 from "@auth/core/providers/identity-server4"
import Instagram from "@auth/core/providers/instagram"
// import Keycloak from "@auth/core/providers/keycloak"
import Line from "@auth/core/providers/line"
import LinkedIn from "@auth/core/providers/linkedin"
import Mailchimp from "@auth/core/providers/mailchimp"
// import Okta from "@auth/core/providers/okta"
import Osu from "@auth/core/providers/osu"
import Patreon from "@auth/core/providers/patreon"
import Slack from "@auth/core/providers/slack"
import Spotify from "@auth/core/providers/spotify"
import Trakt from "@auth/core/providers/trakt"
import Twitch from "@auth/core/providers/twitch"
import Twitter from "@auth/core/providers/twitter"
import Vk from "@auth/core/providers/vk"
import Wikimedia from "@auth/core/providers/wikimedia"
import WorkOS from "@auth/core/providers/workos"
import Apple from "next-auth/providers/apple"
import Auth0 from "next-auth/providers/auth0"
import AzureAD from "next-auth/providers/azure-ad"
import AzureB2C from "next-auth/providers/azure-ad-b2c"
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
// import Cognito from "next-auth/providers/cognito"
import Credentials from "next-auth/providers/credentials"
import Discord from "next-auth/providers/discord"
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
// import Email from "next-auth/providers/email"
import Facebook from "next-auth/providers/facebook"
import Foursquare from "next-auth/providers/foursquare"
import Freshbooks from "next-auth/providers/freshbooks"
import GitHub from "next-auth/providers/github"
import Gitlab from "next-auth/providers/gitlab"
import Google from "next-auth/providers/google"
// import IDS4 from "next-auth/providers/identity-server4"
import Instagram from "next-auth/providers/instagram"
// import Keycloak from "next-auth/providers/keycloak"
import Line from "next-auth/providers/line"
import LinkedIn from "next-auth/providers/linkedin"
import Mailchimp from "next-auth/providers/mailchimp"
// import Okta from "next-auth/providers/okta"
import Osu from "next-auth/providers/osu"
import Patreon from "next-auth/providers/patreon"
import Slack from "next-auth/providers/slack"
import Spotify from "next-auth/providers/spotify"
import Trakt from "next-auth/providers/trakt"
import Twitch from "next-auth/providers/twitch"
import Twitter from "next-auth/providers/twitter"
import Vk from "next-auth/providers/vk"
import Wikimedia from "next-auth/providers/wikimedia"
import WorkOS from "next-auth/providers/workos"
// // Prisma
// import { PrismaClient } from "@prisma/client"
@@ -66,7 +66,7 @@ import WorkOS from "@auth/core/providers/workos"
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
// })
export const authOptions: AuthOptions = {
export const authOptions: NextAuthOptions = {
// adapter,
// debug: process.env.NODE_ENV !== "production",
theme: {
@@ -129,26 +129,4 @@ if (authOptions.adapter) {
// )
}
// TODO: move to next-auth/edge
function Auth(...args: any[]) {
const envSecret = process.env.AUTH_SECRET ?? process.env.NEXTAUTH_SECRET
const envTrustHost = !!(process.env.NEXTAUTH_URL ?? process.env.AUTH_TRUST_HOST ?? process.env.VERCEL ?? process.env.NODE_ENV !== "production")
if (args.length === 1) {
return async (req: Request) => {
args[0].secret ??= envSecret
args[0].trustHost ??= envTrustHost
return await AuthHandler(req, args[0])
}
}
args[1].secret ??= envSecret
args[1].trustHost ??= envTrustHost
return AuthHandler(args[0], args[1])
}
// export default Auth(authOptions)
export default function handle(request: Request) {
return Auth(request, authOptions)
}
export const config = { runtime: "experimental-edge" }
export default NextAuth(authOptions)

View File

@@ -1,9 +1,9 @@
// This is an example of to protect an API route
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
if (session) {
res.send({

View File

@@ -1,8 +1,8 @@
// This is an example of how to access a session from an API route
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
res.json(session)
}

View File

@@ -1,11 +1,11 @@
// This is an example of how to query data from Supabase with RLS.
// Learn more about Row Levele Security (RLS): https://supabase.com/docs/guides/auth/row-level-security
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
import { createClient } from "@supabase/supabase-js"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
if (!session)
return res.send(JSON.stringify({ error: "No session!" }, null, 2))

View File

@@ -1,5 +1,5 @@
// This is an example of how to protect content using server rendering
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import Layout from "../components/layout"
import AccessDenied from "../components/access-denied"
@@ -26,11 +26,7 @@ export default function Page({ content, session }) {
}
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
const session = await getServerSession(context.req, context.res, authOptions)
let content = null
if (session) {

View File

@@ -1,6 +1,6 @@
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import Layout from "../components/layout"
import { authOptions } from './api/auth/[...nextauth]';
import { authOptions } from "./api/auth/[...nextauth]"
export default function Page() {
// As this page uses Server Side Rendering, the `session` will be already
@@ -12,11 +12,11 @@ export default function Page() {
<Layout>
<h1>Server Side Rendering</h1>
<p>
This page uses the <strong>unstable_getServerSession()</strong> method
in <strong>getServerSideProps()</strong>.
This page uses the <strong>getServerSession()</strong> method in{" "}
<strong>getServerSideProps()</strong>.
</p>
<p>
Using <strong>unstable_getServerSession()</strong> in{" "}
Using <strong>getServerSession()</strong> in{" "}
<strong>getServerSideProps()</strong> is currently the recommended
approach, although the API may still change, if you need to support
Server Side Rendering with authentication.
@@ -40,11 +40,7 @@ export default function Page() {
export async function getServerSideProps(context) {
return {
props: {
session: await unstable_getServerSession(
context.req,
context.res,
authOptions
),
session: await getServerSession(context.req, context.res, authOptions),
},
}
}

View File

@@ -1,6 +1,6 @@
// This is an example of how to protect content using server rendering
// and fetching data from Supabase with RLS enabled.
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import { createClient } from "@supabase/supabase-js"
import Layout from "../components/layout"
@@ -27,11 +27,7 @@ export default function Page({ data, session }) {
}
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
const session = await getServerSession(context.req, context.res, authOptions)
if (!session)
return {

View File

@@ -23,7 +23,8 @@
{
"name": "next"
}
]
],
"strictNullChecks": true
},
"include": [
"next-env.d.ts",

View File

@@ -26,7 +26,7 @@
},
"devDependencies": {
"@types/node": "^17",
"@types/react": "^18.0.15",
"@types/react": "^18.0.37",
"typescript": "^4"
}
}

View File

@@ -53,6 +53,7 @@ export const authOptions: NextAuthOptions = {
],
theme: {
colorScheme: "light",
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
},
callbacks: {
async jwt({ token }) {

View File

@@ -1,5 +1,5 @@
// This is an example of to protect an API route
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
import type { NextApiRequest, NextApiResponse } from "next"
@@ -8,7 +8,7 @@ export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
if (session) {
return res.send({

View File

@@ -1,5 +1,5 @@
// This is an example of how to access a session from an API route
import { unstable_getServerSession } from "next-auth"
import { getServerSession } from "next-auth"
import { authOptions } from "../auth/[...nextauth]"
import type { NextApiRequest, NextApiResponse } from "next"
@@ -8,6 +8,6 @@ export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
res.send(JSON.stringify(session, null, 2))
}

View File

@@ -1,4 +1,4 @@
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import Layout from "../components/layout"
@@ -12,11 +12,11 @@ export default function ServerSidePage({ session }: { session: Session }) {
<Layout>
<h1>Server Side Rendering</h1>
<p>
This page uses the <strong>unstable_getServerSession()</strong> method
in <strong>getServerSideProps()</strong>.
This page uses the <strong>getServerSession()</strong> method in{" "}
<strong>getServerSideProps()</strong>.
</p>
<p>
Using <strong>unstable_getServerSession()</strong> in{" "}
Using <strong>getServerSession()</strong> in{" "}
<strong>getServerSideProps()</strong> is the recommended approach if you
need to support Server Side Rendering with authentication.
</p>
@@ -37,11 +37,7 @@ export default function ServerSidePage({ session }: { session: Session }) {
export async function getServerSideProps(context: GetServerSidePropsContext) {
return {
props: {
session: await unstable_getServerSession(
context.req,
context.res,
authOptions
),
session: await getServerSession(context.req, context.res, authOptions),
},
}
}

View File

@@ -1,4 +0,0 @@
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
NEXTAUTH_SECRET=
PUBLIC_NEXTAUTH_URL=http://localhost:5173

View File

@@ -1,24 +0,0 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier",
],
plugins: ["svelte3", "@typescript-eslint"],
ignorePatterns: ["*.cjs", "build/**/*"],
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
settings: {
"svelte3/typescript": () => require("typescript"),
},
parserOptions: {
sourceType: "module",
ecmaVersion: 2020,
},
env: {
browser: true,
es2017: true,
node: true,
},
}

View File

@@ -1,8 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example

View File

@@ -1,76 +0,0 @@
# SvelteKit + NextAuth.js Playground
NextAuth.js is committed to bringing easy authentication to other frameworks. https://github.com/nextauthjs/next-auth/issues/2294
SvelteKit support with NextAuth.js is currently experimental. This directory contains a minimal, proof-of-concept application. Parts of this is expected to be abstracted away into a package like `@next-auth/sveltekit`
## Running this Demo
- Copy `.env.example` to `.env`
- In `.env`, set `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`
- See [https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app))
- When creating the OAuth app, set "Homepage URL" to `http://localhost:5173` and Authorization callack URL to `http://localhost:5173/api/auth/callback/github`
- In `.env`, set `NEXTAUTH_SECRET` to any random string
- Build and run the application: `yarn build && yarn start`
## Existing Project
### Add API Route
To add NextAuth.js to a project create a file called `[...nextauth]/+server.js` in routes/api/auth. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
```ts
import { NextAuth, options } from "$lib/next-auth"
export const { GET, POST } = NextAuth(options)
```
### Add [hook](https://kit.svelte.dev/docs/hooks)
```ts
import type { Handle } from "@sveltejs/kit"
import { getServerSession, options as nextAuthOptions } from "$lib/next-auth"
export const handle: Handle = async function handle({
event,
resolve,
}): Promise<Response> {
const session = await getServerSession(event.request, nextAuthOptions)
event.locals.session = session
return resolve(event)
}
```
### Load Session from Primary Layout
```ts
// src/lib/routes/+layout.server.ts
import type { LayoutServerLoad } from "./$types"
export const load: LayoutServerLoad = ({ locals }) => {
return {
session: locals.session,
}
}
```
### Protecting a Route
```ts
// src/lib/routes/protected/+page.ts
import { redirect } from "@sveltejs/kit"
import type { PageLoad } from "./$types"
export const load: PageLoad = async ({ parent }) => {
const { session } = await parent()
if (!session?.user) {
throw redirect(302, "/")
}
return {}
}
```
## Packaging lib
Refer to https://kit.svelte.dev/docs/packaging

View File

@@ -1,43 +0,0 @@
{
"name": "sveltekit-nextauth",
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"start": "HOST=127.0.0.1 PORT=5173 ORIGIN=http://localhost:5173 node ./build",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^1.0.0-next.80",
"@sveltejs/adapter-node": "1.0.0-next.96",
"@sveltejs/kit": "1.0.0-next.511",
"@types/cookie": "^0.5.1",
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/parser": "^5.35.1",
"eslint": "^8.22.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte3": "^4.0.0",
"prettier": "^2.7.1",
"prettier-plugin-svelte": "^2.7.0",
"svelte": "^3.49.0",
"svelte-check": "^2.8.1",
"svelte-preprocess": "^4.10.7",
"tslib": "^2.4.0",
"typescript": "~4.8.2",
"vite": "^3.1.0"
},
"type": "module",
"dependencies": {
"cookie": "0.5.0",
"next-auth": "latest"
},
"prettier": {
"semi": false,
"singleQuote": false
}
}

View File

@@ -1,30 +0,0 @@
/// <reference types="@sveltejs/kit" />
import type {
User as NextAuthUser,
Session as NextAuthSession,
} from "next-auth"
// optionally extend the `user`
interface User extends NextAuthUser {
// add custom fields here
}
interface AppSession extends NextAuthSession {
user: User
}
// See https://kit.svelte.dev/docs/typescript
// for information about these interfaces
declare global {
declare namespace App {
interface Locals {
session: AppSession
}
interface Platform {}
interface Session extends AppSession {}
interface Stuff {}
}
}

View File

@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body>
<div>%sveltekit.body%</div>
</body>
</html>

View File

@@ -1,14 +0,0 @@
import type { Handle } from "@sveltejs/kit"
import { getServerSession, options as nextAuthOptions } from "$lib/next-auth"
export const handle: Handle = async function handle({
event,
resolve,
}): Promise<Response> {
const session = await getServerSession(event.request, nextAuthOptions)
if (session) {
event.locals.session = session
}
return resolve(event)
}

View File

@@ -1,144 +0,0 @@
import type { ServerLoadEvent } from "@sveltejs/kit"
import type { RequestInternal } from "next-auth"
import type { NextAuthAction, NextAuthOptions } from "next-auth/core/types"
import type { OutgoingResponse as NextAuthResponse } from "next-auth/core"
import { NextAuthHandler } from "next-auth/core"
import GithubProvider from "next-auth/providers/github"
import cookie from "cookie"
import {
GITHUB_CLIENT_ID,
GITHUB_CLIENT_SECRET,
NEXTAUTH_SECRET,
} from "$env/static/private"
import { PUBLIC_NEXTAUTH_URL } from "$env/static/public"
// @ts-expect-error import is exported on .default during SSR
const github = GithubProvider?.default || GithubProvider
export const options: NextAuthOptions = {
providers: [
github({
clientId: GITHUB_CLIENT_ID,
clientSecret: GITHUB_CLIENT_SECRET,
}),
],
}
const toSvelteKitResponse = async <
T extends string | any[] | Record<string, any>
>(
request: Request,
nextAuthResponse: NextAuthResponse<T>
): Promise<Response> => {
const { cookies, redirect } = nextAuthResponse
const headers = new Headers()
for (const header of nextAuthResponse?.headers || []) {
// pass headers along from next-auth
headers.set(header.key, header.value)
}
// set-cookie header
if (cookies?.length) {
headers.set(
"set-cookie",
cookies
?.map((item) => cookie.serialize(item.name, item.value, item.options))
.join(",") as string
)
}
let body = undefined
let status = nextAuthResponse.status || 200
if (redirect) {
let formData: FormData | null = null
try {
formData = await request.formData()
} catch {
// no formData passed
}
const { json } = Object.fromEntries(formData ?? [])
if (json !== "true") {
status = 302
headers.set("Location", redirect)
} else {
body = { url: redirect }
}
} else {
body = nextAuthResponse.body
}
// @ts-expect-error - body is a known HTML document or JSON object
return new Response(body, {
status,
headers,
})
}
const SKNextAuthHandler = async (
{ request, url, params }: ServerLoadEvent,
options: NextAuthOptions
): Promise<Response> => {
const [action, provider] = params.nextauth!.split("/")
let body: FormData | undefined
try {
body = await request.formData()
} catch {
// no formData passed
}
options.secret = NEXTAUTH_SECRET
const req: RequestInternal = {
host: PUBLIC_NEXTAUTH_URL,
body: Object.fromEntries(body ?? []),
query: Object.fromEntries(url.searchParams),
headers: request.headers,
method: request.method,
cookies: cookie.parse(request.headers.get("cookie") || ""),
action: action as NextAuthAction,
providerId: provider,
error: provider,
}
const response = await NextAuthHandler({
req,
options,
})
return toSvelteKitResponse(request, response)
}
export const getServerSession = async (
request: Request,
options: NextAuthOptions
): Promise<App.Session | null> => {
options.secret = NEXTAUTH_SECRET
const session = await NextAuthHandler<App.Session>({
req: {
host: PUBLIC_NEXTAUTH_URL,
action: "session",
method: "GET",
cookies: cookie.parse(request.headers.get("cookie") || ""),
headers: request.headers,
},
options,
})
const { body } = session
if (body && Object.keys(body).length) {
return body as App.Session
}
return null
}
export const NextAuth = (
options: NextAuthOptions
): {
GET: (event: ServerLoadEvent) => Promise<unknown>
POST: (event: ServerLoadEvent) => Promise<unknown>
} => ({
GET: (event) => SKNextAuthHandler(event, options),
POST: (event) => SKNextAuthHandler(event, options),
})

View File

@@ -1,7 +0,0 @@
import type { LayoutServerLoad } from "./$types"
export const load: LayoutServerLoad = ({ locals }) => {
return {
session: locals.session,
}
}

View File

@@ -1,151 +0,0 @@
<script lang="ts">
import { page } from "$app/stores"
</script>
<div>
<header>
<div class="signedInStatus">
<p class="nojs-show loaded">
{#if Object.keys($page.data.session || {}).length}
{#if $page.data.session.user.image}
<span
style="background-image: url('{$page.data.session.user.image}')"
class="avatar"
/>
{/if}
<span class="signedInText">
<small>Signed in as</small><br />
<strong
>{$page.data.session.user.email ||
$page.data.session.user.name}</strong
>
</span>
<a href="/api/auth/signout" class="button">Sign out</a>
{:else}
<span class="notSignedInText">You are not signed in</span>
<a href="/api/auth/signin" class="buttonPrimary">Sign in</a>
{/if}
</p>
</div>
<nav>
<ul class="navItems">
<li class="navItem"><a href="/">Home</a></li>
<li class="navItem"><a href="/protected">Protected</a></li>
</ul>
</nav>
</header>
<slot />
</div>
<style>
:global(body) {
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;
background: #fff;
color: #333;
}
:global(li),
:global(p) {
line-height: 1.5rem;
}
:global(a) {
font-weight: 500;
}
:global(hr) {
border: 1px solid #ddd;
}
:global(iframe) {
background: #ccc;
border: 1px solid #ccc;
height: 10rem;
width: 100%;
border-radius: 0.5rem;
filter: invert(1);
}
.nojs-show {
opacity: 1;
top: 0;
}
.signedInStatus {
display: block;
min-height: 4rem;
width: 100%;
}
.loaded {
position: relative;
top: 0;
opacity: 1;
overflow: hidden;
border-radius: 0 0 0.6rem 0.6rem;
padding: 0.6rem 1rem;
margin: 0;
background-color: rgba(0, 0, 0, 0.05);
transition: all 0.2s ease-in;
}
.signedInText,
.notSignedInText {
position: absolute;
padding-top: 0.8rem;
left: 1rem;
right: 6.5rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: inherit;
z-index: 1;
line-height: 1.3rem;
}
.signedInText {
padding-top: 0rem;
left: 4.6rem;
}
.avatar {
border-radius: 2rem;
float: left;
height: 2.8rem;
width: 2.8rem;
background-color: white;
background-size: cover;
background-repeat: no-repeat;
}
.button,
.buttonPrimary {
float: right;
margin-right: -0.4rem;
font-weight: 500;
border-radius: 0.3rem;
cursor: pointer;
font-size: 1rem;
line-height: 1.4rem;
padding: 0.7rem 0.8rem;
position: relative;
z-index: 10;
background-color: transparent;
color: #555;
}
.buttonPrimary {
background-color: #346df1;
border-color: #346df1;
color: #fff;
text-decoration: none;
padding: 0.7rem 1.4rem;
}
.buttonPrimary:hover {
box-shadow: inset 0 0 5rem rgba(0, 0, 0, 0.2);
}
.navItems {
margin-bottom: 2rem;
padding: 0;
list-style: none;
}
.navItem {
display: inline-block;
margin-right: 1rem;
}
</style>

View File

@@ -1,7 +0,0 @@
<h1>SvelteKit + NextAuth.js Example</h1>
<p>
This is an example site to demonstrate how to use <a
href="https://kit.svelte.dev/">SvelteKit</a
>
with <a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
</p>

View File

@@ -1,3 +0,0 @@
import { NextAuth, options } from "$lib/next-auth"
export const { GET, POST } = NextAuth(options)

View File

@@ -1,10 +0,0 @@
<script lang="ts">
import { page } from "$app/stores"
</script>
<h1>Protected page</h1>
<p>
This is a protected content. You can access this content because you are
signed in.
</p>
<p>Session expiry: {$page.data.session.expires}</p>

View File

@@ -1,10 +0,0 @@
import { redirect } from "@sveltejs/kit"
import type { PageLoad } from "./$types"
export const load: PageLoad = async ({ parent }) => {
const { session } = await parent()
if (!session?.user) {
throw redirect(302, "/")
}
return {}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,14 +0,0 @@
import adapter from "@sveltejs/adapter-node" // or use https://github.com/sveltejs/kit/tree/master/packages/adapter-auto
import preprocess from "svelte-preprocess"
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),
kit: {
adapter: adapter(),
},
}
export default config

View File

@@ -1,17 +0,0 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
// from the referenced tsconfig.json - TypeScript does not merge them in
}

View File

@@ -1,8 +0,0 @@
import { sveltekit } from "@sveltejs/kit/vite"
import type { UserConfig } from "vite"
const config: UserConfig = {
plugins: [sveltekit()],
}
export default config

File diff suppressed because it is too large Load Diff

23
docs/docs/adapters.md Normal file
View File

@@ -0,0 +1,23 @@
---
id: adapters
title: Adapters
---
Visit the [authjs.dev](https://authjs.dev/reference/adapters) page for the up-to-date documentation.
- [Dgraph](https://authjs.dev/reference/adapter/dgraph)
- [Drizzle](https://authjs.dev/reference/adapter/drizzle)
- [DynamoDB](https://authjs.dev/reference/adapter/dynamodb)
- [Fauna](https://authjs.dev/reference/adapter/fauna)
- [Firebase](https://authjs.dev/reference/adapter/firebase)
- [kysely](https://authjs.dev/reference/adapter/kysely)
- [MikroORM](https://authjs.dev/reference/adapter/mikro-orm)
- [MongoDB](https://authjs.dev/reference/adapter/mongodb)
- [neo4j](https://authjs.dev/reference/adapter/neo4j)
- [Prisma](https://authjs.dev/reference/adapter/prisma)
- [PouchDB](https://authjs.dev/reference/adapter/pouchdb)
- [Sequelize](https://authjs.dev/reference/adapter/sequelize)
- [Supabase](https://authjs.dev/reference/adapter/supabase)
- [TypeORM](https://authjs.dev/reference/adapter/typeorm)
- [Upstash Redis](https://authjs.dev/reference/adapter/upstash-redis)
- [Xata](https://authjs.dev/reference/adapter/xata)

View File

@@ -1,250 +0,0 @@
---
id: dgraph
title: Dgraph
---
# Dgraph
This is the Dgraph Adapter for [`next-auth`](https://next-auth.js.org).
## Getting Started
1. Install the necessary packages
```bash npm2yarn2pnpm
npm install next-auth @next-auth/dgraph-adapter
```
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { DgraphAdapter } from "@next-auth/dgraph-adapter"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [],
adapter: DgraphAdapter({
endpoint: process.env.DGRAPH_GRAPHQL_ENDPOINT,
authToken: process.env.DGRAPH_GRAPHQL_KEY,
// you can omit the following properties if you are running an unsecure schema
authHeader: process.env.AUTH_HEADER, // default: "Authorization",
jwtSecret: process.env.SECRET,
}),
})
```
## Quick start with the unsecure schema
The quickest way to use Dgraph is by applying the unsecure schema to your [local](https://dgraph.io/docs/graphql/admin/#modifying-a-schema) Dgraph instance or if using Dgraph [cloud](https://dgraph.io/docs/cloud/cloud-quick-start/#the-schema) you can paste the schema in the codebox to update.
:::warning
This approach is not secure or for production use, and does not require a `jwtSecret`.
:::
> This schema is adapted for use in Dgraph and based upon our main [schema](/adapters/models)
#### Unsecure schema
```graphql
type Account {
id: ID
type: String
provider: String @search(by: [hash])
providerAccountId: String @search(by: [hash])
refreshToken: String
expires_at: Int64
accessToken: String
token_type: String
refresh_token: String
access_token: String
scope: String
id_token: String
session_state: String
user: User @hasInverse(field: "accounts")
}
type Session {
id: ID
expires: DateTime
sessionToken: String @search(by: [hash])
user: User @hasInverse(field: "sessions")
}
type User {
id: ID
name: String
email: String @search(by: [hash])
emailVerified: DateTime
image: String
accounts: [Account] @hasInverse(field: "user")
sessions: [Session] @hasInverse(field: "user")
}
type VerificationToken {
id: ID
identifier: String @search(by: [hash])
token: String @search(by: [hash])
expires: DateTime
}
```
## Securing your database
For production deployments you will want to restrict the access to the types used
by next-auth. The main form of access control used in Dgraph is via `@auth` directive alongide types in the schema.
#### Secure schema
```graphql
type Account
@auth(
delete: { rule: "{$nextAuth: { eq: true } }" }
add: { rule: "{$nextAuth: { eq: true } }" }
query: { rule: "{$nextAuth: { eq: true } }" }
update: { rule: "{$nextAuth: { eq: true } }" }
) {
id: ID
type: String
provider: String @search(by: [hash])
providerAccountId: String @search(by: [hash])
refreshToken: String
expires_at: Int64
accessToken: String
token_type: String
refresh_token: String
access_token: String
scope: String
id_token: String
session_state: String
user: User @hasInverse(field: "accounts")
}
type Session
@auth(
delete: { rule: "{$nextAuth: { eq: true } }" }
add: { rule: "{$nextAuth: { eq: true } }" }
query: { rule: "{$nextAuth: { eq: true } }" }
update: { rule: "{$nextAuth: { eq: true } }" }
) {
id: ID
expires: DateTime
sessionToken: String @search(by: [hash])
user: User @hasInverse(field: "sessions")
}
type User
@auth(
query: {
or: [
{
rule: """
query ($userId: String!) {queryUser(filter: { id: { eq: $userId } } ) {id}}
"""
}
{ rule: "{$nextAuth: { eq: true } }" }
]
}
delete: { rule: "{$nextAuth: { eq: true } }" }
add: { rule: "{$nextAuth: { eq: true } }" }
update: {
or: [
{
rule: """
query ($userId: String!) {queryUser(filter: { id: { eq: $userId } } ) {id}}
"""
}
{ rule: "{$nextAuth: { eq: true } }" }
]
}
) {
id: ID
name: String
email: String @search(by: [hash])
emailVerified: DateTime
image: String
accounts: [Account] @hasInverse(field: "user")
sessions: [Session] @hasInverse(field: "user")
}
type VerificationToken
@auth(
delete: { rule: "{$nextAuth: { eq: true } }" }
add: { rule: "{$nextAuth: { eq: true } }" }
query: { rule: "{$nextAuth: { eq: true } }" }
update: { rule: "{$nextAuth: { eq: true } }" }
) {
id: ID
identifier: String @search(by: [hash])
token: String @search(by: [hash])
expires: DateTime
}
# Dgraph.Authorization {"VerificationKey":"<YOUR JWT SECRET HERE>","Header":"<YOUR AUTH HEADER HERE>","Namespace":"<YOUR CUSTOM NAMESPACE HERE>","Algo":"HS256"}
```
#### Dgraph.Authorization
In order to secure your graphql backend define the `Dgraph.Authorization` object at the
bottom of your schema and provide `authHeader` and `jwtSecret` values to the DgraphClient.
```js
# Dgraph.Authorization {"VerificationKey":"<YOUR JWT SECRET HERE>","Header":"<YOUR AUTH HEADER HERE>","Namespace":"YOUR CUSTOM NAMESPACE HERE","Algo":"HS256"}
```
#### VerificationKey and jwtSecret
This is the key used to sign the JWT. Ex. `process.env.SECRET` or `process.env.APP_SECRET`.
#### Header and authHeader
The `Header` tells Dgraph where to lookup a JWT within the headers of the incoming requests made to the dgraph server.
You have to configure it at the bottom of your schema file. This header is the same as the `authHeader` property you
provide when you instantiate the `DgraphClient`.
#### The nextAuth secret
The `$nextAuth` secret is securely generated using the `jwtSecret` and injected by the DgraphAdapter in order to allow interacting with the JWT DgraphClient for anonymous user requests made within the system `ie. login, register`. This allows
secure interactions to be made with all the auth types required by next-auth. You have to specify it for each auth rule of
each type defined in your secure schema.
```js
type VerificationRequest
@auth(
delete: { rule: "{$nextAuth: { eq: true } }" },
add: { rule: "{$nextAuth: { eq: true } }" },
query: { rule: "{$nextAuth: { eq: true } }" },
update: { rule: "{$nextAuth: { eq: true } }" }
) {
...
}
```
## Working with JWT session and @auth directive
Dgraph only works with HS256 or RS256 algorithms. If you want to use session jwt to securely interact with your dgraph
database you must customize next-auth `encode` and `decode` functions, as the default algorithm is HS512. You can
further customize the jwt with roles if you want to implement [`RBAC logic`](https://dgraph.io/docs/graphql/authorization/directive/#role-based-access-control).
```js
import * as jwt from "jsonwebtoken"
export default NextAuth({
session: {
strategy: "jwt",
},
jwt: {
secret: process.env.SECRET,
encode: async ({ secret, token }) => {
return jwt.sign({ ...token, userId: token.id }, secret, {
algorithm: "HS256",
expiresIn: 30 * 24 * 60 * 60, // 30 days
})
},
decode: async ({ secret, token }) => {
return jwt.verify(token, secret, { algorithms: ["HS256"] })
},
},
})
```
Once your `Dgraph.Authorization` is defined in your schema and the JWT settings are set, this will allow you to define
[`@auth rules`](https://dgraph.io/docs/graphql/authorization/authorization-overview/) for every part of your schema.

View File

@@ -1,147 +0,0 @@
---
id: dynamodb
title: DynamoDB
---
# DynamoDB
This is the AWS DynamoDB Adapter for next-auth. This package can only be used in conjunction with the primary next-auth package. It is not a standalone package.
By default, the adapter expects a table with a partition key `pk` and a sort key `sk`, as well as a global secondary index named `GSI1` with `GSI1PK` as partition key and `GSI1SK` as sorting key. To automatically delete sessions and verification requests after they expire using [dynamodb TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) you should [enable the TTL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/time-to-live-ttl-how-to.html) with attribute name 'expires'. You can set whatever you want as the table name and the billing method.
You can find the full schema in the table structure section below.
## Getting Started
1. Install `next-auth` and `@next-auth/dynamodb-adapter`
```bash npm2yarn2pnpm
npm install next-auth @next-auth/dynamodb-adapter
```
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
You need to pass `DynamoDBDocument` client from the modular [`aws-sdk`](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/dynamodb-example-dynamodb-utilities.html) v3 to the adapter.
The default table name is `next-auth`, but you can customise that by passing `{ tableName: 'your-table-name' }` as the second parameter in the adapter.
```javascript title="pages/api/auth/[...nextauth].js"
import { DynamoDB } from "@aws-sdk/client-dynamodb"
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
import { DynamoDBAdapter } from "@next-auth/dynamodb-adapter"
const config: DynamoDBClientConfig = {
credentials: {
accessKeyId: process.env.NEXT_AUTH_AWS_ACCESS_KEY as string,
secretAccessKey: process.env.NEXT_AUTH_AWS_SECRET_KEY as string,
},
region: process.env.NEXT_AUTH_AWS_REGION,
};
const client = DynamoDBDocument.from(new DynamoDB(config), {
marshallOptions: {
convertEmptyValues: true,
removeUndefinedValues: true,
convertClassInstanceToMap: true,
},
})
export default NextAuth({
// Configure one or more authentication providers
providers: [
Providers.GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
Providers.Email({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
}),
// ...add more providers here
],
adapter: DynamoDBAdapter(
client
),
...
});
```
(AWS secrets start with `NEXT_AUTH_` in order to not conflict with [Vercel's reserved environment variables](https://vercel.com/docs/environment-variables#reserved-environment-variables).)
## Schema
The table respects the single table design pattern. This has many advantages:
- Only one table to manage, monitor and provision.
- Querying relations is faster than with multi-table schemas (for eg. retrieving all sessions for a user).
- Only one table needs to be replicated, if you want to go multi-region.
> This schema is adapted for use in DynamoDB and based upon our main [schema](/adapters/models)
![DynamoDB Table](https://i.imgur.com/hGZtWDq.png)
You can create this table with infrastructure as code using [`aws-cdk`](https://github.com/aws/aws-cdk) with the following table definition:
```javascript title=stack.ts
new dynamodb.Table(this, `NextAuthTable`, {
tableName: "next-auth",
partitionKey: { name: "pk", type: dynamodb.AttributeType.STRING },
sortKey: { name: "sk", type: dynamodb.AttributeType.STRING },
timeToLiveAttribute: "expires",
}).addGlobalSecondaryIndex({
indexName: "GSI1",
partitionKey: { name: "GSI1PK", type: dynamodb.AttributeType.STRING },
sortKey: { name: "GSI1SK", type: dynamodb.AttributeType.STRING },
})
```
Alternatively you can use this cloudformation template:
```yaml title=cloudformation.yaml
NextAuthTable:
Type: "AWS::DynamoDB::Table"
Properties:
TableName: next-auth
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
- AttributeName: sk
AttributeType: S
- AttributeName: GSI1PK
AttributeType: S
- AttributeName: GSI1SK
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
- AttributeName: sk
KeyType: RANGE
GlobalSecondaryIndexes:
- IndexName: GSI1
Projection:
ProjectionType: ALL
KeySchema:
- AttributeName: GSI1PK
KeyType: HASH
- AttributeName: GSI1SK
KeyType: RANGE
TimeToLiveSpecification:
AttributeName: expires
Enabled: true
```
## Custom Schema
You can configure your custom table schema by passing the `options` key to the adapter constructor:
```
const adapter = DynamoDBAdapter(client, {
tableName: "custom-table-name",
partitionKey: "custom-pk",
sortKey: "custom-sk",
indexName: "custom-index-name",
indexPartitionKey: "custom-index-pk",
indexSortKey: "custom-index-sk",
})
```

View File

@@ -1,85 +0,0 @@
---
id: fauna
title: FaunaDB
---
# FaunaDB
This is the Fauna Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
You can find the Fauna schema and seed information in the docs at [next-auth.js.org/adapters/fauna](https://next-auth.js.org/adapters/fauna).
## Getting Started
1. Install the necessary packages
```bash npm2yarn2pnpm
npm install next-auth @next-auth/fauna-adapter faunadb
```
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { Client as FaunaClient } from "faunadb"
import { FaunaAdapter } from "@next-auth/fauna-adapter"
const client = new FaunaClient({
secret: "secret",
scheme: "http",
domain: "localhost",
port: 8443,
})
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/providers/overview
providers: [],
adapter: FaunaAdapter(client)
...
})
```
## Schema
Run the following commands inside of the `Shell` tab in the Fauna dashboard to setup the appropriate collections and indexes.
```javascript
CreateCollection({ name: "accounts" })
CreateCollection({ name: "sessions" })
CreateCollection({ name: "users" })
CreateCollection({ name: "verification_tokens" })
```
```javascript
CreateIndex({
name: "account_by_provider_and_provider_account_id",
source: Collection("accounts"),
unique: true,
terms: [
{ field: ["data", "provider"] },
{ field: ["data", "providerAccountId"] },
],
})
CreateIndex({
name: "session_by_session_token",
source: Collection("sessions"),
unique: true,
terms: [{ field: ["data", "sessionToken"] }],
})
CreateIndex({
name: "user_by_email",
source: Collection("users"),
unique: true,
terms: [{ field: ["data", "email"] }],
})
CreateIndex({
name: "verification_token_by_identifier_and_token",
source: Collection("verification_tokens"),
unique: true,
terms: [{ field: ["data", "identifier"] }, { field: ["data", "token"] }],
})
```
> This schema is adapted for use in Fauna and based upon our main [schema](/adapters/models)

View File

@@ -1,91 +0,0 @@
---
id: firebase
title: Firebase
---
# Firebase
This is the Firebase (Firestore) Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
## Getting Started
1. Install the necessary packages
```bash npm2yarn2pnpm
npm install next-auth @next-auth/firebase-adapter
```
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { FirestoreAdapter } from "@next-auth/firebase-adapter"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/providers
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
adapter: FirestoreAdapter({
apiKey: process.env.FIREBASE_API_KEY,
appId: process.env.FIREBASE_APP_ID,
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.FIREBASE_DATABASE_URL,
projectId: process.env.FIREBASE_PROJECT_ID,
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
// Optional emulator config (see below for options)
emulator: {},
}),
// ...
});
```
## Options
When initializing the firestore adapter, you must pass in the firebase config object with the details from your project. More details on how to obtain that config object can be found [here](https://support.google.com/firebase/answer/7015592).
An example firebase config looks like this:
```js
const firebaseConfig = {
apiKey: "AIzaSyDOCAbC123dEf456GhI789jKl01-MnO",
authDomain: "myapp-project-123.firebaseapp.com",
databaseURL: "https://myapp-project-123.firebaseio.com",
projectId: "myapp-project-123",
storageBucket: "myapp-project-123.appspot.com",
messagingSenderId: "65211879809",
appId: "1:65211879909:web:3ae38ef1cdcb2e01fe5f0c",
measurementId: "G-8GSGZQ44ST",
}
```
See [firebase.google.com/docs/web/setup](https://firebase.google.com/docs/web/setup) for more details.
You can optionally pass in emulator options to automatically connect to your local Firebase emulator.
```js
FirestoreAdapter({
// ...
// Passing in an enable object will enable the emulator
emulator: {
// Optional host, defaults to `localhost`
host: 'localhost',
// Optional port, defaults to `3001`
port: 3001,
},
}),
```
:::tip **From Firebase**
**Caution**: We do not recommend manually modifying an app's Firebase config file or object. If you initialize an app with invalid or missing values for any of these required "Firebase options", then your end users may experience serious issues.
For open source projects, we generally do not recommend including the app's Firebase config file or object in source control because, in most cases, your users should create their own Firebase projects and point their apps to their own Firebase resources (via their own Firebase config file or object).
:::

View File

@@ -1,113 +0,0 @@
---
id: mikro-orm
title: MikroORM
---
To use this Adapter, you need to install Mikro ORM, the driver that suits your database, and the separate `@next-auth/mikro-orm-adapter` package:
```bash npm2yarn2pnpm
npm install next-auth @next-auth/mikro-orm-adapter @mikro-orm/core @mikro-orm/[YOUR DRIVER]
```
Configure NextAuth.js to use the MikroORM Adapter:
```typescript title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import { MikroOrmAdapter } from "@next-auth/mikro-orm-adapter"
export default NextAuth({
adapter: MikroOrmAdapter({
// MikroORM options object. Ref: https://mikro-orm.io/docs/next/configuration#driver
dbName: "./db.sqlite",
type: "sqlite",
debug: process.env.DEBUG === "true" || process.env.DEBUG?.includes("db"),
}),
providers: [],
})
```
## Setup
### Passing custom entities
The MikroORM adapter ships with its own set of entities. If you'd like to extend them, you can optionally pass them to the adapter.
> This schema is adapted for use in MikroORM and based upon our main [schema](/adapters/models)
```typescript title="pages/api/auth/[...nextauth].ts"
import config from "config/mikro-orm.ts"
import {
Cascade,
Collection,
Entity,
OneToMany,
PrimaryKey,
Property,
Unique,
} from "@mikro-orm/core"
import { defaultEntities } from "@next-auth/mikro-orm-adapter"
const { Account, Session } = defaultEntities
@Entity()
export class User implements defaultEntities.User {
@PrimaryKey()
id: string = randomUUID()
@Property({ nullable: true })
name?: string
@Property({ nullable: true })
@Unique()
email?: string
@Property({ type: "Date", nullable: true })
emailVerified: Date | null = null
@Property({ nullable: true })
image?: string
@OneToMany({
entity: () => Session,
mappedBy: (session) => session.user,
hidden: true,
orphanRemoval: true,
cascade: [Cascade.ALL],
})
sessions = new Collection<Session>(this)
@OneToMany({
entity: () => Account,
mappedBy: (account) => account.user,
hidden: true,
orphanRemoval: true,
cascade: [Cascade.ALL],
})
accounts = new Collection<Account>(this)
@Enum({ hidden: true })
role = "ADMIN"
}
export default NextAuth({
adapter: MikroOrmAdapter(config, { entities: { User } }),
})
```
### Including the default entities in your MikroORM config
You may want to include the defaultEntities in your MikroORM configuration to include them in Migrations etc.
To achieve that include them in your "entities" array:
```typescript title="config/mikro-orm.ts"
import { Options } from "@mikro-orm/core";
import { defaultEntities } from "@next-auth/mikro-orm-adapter"
const config: Options = {
...
entities: [VeryImportantEntity, ...Object.values(defaultEntities)],
};
export default config;
```

View File

@@ -1,118 +0,0 @@
---
id: models
title: Models
---
NextAuth.js can be used with any database. Models tell you what structures NextAuth.js expects from your database. Models will vary slightly depending on which adapter you use, but in general, will look something like this. Each adapter's model/schema will be slightly adapted for its needs, but will look very much like this schema below:
```mermaid
erDiagram
User ||--|{ Account : ""
User {
string id
string name
string email
timestamp emailVerified
string image
}
User ||--|{ Session : ""
Session {
string id
timestamp expires
string sessionToken
string userId
}
Account {
string id
string userId
string type
string provider
string providerAccountId
string refresh_token
string access_token
int expires_at
string token_type
string scope
string id_token
string session_state
string oauth_token_secret
string oauth_token
}
VerificationToken {
string identifier
string token
timestamp expires
}
```
More information about each Model / Table can be found below.
:::note
You can [create your own adapter](/tutorials/creating-a-database-adapter) if you want to use NextAuth.js with a database that is not supported out of the box, or you have to change fields on any of the models.
:::
---
## User
The User model is for information such as the user's name and email address.
Email address is optional, but if one is specified for a User then it must be unique.
:::note
If a user first signs in with OAuth then their email address is automatically populated using the one from their OAuth profile, if the OAuth provider returns one.
This provides a way to contact users and for users to maintain access to their account and sign in using email in the event they are unable to sign in with the OAuth provider in future (if the [Email Provider](/providers/email) is configured).
:::
User creation in the database is automatic, and happens when the user is logging in for the first time with a provider. The default data saved is `id`, `name`, `email` and `image`. You can add more profile data by returning extra fields in your [OAuth provider's `profile()`](/configuration/providers/oauth#options) callback.
## Account
The Account model is for information about OAuth accounts associated with a User. It will usually contain `access_token`, `id_token` and other OAuth specific data. [`TokenSet`](https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-tokensetinput) from `openid-client` might give you an idea of all the fields.
:::note
In case of an OAuth 1.0 provider (like Twitter), you will have to look for `oauth_token` and `oauth_token_secret` string fields. GitHub also has an extra `refresh_token_expires_in` integer field. You have to make sure that your database schema includes these fields.
:::
A single User can have multiple Accounts, but each Account can only have one User.
Linking Accounts to Users happen automatically, only when they have the same e-mail address, and the user is currently signed in. Check the [FAQ](/faq#security) for more information why this is a requirement.
:::tip
You can manually unlink accounts, if your adapter implements the `unlinkAccount` method. Make sure to take all the necessary security steps to avoid data loss.
:::
:::note
Linking and unlinking accounts through an API is a planned feature: https://github.com/nextauthjs/next-auth/issues/230
:::
## Session
The Session model is used for database sessions. It is not used if JSON Web Tokens are enabled. Keep in mind, that you can use a database to persist Users and Accounts, and still use JWT for sessions. See the [`session.strategy`](/configuration/options#session) option.
A single User can have multiple Sessions, each Session can only have one User.
:::tip
When a Session is read, we check if it's `expires` field indicates an invalid session, and delete it from the database. You can also do this clean-up periodically in the background to avoid our extra delete call to the database during an active session retrieval. This might result in a slight performance increase in a few cases.
:::
## Verification Token
The Verification Token model is used to store tokens for passwordless sign in.
A single User can have multiple open Verification Tokens (e.g. to sign in to different devices).
It has been designed to be extendable for other verification purposes in the future (e.g. 2FA / short codes).
:::note
NextAuth.js makes sure that every token is usable only once, and by default has a short (1 day, can be configured by [`maxAge`](/configuration/providers/email#options)) lifetime. If your user did not manage to finish the sign-in flow in time, they will have to start the sign-in process again.
:::
:::tip
Due to users forgetting or failing at the sign-in flow, you might end up with unwanted rows in your database, that you might have to periodically clean up to avoid filling the database up with unnecessary data.
:::
## RDBMS Naming Convention
In the NextAuth.js v4 some schemas for the providers which support classic RDBMS type databases, like Prisma and TypeORM, have ended up with column names with mixed casing, i.e. snake_case and camelCase. If this is an issue for you or your underlying database system, please take a look at the "Naming Convention" section in the Prisma or TypeORM page.

View File

@@ -1,66 +0,0 @@
---
id: mongodb
title: MongoDB
---
# MongoDB
The MongoDB adapter does not handle connections automatically, so you will have to make sure that you pass the Adapter a `MongoClient` that is connected already. Below you can see an example how to do this.
## Usage
1. Install the necessary packages
```bash npm2yarn2pnpm
npm install next-auth @next-auth/mongodb-adapter mongodb
```
2. Add `lib/mongodb.ts`
```ts
// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
import { MongoClient } from 'mongodb'
if (!process.env.MONGODB_URI) {
throw new Error('Invalid/Missing environment variable: "MONGODB_URI"')
}
const uri = process.env.MONGODB_URI
const options = {}
let client
let clientPromise: Promise<MongoClient>
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options)
global._mongoClientPromise = client.connect()
}
clientPromise = global._mongoClientPromise
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options)
clientPromise = client.connect()
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise
```
3. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
```js
import NextAuth from "next-auth"
import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
import clientPromise from "../../../lib/mongodb"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
adapter: MongoDBAdapter(clientPromise),
...
})
```

View File

@@ -1,117 +0,0 @@
---
id: neo4j
title: Neo4j
---
# Neo4j
This is the Neo4j Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
## Getting Started
1. Install the necessary packages
```bash npm2yarn2pnpm
npm install next-auth @next-auth/neo4j-adapter neo4j-driver
```
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
```javascript title="pages/api/auth/[...nextauth].js"
import neo4j from "neo4j-driver"
import { Neo4jAdapter } from "@next-auth/neo4j-adapter"
const driver = neo4j.driver(
"bolt://localhost",
neo4j.auth.basic("neo4j", "password")
)
const neo4jSession = driver.session()
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [],
adapter: Neo4jAdapter(neo4jSession),
...
})
```
## Schema
### Node labels
The following node labels are used.
- User
- Account
- Session
- VerificationToken
### Relationships
The following relationships and relationship labels are used.
- (:User)-[:HAS_ACCOUNT]->(:Account)
- (:User)-[:HAS_SESSION]->(:Session)
### Properties
This schema is adapted for use in Neo4J and is based upon our main [models](/adapters/models). Please check there for the node properties. Relationships have no properties.
### Indexes
Optimum indexes will vary on your edition of Neo4j i.e. community or enterprise, and in case you have your own additional data on the nodes. Below are basic suggested indexes.
1. For **both** Community Edition & Enterprise Edition create constraints and indexes
```cypher
CREATE CONSTRAINT user_id_constraint IF NOT EXISTS
ON (u:User) ASSERT u.id IS UNIQUE;
CREATE INDEX user_id_index IF NOT EXISTS
FOR (u:User) ON (u.id);
CREATE INDEX user_email_index IF NOT EXISTS
FOR (u:User) ON (u.email);
CREATE CONSTRAINT session_session_token_constraint IF NOT EXISTS
ON (s:Session) ASSERT s.sessionToken IS UNIQUE;
CREATE INDEX session_session_token_index IF NOT EXISTS
FOR (s:Session) ON (s.sessionToken);
```
2.a. For Community Edition **only** create single-property indexes
```cypher
CREATE INDEX account_provider_index IF NOT EXISTS
FOR (a:Account) ON (a.provider);
CREATE INDEX account_provider_account_id_index IF NOT EXISTS
FOR (a:Account) ON (a.providerAccountId);
CREATE INDEX verification_token_identifier_index IF NOT EXISTS
FOR (v:VerificationToken) ON (v.identifier);
CREATE INDEX verification_token_token_index IF NOT EXISTS
FOR (v:VerificationToken) ON (v.token);
```
2.b. For Enterprise Edition **only** create composite node key constraints and indexes
```cypher
CREATE CONSTRAINT account_provider_composite_constraint IF NOT EXISTS
ON (a:Account) ASSERT (a.provider, a.providerAccountId) IS NODE KEY;
CREATE INDEX account_provider_composite_index IF NOT EXISTS
FOR (a:Account) ON (a.provider, a.providerAccountId);
CREATE CONSTRAINT verification_token_composite_constraint IF NOT EXISTS
ON (v:VerificationToken) ASSERT (v.identifier, v.token) IS NODE KEY;
CREATE INDEX verification_token_composite_index IF NOT EXISTS
FOR (v:VerificationToken) ON (v.identifier, v.token);
```

View File

@@ -1,54 +0,0 @@
---
id: overview
title: Overview
---
An **Adapter** in NextAuth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc. Adapters are optional, unless you need to persist user information in your own database, or you want to implement certain flows. The [Email Provider](/providers/email) requires an adapter to be able to save [Verification Tokens](/adapters/models#verification-token).
:::tip
When using a database, you can still use JWT for session handling for fast access. See the [`session.strategy`](/configuration/options#session) option. Read about the trade-offs of JWT in the [FAQ](/faq#json-web-tokens).
:::
We have a list of official adapters that are distributed as their own packages under the `@next-auth/{name}-adapter` namespace. Their source code is available in their various adapters package directories at [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth/tree/main/packages).
- [`xata`](./xata)
- [`prisma`](./prisma)
- [`fauna`](./fauna)
- [`dynamodb`](./dynamodb)
- [`firebase`](./firebase)
- [`pouchdb`](./pouchdb)
- [`mongodb`](./mongodb)
- [`neo4j`](./neo4j)
- [`typeorm-legacy`](./typeorm)
- [`sequelize`](./sequelize)
- [`supabase`](./supabase)
- [`dgraph`](./dgraph)
- [`upstash-redis`](./upstash-redis)
## Custom Adapter
If you have a database/backend that we don't officially support, you can create your own adapter.
See the tutorial for [creating a database Adapter](/tutorials/creating-a-database-adapter) for more information.
:::tip
If you would like to see a new adapter in the official repository, please [open a PR](https://github.com/nextauthjs/next-auth/issues/new) and we will help you to get it merged. Tell us if you are interested in becoming one of the maintainers of any of the official adapters.
:::
### Editor integration
Adapters are strongly typed, and they rely on the single `Adapter` interface imported from `next-auth/adapters`.
When writing your own custom Adapter in plain JavaScript, note that you can use **JSDoc** to get helpful editor hints and auto-completion like so:
```js
/** @return { import("next-auth/adapters").Adapter } */
function MyAdapter() {
return {
// your adapter methods here
}
}
```
:::note
This will work in code editors with a strong TypeScript integration like VSCode or WebStorm. It might not work if you're using more lightweight editors like VIM or Atom.
:::

View File

@@ -1,65 +0,0 @@
---
id: pouchdb
title: PouchDB
---
# PouchDB
:::warning
This adapter is still experimental and does not work with NextAuth.js 4 or newer. If you would like to help out upgrading it, please [open a PR](https://github.com/nextauthjs/next-auth/tree/main/packages)
:::
This is the PouchDB Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
Depending on your architecture you can use PouchDB's http adapter to reach any database compliant with the CouchDB protocol (CouchDB, Cloudant, ...) or use any other PouchDB compatible adapter (leveldb, in-memory, ...)
## Getting Started
> **Prerequisites**: Your PouchDB instance MUST provide the `pouchdb-find` plugin since it is used internally by the adapter to build and manage indexes
1. Install `next-auth` and `@next-auth/pouchdb-adapter`
```bash npm2yarn2pnpm
npm install next-auth @next-auth/pouchdb-adapter
```
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { PouchDBAdapter } from "@next-auth/pouchdb-adapter"
import PouchDB from "pouchdb"
// Setup your PouchDB instance and database
PouchDB.plugin(require("pouchdb-adapter-leveldb")) // Any other adapter
.plugin(require("pouchdb-find")) // Don't forget the `pouchdb-find` plugin
const pouchdb = new PouchDB("auth_db", { adapter: "leveldb" })
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/providers/overview
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
],
adapter: PouchDBAdapter(pouchdb),
// ...
})
```
## Advanced
### Memory-First Caching Strategy
If you need to boost your authentication layer performance, you may use PouchDB's powerful sync features and various adapters, to build a memory-first caching strategy.
Use an in-memory PouchDB as your main authentication database, and synchronize it with any other persisted PouchDB. You may do a one way, one-off replication at startup from the persisted PouchDB into the in-memory PouchDB, then two-way, continuous, retriable sync.
This will most likely not increase performance much in a serverless environment due to various reasons such as concurrency, function startup time increases, etc.
For more details, please see https://pouchdb.com/api.html#sync

View File

@@ -1,226 +0,0 @@
---
id: prisma
title: Prisma
---
# Prisma
To use this Adapter, you need to install Prisma Client, Prisma CLI, and the separate `@next-auth/prisma-adapter` package:
```bash npm2yarn2pnpm
npm install next-auth @prisma/client @next-auth/prisma-adapter
npm install prisma --save-dev
```
Create a file with your Prisma Client:
```typescript title="lib/prismadb.ts"
import { PrismaClient } from "@prisma/client"
declare global {
var prisma: PrismaClient | undefined
}
const client = globalThis.prisma || new PrismaClient()
if (process.env.NODE_ENV !== "production") globalThis.prisma = client
export default client
```
Configure your NextAuth.js to use the Prisma Adapter:
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { PrismaAdapter } from "@next-auth/prisma-adapter"
import prisma from "../../../lib/prismadb"
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
})
```
Schema for the Prisma Adapter (`@next-auth/prisma-adapter`)
## Setup
### Create the Prisma schema
You need to use at least Prisma 2.26.0. Create a schema file in `prisma/schema.prisma` similar to this one:
> This schema is adapted for use in Prisma and based upon our main [schema](/adapters/models)
```json title="schema.prisma"
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
shadowDatabaseUrl = env("SHADOW_DATABASE_URL") // Only needed when using a cloud provider that doesn't support the creation of new databases, like Heroku. Learn more: https://pris.ly/migrate-shadow
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["referentialActions"] // You won't need this in Prisma 3.X or higher.
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
```
:::note
When using the MySQL connector for Prisma, the [Prisma `String` type](https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string) gets mapped to `varchar(191)` which may not be long enough to store fields such as `id_token` in the `Account` model. This can be avoided by explicitly using the `Text` type with `@db.Text`.
:::
### Create the database schema with Prisma Migrate
**Warning:** Make sure to back up your database before running using Prisma Migrate.
```
npx prisma migrate dev
```
This will create an SQL migration file and execute it.
Note that you will need to specify your database connection string in the environment variable `DATABASE_URL`. You can do this by setting it in a `.env` file at the root of your project.
To learn more about [Prisma Migrate](https://www.prisma.io/migrate), check out the [Migrate docs](https://www.prisma.io/docs/concepts/components/prisma-migrate).
### Generate Client
Once you have saved your schema, use the Prisma CLI to generate the Prisma Client:
```
npx prisma generate
```
To configure your database to use the new schema (i.e. create tables and columns) use the `prisma migrate` command:
```
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, 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
If mixed snake_case and camelCase column names is an issue for you and/or your underlying database system, we recommend using Prisma's `@map()`([see the documentation here](https://www.prisma.io/docs/concepts/components/prisma-schema/names-in-underlying-database)) feature to change the field names. This won't affect NextAuth.js, but will allow you to customize the column names to whichever naming convention you wish.
For example, moving to `snake_case` and plural table names.
```json title="schema.prisma"
model Account {
id String @id @default(cuid())
userId String @map("user_id")
type String
provider String
providerAccountId String @map("provider_account_id")
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@map("accounts")
}
model Session {
id String @id @default(cuid())
sessionToken String @unique @map("session_token")
userId String @map("user_id")
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("sessions")
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime? @map("email_verified")
image String?
accounts Account[]
sessions Session[]
@@map("users")
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
@@map("verificationtokens")
}
```

View File

@@ -1,88 +0,0 @@
---
id: sequelize
title: Sequelize
---
# Sequelize
This is the Sequelize Adapter for [`next-auth`](https://next-auth.js.org).
## Getting Started
1. Install the necessary packages
```bash npm2yarn2pnpm
npm install next-auth @next-auth/sequelize-adapter sequelize
```
:::warning
You'll also have to manually install [the driver for your database](https://sequelize.org/master/manual/getting-started.html) of choice.
:::
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import SequelizeAdapter from "@next-auth/sequelize-adapter"
import { Sequelize } from "sequelize"
// https://sequelize.org/master/manual/getting-started.html#connecting-to-a-database
const sequelize = new Sequelize("yourconnectionstring")
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/providers/overview
providers: [],
adapter: SequelizeAdapter(sequelize),
})
```
## Updating the database schema
By default, the sequelize adapter will not create tables in your database. In production, best practice is to create the [required tables](https://next-auth.js.org/adapters/models) in your database via [migrations](https://sequelize.org/master/manual/migrations.html). In development, you are able to call [`sequelize.sync()`](https://sequelize.org/master/manual/model-basics.html#model-synchronization) to have sequelize create the necessary tables, foreign keys and indexes:
> This schema is adapted for use in Sequelize and based upon our main [schema](/adapters/models)
```js
import NextAuth from "next-auth"
import SequelizeAdapter from "@next-auth/sequelize-adapter"
import Sequelize from 'sequelize'
const sequelize = new Sequelize("sqlite::memory:")
const adapter = SequelizeAdapter(sequelize)
// Calling sync() is not recommended in production
sequelize.sync()
export default NextAuth({
...
adapter
...
})
```
## Using custom models
Sequelize models are option to customization like so:
```js
import NextAuth from "next-auth"
import SequelizeAdapter, { models } from "@next-auth/sequelize-adapter"
import Sequelize, { DataTypes } from "sequelize"
const sequelize = new Sequelize("sqlite::memory:")
export default NextAuth({
// https://next-auth.js.org/providers/overview
providers: [],
adapter: SequelizeAdapter(sequelize, {
models: {
User: sequelize.define("user", {
...models.User,
phoneNumber: DataTypes.STRING,
}),
},
}),
})
```

View File

@@ -1,309 +0,0 @@
---
id: supabase
title: Supabase
---
# Supabase
This is the Supabase Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
:::note
This adapter is developed by the community and not officially maintained or supported by Supabase. It uses the Supabase Database to store user and session data in a separate `next_auth` schema. It is a standalone Auth server that does not interface with Supabase Auth and therefore provides a different feature set.
If youre looking for an officially maintained Auth server with additional features like [built-in email server](https://supabase.com/docs/guides/auth/auth-email#configure-email-settings?utm_source=next-auth-docs&medium=referral&campaign=next-auth), [phone auth](https://supabase.com/docs/guides/auth/auth-twilio?utm_source=next-auth-docs&medium=referral&campaign=next-auth), and [Multi Factor Authentication (MFA / 2FA)](https://supabase.com/contact/mfa?utm_source=next-auth-docs&medium=referral&campaign=next-auth), please use [Supabase Auth](https://supabase.com/auth) with the [Auth Helpers for Next.js](https://supabase.com/docs/guides/auth/auth-helpers/nextjs?utm_source=next-auth-docs&medium=referral&campaign=next-auth).
:::
## Getting Started
1. Install `@supabase/supabase-js`, `next-auth` and `@next-auth/supabase-adapter`.
```bash npm2yarn2pnpm
npm install @supabase/supabase-js next-auth @next-auth/supabase-adapter
```
2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
```js title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { SupabaseAdapter } from "@next-auth/supabase-adapter"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [...],
adapter: SupabaseAdapter({
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
}),
// ...
})
```
## Setup
### Create the `next_auth` schema in Supabase
Setup your database as described in our main [schema](/adapters/models), by copying the SQL schema below in the Supabase [SQL Editor](https://app.supabase.com/project/_/sql).
Alternatively you can select the NextAuth Quickstart card on the [SQL Editor page](https://app.supabase.com/project/_/sql), or [create a migration with the Supabase CLI](https://supabase.com/docs/guides/cli/local-development#database-migrations?utm_source=next-auth-docs&medium=referral&campaign=next-auth).
```sql
--
-- Name: next_auth; Type: SCHEMA;
--
CREATE SCHEMA next_auth;
GRANT USAGE ON SCHEMA next_auth TO service_role;
GRANT ALL ON SCHEMA next_auth TO postgres;
--
-- Create users table
--
CREATE TABLE IF NOT EXISTS next_auth.users
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name text,
email text,
"emailVerified" timestamp with time zone,
image text,
CONSTRAINT users_pkey PRIMARY KEY (id),
CONSTRAINT email_unique UNIQUE (email)
);
GRANT ALL ON TABLE next_auth.users TO postgres;
GRANT ALL ON TABLE next_auth.users TO service_role;
--- uid() function to be used in RLS policies
CREATE FUNCTION next_auth.uid() RETURNS uuid
LANGUAGE sql STABLE
AS $$
select
coalesce(
nullif(current_setting('request.jwt.claim.sub', true), ''),
(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
)::uuid
$$;
--
-- Create sessions table
--
CREATE TABLE IF NOT EXISTS next_auth.sessions
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
expires timestamp with time zone NOT NULL,
"sessionToken" text NOT NULL,
"userId" uuid,
CONSTRAINT sessions_pkey PRIMARY KEY (id),
CONSTRAINT sessionToken_unique UNIQUE ("sessionToken"),
CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId")
REFERENCES next_auth.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
);
GRANT ALL ON TABLE next_auth.sessions TO postgres;
GRANT ALL ON TABLE next_auth.sessions TO service_role;
--
-- Create accounts table
--
CREATE TABLE IF NOT EXISTS next_auth.accounts
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
type text NOT NULL,
provider text NOT NULL,
"providerAccountId" text NOT NULL,
refresh_token text,
access_token text,
expires_at bigint,
token_type text,
scope text,
id_token text,
session_state text,
oauth_token_secret text,
oauth_token text,
"userId" uuid,
CONSTRAINT accounts_pkey PRIMARY KEY (id),
CONSTRAINT provider_unique UNIQUE (provider, "providerAccountId"),
CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId")
REFERENCES next_auth.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
);
GRANT ALL ON TABLE next_auth.accounts TO postgres;
GRANT ALL ON TABLE next_auth.accounts TO service_role;
--
-- Create verification_tokens table
--
CREATE TABLE IF NOT EXISTS next_auth.verification_tokens
(
identifier text,
token text,
expires timestamp with time zone NOT NULL,
CONSTRAINT verification_tokens_pkey PRIMARY KEY (token),
CONSTRAINT token_unique UNIQUE (token),
CONSTRAINT token_identifier_unique UNIQUE (token, identifier)
);
GRANT ALL ON TABLE next_auth.verification_tokens TO postgres;
GRANT ALL ON TABLE next_auth.verification_tokens TO service_role;
```
### Expose the `next_auth` schema in Supabase
Expose the `next_auth` schema via the Serverless API in the [API settings](https://app.supabase.com/project/_/settings/api) by adding `next_auth` to the "Exposed schemas" list.
When developing locally add `next_auth` to the `schemas` array in the `config.toml` file in the `supabase` folder that was generated by the [Supabase CLI](https://supabase.com/docs/guides/cli/local-development#initialize-your-project?utm_source=next-auth-docs&medium=referral&campaign=next-auth).
## Enabling Row Level Security (RLS)
Postgres provides a powerful feature called [Row Level Security (RLS)](https://supabase.com/docs/guides/auth/row-level-security?utm_source=next-auth-docs&medium=referral&campaign=next-auth) to limit access to data.
This works by sending a signed JWT to your [Supabase Serverless API](https://supabase.com/docs/guides/api?utm_source=next-auth-docs&medium=referral&campaign=next-auth). There is two steps to make this work with NextAuth:
### 1. Generate the Supabase `access_token` JWT in the session callback
To sign the JWT use the `jsonwebtoken` package:
```bash npm2yarn2pnpm
npm install jsonwebtoken
```
Using the [NexthAuth Session callback](https://next-auth.js.org/configuration/callbacks#session-callback) create the Supabase `access_token` and append it to the `session` object.
To sign the JWT use the Supabase JWT secret which can be found in the [API settings](https://app.supabase.com/project/_/settings/api)
```js title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { SupabaseAdapter } from "@next-auth/supabase-adapter"
import jwt from "jsonwebtoken"
// For more information on each option (and a full list of options) go to
// https://next-auth.js.org/configuration/options
export default NextAuth({
// https://next-auth.js.org/configuration/providers
providers: [...],
adapter: SupabaseAdapter({
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
}),
callbacks: {
async session({ session, user }) {
const signingSecret = process.env.SUPABASE_JWT_SECRET
if (signingSecret) {
const payload = {
aud: "authenticated",
exp: Math.floor(new Date(session.expires).getTime() / 1000),
sub: user.id,
email: user.email,
role: "authenticated",
}
session.supabaseAccessToken = jwt.sign(payload, signingSecret)
}
return session
},
},
// ...
})
```
### 2. Inject the Supabase `access_token` JWT into the Supabase Client
For example, given the following public schema:
```sql
/**
* USERS
* Note: This table contains user data. Users should only be able to view and update their own data.
*/
create table users (
-- UUID from next_auth.users
id uuid not null primary key,
name text,
email text,
image text,
constraint "users_id_fkey" foreign key ("id")
references next_auth.users (id) match simple
on update no action
on delete cascade -- if user is deleted in NextAuth they will also be deleted in our public table.
);
alter table users enable row level security;
create policy "Can view own user data." on users for select using (next_auth.uid() = id);
create policy "Can update own user data." on users for update using (next_auth.uid() = id);
/**
* This trigger automatically creates a user entry when a new user signs up via NextAuth.
*/
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.users (id, name, email, image)
values (new.id, new.name, new.email, new.image);
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on next_auth.users
for each row execute procedure public.handle_new_user();
```
The `supabaseAccessToken` is now available on the `session` object and can be passed to the supabase-js client. This works in any environment: client-side, server-side (API routes, SSR), as well as in middleware edge functions!
```js
// ...
// Use `useSession()` or `unstable_getServerSession()` to get the NextAuth session.
const { supabaseAccessToken } = session
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
global: {
headers: {
Authorization: `Bearer ${supabaseAccessToken}`,
},
},
}
)
// Now you can query with RLS enabled.
const { data, error } = await supabase.from("users").select("*")
```
## Usage with TypeScript
You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion.
Creating a new supabase client object:
```tsx
import { createClient } from "@supabase/supabase-js"
import { Database } from "../database.types"
const supabase = createClient<Database>()
```
### Extend the session type with the `supabaseAccessToken`
In order to extend the `session` object with the `supabaseAccessToken` we need to extend the `session` interface in a `types/next-auth.d.ts` file:
```ts title="types/next-auth.d.ts"
import NextAuth, { DefaultSession } from "next-auth"
declare module "next-auth" {
/**
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
*/
interface Session {
// A JWT which can be used as Authorization header with supabase-js for RLS.
supabaseAccessToken?: string
user: {
/** The user's postal address. */
address: string
} & DefaultSession["user"]
}
}
```

View File

@@ -1,237 +0,0 @@
---
id: typeorm
title: TypeORM
---
# TypeORM
This Adapter is used to support SQL-flavored databases (like SQLite, MySQL, MSSQL, MariaDB, CockroachDB, etc.) through [TypeORM](https://typeorm.io).
:::note
If you previously used this Adapter with MongoDB, check out the [MongoDB Adapter](/adapters/mongodb) instead.
:::
:::note
In the future, we might split up this adapter to support single flavors of SQL for easier maintenance and reduced bundle size.
:::
## Usage
:::warning
[`typeorm`](https://github.com/typeorm/typeorm) is still in active development and has not yet published a stable release. Because of this, you can expect breaking changes in minor versions. This adapter expects `typeorm@0.3.7` and is not validated against previous or future releases.
:::
To use this Adapter, you need to install the following packages:
```bash npm2yarn2pnpm
npm install next-auth @next-auth/typeorm-legacy-adapter typeorm
```
Configure your NextAuth.js to use the TypeORM Adapter:
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
export default NextAuth({
adapter: TypeORMLegacyAdapter("yourconnectionstring"),
...
})
```
`TypeORMLegacyAdapter` takes either a connection string, or a [`DataSourceOptions`](https://github.com/typeorm/typeorm/blob/master/docs/data-source-options.md) object as its first parameter.
## Custom models
The TypeORM adapter uses [`Entity` classes](https://github.com/typeorm/typeorm/blob/master/docs/entities.md) to define the shape of your data.
If you want to override the default entities (for example to add a `role` field to your `UserEntity`), you will have to do the following:
> This schema is adapted for use in TypeORM and based upon our main [schema](/adapters/models)
1. Create a file containing your modified entities:
(The file below is based on the [default entities](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-typeorm-legacy/src/entities.ts))
```diff title="lib/entities.ts"
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToOne,
OneToMany,
ValueTransformer,
} from "typeorm"
const transformer: Record<"date" | "bigint", ValueTransformer> = {
date: {
from: (date: string | null) => date && new Date(parseInt(date, 10)),
to: (date?: Date) => date?.valueOf().toString(),
},
bigint: {
from: (bigInt: string | null) => bigInt && parseInt(bigInt, 10),
to: (bigInt?: number) => bigInt?.toString(),
},
}
@Entity({ name: "users" })
export class UserEntity {
@PrimaryGeneratedColumn("uuid")
id!: string
@Column({ type: "varchar", nullable: true })
name!: string | null
@Column({ type: "varchar", nullable: true, unique: true })
email!: string | null
@Column({ type: "varchar", nullable: true, transformer: transformer.date })
emailVerified!: string | null
@Column({ type: "varchar", nullable: true })
image!: string | null
+ @Column({ type: "varchar", nullable: true })
+ role!: string | null
@OneToMany(() => SessionEntity, (session) => session.userId)
sessions!: SessionEntity[]
@OneToMany(() => AccountEntity, (account) => account.userId)
accounts!: AccountEntity[]
}
@Entity({ name: "accounts" })
export class AccountEntity {
@PrimaryGeneratedColumn("uuid")
id!: string
@Column({ type: "uuid" })
userId!: string
@Column()
type!: string
@Column()
provider!: string
@Column()
providerAccountId!: string
@Column({ type: "varchar", nullable: true })
refresh_token!: string | null
@Column({ type: "varchar", nullable: true })
access_token!: string | null
@Column({
nullable: true,
type: "bigint",
transformer: transformer.bigint,
})
expires_at!: number | null
@Column({ type: "varchar", nullable: true })
token_type!: string | null
@Column({ type: "varchar", nullable: true })
scope!: string | null
@Column({ type: "varchar", nullable: true })
id_token!: string | null
@Column({ type: "varchar", nullable: true })
session_state!: string | null
@Column({ type: "varchar", nullable: true })
oauth_token_secret!: string | null
@Column({ type: "varchar", nullable: true })
oauth_token!: string | null
@ManyToOne(() => UserEntity, (user) => user.accounts, {
createForeignKeyConstraints: true,
})
user!: UserEntity
}
@Entity({ name: "sessions" })
export class SessionEntity {
@PrimaryGeneratedColumn("uuid")
id!: string
@Column({ unique: true })
sessionToken!: string
@Column({ type: "uuid" })
userId!: string
@Column({ transformer: transformer.date })
expires!: string
@ManyToOne(() => UserEntity, (user) => user.sessions)
user!: UserEntity
}
@Entity({ name: "verification_tokens" })
export class VerificationTokenEntity {
@PrimaryGeneratedColumn("uuid")
id!: string
@Column()
token!: string
@Column()
identifier!: string
@Column({ transformer: transformer.date })
expires!: string
}
```
2. Pass them to `TypeORMLegacyAdapter`
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
import * as entities from "lib/entities"
export default NextAuth({
adapter: TypeORMLegacyAdapter("yourconnectionstring", { entities }),
...
})
```
:::tip Synchronize your database ♻
The `synchronize: true` option in TypeORM will generate SQL that exactly matches the entities. This will automatically apply any changes it finds in the entity model. This is a useful option in development.
:::
:::warning Using synchronize in production
`synchronize: true` should not be enabled against production databases as it may cause data loss if the configured schema does not match the expected schema! We recommend that you synchronize/migrate your production database at build-time.
:::
## Naming Conventions
If mixed snake_case and camelCase column names are an issue for you and/or your underlying database system, we recommend using TypeORM's naming strategy feature to change the target field names. There is a package called `typeorm-naming-strategies` which includes a `snake_case` strategy which will translate the fields from how NextAuth.js expects them, to snake_case in the actual database.
For example, you can add the naming convention option to the connection object in your NextAuth config.
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
import { SnakeNamingStrategy } from 'typeorm-naming-strategies'
export default NextAuth({
adapter: TypeORMLegacyAdapter({
type: "mysql",
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
namingStrategy: new SnakeNamingStrategy()
}),
...
})
```

View File

@@ -1,69 +0,0 @@
---
id: upstash-redis
title: Upstash Redis
---
# Upstash Redis
To use this Adapter, you need to install `@upstash/redis` and `@next-auth/upstash-redis-adapter` package:
```bash npm2yarn2pnpm
npm install @upstash/redis @next-auth/upstash-redis-adapter
```
Configure your NextAuth.js to use the Upstash Redis Adapter:
```javascript title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { UpstashRedisAdapter } from "@next-auth/upstash-redis-adapter"
import { Redis } from "@upstash/redis"
const redis = new Redis({
url: process.env.UPSTASH_REDIS_URL,
token: process.env.UPSTASH_REDIS_TOKEN
})
export default NextAuth({
adapter: UpstashRedisAdapter(redis),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
})
```
## Using Multiple Apps with a Single Upstash Redis Instance
The Upstash free-tier allows for only one Redis instance. If you have multiple Next-Auth connected apps using this instance, you need different key prefixes for every app.
You can change the prefixes by passing an `options` object as the second argument to the adapter factory function.
The default values for this object are:
```js
const defaultOptions = {
baseKeyPrefix: "",
accountKeyPrefix: "user:account:",
accountByUserIdPrefix: "user:account:by-user-id:",
emailKeyPrefix: "user:email:",
sessionKeyPrefix: "user:session:",
sessionByUserIdKeyPrefix: "user:session:by-user-id:",
userKeyPrefix: "user:",
verificationTokenKeyPrefix: "user:token:",
}
```
Usually changing the `baseKeyPrefix` should be enough for this scenario, but for more custom setups, you can also change the prefixes of every single key.
Example:
```js
export default NextAuth({
...
adapter: UpstashRedisAdapter(redis, {baseKeyPrefix: "app2:"})
...
})
```

View File

@@ -1,242 +0,0 @@
---
id: xata
title: Xata
---
# Xata
This adapter allows using next-auth with Xata as a database to store users, sessions, and more. The preferred way to create a Xata project and use Xata databases is using the [Xata Command Line Interface (CLI)](https://docs.xata.io/cli/getting-started). The CLI allows generating a `XataClient` that will help you work with Xata in a safe way, and that this adapter depends on.
<!-- @todo add GIFs -->
## Getting Started
Let's first make sure we have everything installed and configured. We're going to need:
- next-auth + adapter
- the Xata CLI
- to configure the CLI
We can do this like so:
```bash npm2yarn2pnpm
# Install next-auth + adapter
npm install next-auth @next-auth/xata-adapter
# Install the Xata CLI globally if you don't already have it
npm install --location=global @xata.io/cli
# Login
xata auth login
```
Now that we're ready, let's create a new Xata project using our next-auth schema that the Xata adapter can work with. To do that, copy and paste this schema file into your project's directory:
```json title="schema.json"
{
"formatVersion": "",
"tables": [
{
"name": "nextauth_users",
"columns": [
{
"name": "email",
"type": "email"
},
{
"name": "emailVerified",
"type": "datetime"
},
{
"name": "name",
"type": "string"
},
{
"name": "image",
"type": "string"
}
]
},
{
"name": "nextauth_accounts",
"columns": [
{
"name": "user",
"type": "link",
"link": {
"table": "nextauth_users"
}
},
{
"name": "type",
"type": "string"
},
{
"name": "provider",
"type": "string"
},
{
"name": "providerAccountId",
"type": "string"
},
{
"name": "refresh_token",
"type": "string"
},
{
"name": "access_token",
"type": "string"
},
{
"name": "expires_at",
"type": "int"
},
{
"name": "token_type",
"type": "string"
},
{
"name": "scope",
"type": "string"
},
{
"name": "id_token",
"type": "text"
},
{
"name": "session_state",
"type": "string"
}
]
},
{
"name": "nextauth_verificationTokens",
"columns": [
{
"name": "identifier",
"type": "string"
},
{
"name": "token",
"type": "string"
},
{
"name": "expires",
"type": "datetime"
}
]
},
{
"name": "nextauth_users_accounts",
"columns": [
{
"name": "user",
"type": "link",
"link": {
"table": "nextauth_users"
}
},
{
"name": "account",
"type": "link",
"link": {
"table": "nextauth_accounts"
}
}
]
},
{
"name": "nextauth_users_sessions",
"columns": [
{
"name": "user",
"type": "link",
"link": {
"table": "nextauth_users"
}
},
{
"name": "session",
"type": "link",
"link": {
"table": "nextauth_sessions"
}
}
]
},
{
"name": "nextauth_sessions",
"columns": [
{
"name": "sessionToken",
"type": "string"
},
{
"name": "expires",
"type": "datetime"
},
{
"name": "user",
"type": "link",
"link": {
"table": "nextauth_users"
}
}
]
}
]
}
```
Now, run the following command:
```bash
xata init --schema=./path/to/your/schema.json
```
The CLI will walk you through a setup process where you choose a [workspace](https://docs.xata.io/concepts/workspaces) (kind of like a GitHub org or a Vercel team) and an appropriate database. We recommend using a fresh database for this, as we'll augment it with tables that next-auth needs.
Once you're done, you can continue using next-auth in your project as expected, like creating a `./pages/api/auth/[...nextauth]` route.
```typescript title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
const client = new XataClient()
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
})
```
Now to Xata-fy this route, let's add the Xata client and adapter:
```diff
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
+import { XataAdapter } from "@next-auth/xata-adapter"
+import { XataClient } from "../../../xata" // or wherever you've chosen to create the client
+const client = new XataClient()
export default NextAuth({
+ adapter: XataAdapter(client),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
],
})
```
This fully sets up your next-auth site to work with Xata.
## Contributing
This is an open-source project created by humans, and as such, might have a few issues. If you experience any of these, we recommend [opening issues](https://github.com/nextauthjs/next-auth/issues/new?assignees=&labels=triage&template=1_bug_framework.yml&title=Issue%20on%20Xata%20adapter&description=I%20experienced%20this%20issue:\n##%20Reproduction%20Steps:\n\n-) that can help us solve problems and build reliable software.

View File

@@ -107,7 +107,7 @@ The redirect callback may be invoked more than once in the same flow.
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 [encrypted](/configuration/options#jwt), and it is stored in a cookie.
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `unstable_getServerSession()`, `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.
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `getServerSession()`, `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.
- As with database persisted session expiry times, token expiry time is extended whenever a session is active.
- The arguments _user_, _account_, _profile_ and _isNewUser_ are only passed the first time this callback is called on a new session, after the user signs in. In subsequent calls, only `token` will be available.
@@ -139,8 +139,8 @@ The session callback is called whenever a session is checked. By default, **only
e.g. `getSession()`, `useSession()`, `/api/auth/session`
- When using database sessions, the User object is passed as an argument.
- When using JSON Web Tokens for sessions, the JWT payload is provided instead.
- When using database sessions, the User (`user`) object is passed as an argument.
- When using JSON Web Tokens for sessions, the JWT payload (`token`) is provided instead.
```js title="pages/api/auth/[...nextauth].js"
...

View File

@@ -3,7 +3,7 @@ id: databases
title: Databases
---
NextAuth.js offers multiple database adapters. Check out [the overview](/adapters/overview).
NextAuth.js offers multiple database adapters. Check out [the overview](https://authjs.dev/reference/adapters).
> As of **v4** NextAuth.js no longer ships with an adapter included by default. If you would like to persist any information, you need to install one of the many available adapters yourself. See the individual adapter documentation pages for more details.
@@ -13,4 +13,4 @@ To learn more about databases in NextAuth.js and how they are used, check out [d
## How to use a database
See the [documentation for adapters](/adapters/overview) for more information on advanced configuration, including how to use NextAuth.js with other databases using a [custom adapter](/tutorials/creating-a-database-adapter).
See the [documentation for adapters](https://authjs.dev/reference/adapters) for more information on advanced configuration, including how to use NextAuth.js with other databases using a [custom adapter](/tutorials/creating-a-database-adapter).

View File

@@ -3,17 +3,23 @@ id: initialization
title: Initialization
---
The main entry point of NextAuth.js is the `NextAuth` method that you import from `next-auth`. It handles different types of requests, as defined in the [REST API](../getting-started/rest-api.md) section.
:::info
NextAuth.js cannot use the run [Edge Runtime](https://nextjs.org/docs/api-reference/edge-runtime) for initialization. The upcoming [`@auth/nextjs` library](https://authjs.dev/reference/nextjs) (which will replace `next-auth`) on the other hand will be fully compatible.
:::
You can initialize NextAuth.js in a few different ways.
## Simple initialization
### API Routes (`pages`)
In Next.js, you can define an API route that will catch all requests that begin with a certain path. Conveniently, this is called [Catch all API routes](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes).
When you define a `/pages/api/auth/[...nextauth]` JS/TS file, you instruct NextAuth.js that every API request beginning with `/api/auth/*` should be handled by the code written in the `[...nextauth]` file.
Depending on your use case, you can initialize NextAuth.js in two different ways:
## Simple initialization
In most cases, you won't need to worry about what `NextAuth.js` does, and you will get by just fine with the following initialization:
```ts title="/pages/api/auth/[...nextauth].js"
```ts title="/pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
export default NextAuth({
@@ -25,9 +31,37 @@ Here, you only need to pass your [options](/configuration/options) to `NextAuth`
This is the preferred initialization in tutorials/other parts of the documentation, as it simplifies the code and reduces potential errors in the authentication flow.
### Route Handlers (`app/`)
[Next.js 13.2](https://nextjs.org/blog/next-13-2#custom-route-handlers) introduced [Route Handlers](https://beta.nextjs.org/docs/routing/route-handlers), the preferred way to handle REST-like requests in App Router (`app/`).
You can initialize NextAuth.js with a Route Handler too, very similar to API Routes.
```ts title="/app/api/auth/[...nextauth]/route.ts"
import NextAuth from "next-auth"
const handler = NextAuth({
...
})
export { handler as GET, handler as POST }
```
Internally, NextAuth.js detects that it is being initialized in a Route Handler (by understanding that it is passed a Web [`Request` instance](https://developer.mozilla.org/en-US/docs/Web/API/Request)), and will return a handler that returns a [`Response` instance](https://developer.mozilla.org/en-US/docs/Web/API/Response). A Route Handler file expects you to export some named handler functions that handle a request and return a response. NextAuth.js needs the `GET` and `POST` handlers to function properly, so we export those two.
:::info
Technically, in a Route Handler, the `api/` prefix is not necessary, but we decided to keep it required for an easier migration.
:::
## Advanced initialization
If you have a specific use case and need to make NextAuth.js do something slightly different than what it is designed for, keep in mind, the `[...nextauth].js` config file is still just **a regular [API Route](https://nextjs.org/docs/api-routes/introduction)** at the end of the day.
:::info
The following describes the advanced initialization with API Routes, but everything will apply similarily when using [Route Handlers](https://beta.nextjs.org/docs/routing/route-handlers) too.
Instead, `NextAuth` will receive the first two arguments of a Route Handler, and the third argument will be the [auth options](../configuration/options.md)
:::
If you have a specific use case and need to make NextAuth.js do something slightly different than what it is designed for, keep in mind, the `[...nextauth].ts` config file is just **a regular [API Route](https://nextjs.org/docs/api-routes/introduction)**.
That said, you can initialize NextAuth.js like this:
@@ -91,7 +125,7 @@ export default async function auth(req: NextApiRequest, res: NextApiResponse) {
A practical example could be to not show a certain provider on the default sign-in page, but still be able to sign in with it. (The idea is taken from [this discussion](https://github.com/nextauthjs/next-auth/discussions/3133)):
```js title="/pages/api/auth/[...nextauth].js"
```js title="/pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
import GoogleProvider from "next-auth/providers/google"

View File

@@ -1,20 +1,35 @@
# Next.js
## `unstable_getServerSession`
## `getServerSession`
:::warning
This feature is experimental and may be removed or changed in the future.
:::tip
You can create a helper function so you don't need to pass `authOptions` around:
```ts title=auth.ts
import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from "next"
import type { NextAuthOptions } from "next-auth"
import { getServerSession } from "next-auth"
// You'll need to import and pass this
// to `NextAuth` in `app/api/auth/[...nextauth]/route.ts`
export const config = {
providers: [], // rest of your config
} satisfies NextAuthOptions
// Use it in server contexts
export function auth(...args: [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]] | [NextApiRequest, NextApiResponse] | []) {
return getServerSession(...args, config)
}
```
:::
When calling from server-side i.e. in API routes or in `getServerSideProps`, we recommend using this function instead of `getSession` to retrieve the `session` object. This method is especially useful when you are using NextAuth.js with a database. This method can _drastically_ reduce response time when used over `getSession` server-side, due to avoiding an extra `fetch` to an API Route (this is generally [not recommended in Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops-or-api-routes)). In addition, `unstable_getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
When calling from the server-side i.e. in Route Handlers, React Server Components, API routes or in `getServerSideProps`, we recommend using this function instead of `getSession` to retrieve the `session` object. This method is especially useful when you are using NextAuth.js with a database. This method can _drastically_ reduce response time when used over `getSession` on server-side, due to avoiding an extra `fetch` to an API Route (this is generally [not recommended in Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops-or-api-routes)). In addition, `getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
Otherwise, if you only want to get the session token, see [`getToken`](/tutorials/securing-pages-and-api-routes#using-gettoken).
`unstable_getServerSession` requires passing the same object you would pass to `NextAuth` when initializing NextAuth.js. To do so, you can export your NextAuth.js options in the following way:
`getServerSession` requires passing the same object you would pass to `NextAuth` when initializing NextAuth.js. To do so, you can export your NextAuth.js options in the following way:
In `[...nextauth].ts`:
```ts
import { NextAuth } from 'next-auth'
import NextAuth from 'next-auth'
import type { NextAuthOptions } from 'next-auth'
export const authOptions: NextAuthOptions = {
@@ -27,10 +42,10 @@ export default NextAuth(authOptions);
### In `getServerSideProps`:
```js
import { authOptions } from 'pages/api/auth/[...nextauth]'
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(context.req, context.res, authOptions)
const session = await getServerSession(context.req, context.res, authOptions)
if (!session) {
return {
@@ -52,11 +67,11 @@ export async function getServerSideProps(context) {
### In API Routes:
```js
import { authOptions } from 'pages/api/auth/[...nextauth]'
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
export async function handler(req, res) {
const session = await unstable_getServerSession(req, res, authOptions)
export default async function handler(req, res) {
const session = await getServerSession(req, res, authOptions)
if (!session) {
res.status(401).json({ message: "You must be logged in." });
@@ -69,24 +84,33 @@ export async function handler(req, res) {
}
```
### In `app/` directory:
### In App Router:
You can also use `unstable_getServerSession` in Next.js' server components:
You can also use `getServerSession` in Next.js' server components:
```tsx
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "pages/api/auth/[...nextauth]"
export default async function Page() {
const session = await unstable_getServerSession(authOptions)
const session = await getServerSession(authOptions)
return <pre>{JSON.stringify(session, null, 2)}</pre>
}
```
:::warning
Currently, the underlying Next.js `cookies()` method does [only provides read access](https://beta.nextjs.org/docs/api-reference/cookies) to the request cookies. This means that the `expires` value is stripped away from `session` in Server Components. Furthermore, there is a hard expiry on sessions, after which the user will be required to sign in again. (The default expiry is 30 days).
Currently, the underlying Next.js `cookies()` method [only provides read access](https://beta.nextjs.org/docs/api-reference/cookies) to the request cookies. This means that the `expires` value is stripped away from `session` in Server Components. Furthermore, there is a hard expiry on sessions, after which the user will be required to sign in again. (The default expiry is 30 days).
:::
### Caching
Note that using this function implies personalized data and that you should not store pages or APIs using this in a [public cache](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control). For example a host like [Vercel](https://vercel.com/docs/concepts/functions/serverless-functions/edge-caching) will implicitly prevent you from caching publicly due to the `set-cookie` header set by this function.
## `unstable_getServerSession`
This method was renamed to `getServerSession`. See the documentation above.
## Middleware
You can use a Next.js Middleware with NextAuth.js to protect your site.
@@ -154,22 +178,27 @@ Callbacks are asynchronous functions you can use to control what happens when an
#### Description
Specify URLs to be used if you want to create custom sign in, and error pages. Pages specified will override the corresponding built-in page.
Specify URLs to be used if you want to create custom sign-in and error pages. The pages specified will override the corresponding built-in page.
:::note
This should match the `pages` configuration that's found in `[...nextauth].ts`.
:::info
The `pages` configuration should match the same configuration in `[...nextauth].ts`. This is so that the `next-auth` Middleware is aware of your custom pages, so it won't end up redirecting to itself when an unauthenticated condition is met.
:::
#### Example (default value)
```js
pages: {
signIn: '/api/auth/signin',
error: '/api/auth/error',
}
import { withAuth } from "next-auth/middleware"
export default withAuth({
// Matches the pages config in `[...nextauth]`
pages: {
signIn: '/login',
error: '/error',
}
})
```
See the documentation for the [pages option](/configuration/pages) for more information.
For more information, see the documentation for the [pages option](/configuration/pages).
---
@@ -179,7 +208,7 @@ See the documentation for the [pages option](/configuration/pages) for more info
#### Description
The same `secret` used in the [NextAuth.js config](/configuration/options#options).
The same `secret` is used in the [NextAuth.js config](/configuration/options#options).
#### Example (default value)
@@ -225,7 +254,6 @@ The `middleware` function will only be invoked if the `authorized` callback retu
If you have a custom jwt decode method set in `[...nextauth].ts`, you must also pass the same `decode` method to `withAuth` in order to read the custom-signed JWT correctly. You may want to extract the encode/decode logic to a separate function for consistency.
``
```ts title="/api/auth/[...nextauth].ts"
import type { NextAuthOptions } from "next-auth"
import NextAuth from "next-auth"
@@ -253,7 +281,7 @@ import withAuth from "next-auth/middleware"
import { authOptions } from "pages/api/auth/[...nextauth]";
export default withAuth({
jwt: { decode: authOptions.jwt },
jwt: { decode: authOptions.jwt?.decode },
callbacks: {
authorized: ({ token }) => !!token,
},

View File

@@ -27,7 +27,7 @@ Using [System Environment Variables](https://vercel.com/docs/concepts/projects/e
### NEXTAUTH_SECRET
Used to encrypt the NextAuth.js JWT, and to hash [email verification tokens](/adapters/models#verification-token). This is the default value for the `secret` option in [NextAuth](/configuration/options#secret) and [Middleware](/configuration/nextjs#secret).
Used to encrypt the NextAuth.js JWT, and to hash [email verification tokens](https://authjs.dev/reference/adapters#verification-token). This is the default value for the `secret` option in [NextAuth](/configuration/options#secret) and [Middleware](/configuration/nextjs#secret).
### NEXTAUTH_URL_INTERNAL
@@ -310,7 +310,7 @@ events: {
#### Description
By default NextAuth.js does not include an adapter any longer. If you would like to persist user / account data, please install one of the many available adapters. More information can be found in the [adapter documentation](/adapters/overview).
By default NextAuth.js does not include an adapter any longer. If you would like to persist user / account data, please install one of the many available adapters. More information can be found in the [adapter documentation](https://authjs.dev/reference/adapters).
---

View File

@@ -77,10 +77,13 @@ In addition, you can define a `theme.brandColor` to define a custom accent color
In order to get the available authentication providers and the URLs to use for them, you can make a request to the API endpoint `/api/auth/providers`:
```jsx title="pages/auth/signin.js"
```tsx title="pages/auth/signin.tsx"
import type { GetServerSidePropsContext, InferGetServerSidePropsType } from "next";
import { getProviders, signIn } from "next-auth/react"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../api/auth/[...nextauth]";
export default function SignIn({ providers }) {
export default function SignIn({ providers }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<>
{Object.values(providers).map((provider) => (
@@ -94,10 +97,20 @@ export default function SignIn({ providers }) {
)
}
export async function getServerSideProps(context) {
const providers = await getProviders()
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await getServerSession(context.req, context.res, authOptions);
// If the user is already logged in, redirect.
// Note: Make sure not to redirect to the same page
// To avoid an infinite loop!
if (session) {
return { redirect: { destination: "/" } };
}
const providers = await getProviders();
return {
props: { providers },
props: { providers: providers ?? [] },
}
}
```
@@ -108,10 +121,11 @@ There is another, more fully styled example signin page available [here](https:/
If you create a custom sign in form for email sign in, you will need to submit both fields for the **email** address and **csrfToken** from **/api/auth/csrf** in a POST request to **/api/auth/signin/email**.
```jsx title="pages/auth/email-signin.js"
```tsx title="pages/auth/email-signin.tsx"
import type { GetServerSidePropsContext, InferGetServerSidePropsType } from "next";
import { getCsrfToken } from "next-auth/react"
export default function SignIn({ csrfToken }) {
export default function SignIn({ csrfToken }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<form method="post" action="/api/auth/signin/email">
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
@@ -124,7 +138,7 @@ export default function SignIn({ csrfToken }) {
)
}
export async function getServerSideProps(context) {
export async function getServerSideProps(context: GetServerSidePropsContext) {
const csrfToken = await getCsrfToken(context)
return {
props: { csrfToken },
@@ -134,7 +148,7 @@ export async function getServerSideProps(context) {
You can also use the `signIn()` function which will handle obtaining the CSRF token for you:
```js
```ts
signIn("email", { email: "jsmith@example.com" })
```
@@ -142,10 +156,11 @@ signIn("email", { email: "jsmith@example.com" })
If you create a sign in form for credentials based authentication, you will need to pass a **csrfToken** from **/api/auth/csrf** in a POST request to **/api/auth/callback/credentials**.
```jsx title="pages/auth/credentials-signin.js"
```tsx title="pages/auth/credentials-signin.tsx"
import type { GetServerSidePropsContext, InferGetServerSidePropsType } from "next";
import { getCsrfToken } from "next-auth/react"
export default function SignIn({ csrfToken }) {
export default function SignIn({ csrfToken }: InferGetServerSidePropsType<typeof getServerSideProps>) {
return (
<form method="post" action="/api/auth/callback/credentials">
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
@@ -162,7 +177,7 @@ export default function SignIn({ csrfToken }) {
)
}
export async function getServerSideProps(context) {
export async function getServerSideProps(context: GetServerSidePropsContext) {
return {
props: {
csrfToken: await getCsrfToken(context),
@@ -173,7 +188,7 @@ export async function getServerSideProps(context) {
You can also use the `signIn()` function which will handle obtaining the CSRF token for you:
```js
```ts
signIn("credentials", { username: "jsmith", password: "1234" })
```

View File

@@ -22,7 +22,7 @@ providers: [
// You can pass any HTML attribute to the <input> tag through the object.
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
password: { label: "Password", type: "password" }
password: { label: "Password", type: "password" }
},
async authorize(credentials, req) {
// You need to provide your own logic here that takes the credentials

View File

@@ -3,6 +3,12 @@ id: email
title: Email
---
### Install nodemailer
```bash npm2yarn2pnpm
npm install nodemailer
```
### How to
The Email provider sends "magic links" via email that the user can click on to sign in.
@@ -35,10 +41,10 @@ The email provider requires a database, it cannot be used without one.
| Name | Description | Type | Required |
| :---------------------: | :---------------------------------------------------------------------------------: | :------------------------------: | :------: |
| id | Unique ID for the provider | `string` | Yes |
| name | Descriptive name for the provider | `string` | Yes |
| type | Type of provider, in this case `email` | `"email"` | Yes |
| server | Path or object pointing to the email server | `string` or `Object` | Yes |
| sendVerificationRequest | Callback to execute when a verification request is sent | `(params) => Promise<undefined>` | Yes |
| id | Unique ID for the provider | `string` | No |
| name | Descriptive name for the provider | `string` | No |
| type | Type of provider, in this case `email` | `"email"` | No |
| server | Path or object pointing to the email server | `string` or `Object` | No |
| sendVerificationRequest | Callback to execute to send a verification request, default uses nodemailer | `(params) => Promise<undefined>` | No |
| from | The email address from which emails are sent, default: "<no-reply@example.com>" | `string` | No |
| maxAge | How long until the e-mail can be used to log the user in seconds. Defaults to 1 day | `number` | No |

View File

@@ -40,7 +40,7 @@ sequenceDiagram
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"
Auth Server (Github)->>App Server: GET<br/>"api/auth/callback/github?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
@@ -424,17 +424,3 @@ GoogleProvider({
allowDangerousEmailAccountLinking: true,
})
```
### Adding a new built-in provider
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily!
You only need to add three changes:
1. Add your config: [`src/providers/{provider}.ts`](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers)<br />
- Make sure you use a named default export, like this: `export default function YourProvider`
- Add two SVG's of the provider logo, like `google-dark.svg` (dark mode) and `google.svg` (light mode), to the `/packages/next-auth/provider-logos/` directory as well as the styling config to the provider config object. See existing provider for example
2. Add provider documentation: [`/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/docs/docs/providers)
3. Add the new provider name to the `Provider type` dropdown options in [`the provider issue template`](<[http](https://github.com/nextauthjs/next-auth/edit/main/.github/ISSUE_TEMPLATE/2_bug_provider.yml)>)
That's it! 🎉 Others will be able to discover and use this provider much more easily now!

View File

@@ -18,8 +18,8 @@ See below for more detailed provider settings.
1. Make sure to expose the Vercel [System Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables#system-environment-variables) in your project settings.
2. Create a `NEXTAUTH_SECRET` environment variable for all environments.
a. You can use `openssl rand -base64 32` or https://generate-secret.vercel.app/32 to generate a random value.
b. You **do not** need the `NEXTAUTH_URL` environment variable in Vercel.
- You can use `openssl rand -base64 32` or https://generate-secret.vercel.app/32 to generate a random value.
- You **do not** need the `NEXTAUTH_URL` environment variable in Vercel.
3. Add your provider's client ID and client secret to environment variables. _(Skip this step if not using an [OAuth Provider](/configuration/providers/oauth))_
4. Deploy!
@@ -79,7 +79,7 @@ export default NextAuth({
#### Using the branch based preview URL
Preview deployments at Vercel are often available via multiple URLs. For example, PR's merged to `master` or `main`, will be available the commit and PR specific preview URLs, but also the branch specific preview URLs. This branch specific URL will obviously not change as long as you work with that same branch. Therefore, you could add to your OAuth provider your `{project}-git-main-{user}.vercel.app` preview URL. As this will stay constant for that branch, you can reuse that preview deployment / URL for testing any authentication related deployments.
Preview deployments at Vercel are often available via multiple URLs. For example, PR's merged to `master` or `main`, will be available via commit and PR specific preview URLs, but also the branch specific preview URLs. This branch specific URL will obviously not change as long as you work with that same branch. Therefore, you could add to your OAuth provider your `{project}-git-main-{user}.vercel.app` preview URL. As this will stay constant for that branch, you can reuse that preview deployment / URL for testing any authentication related deployments.
## Netlify

View File

@@ -21,7 +21,7 @@ This error occurs when the `SessionProvider` Context has a problem fetching sess
#### CLIENT_FETCH_ERROR
If you see `CLIENT_FETCH_ERROR` make sure you have configured the `NEXTAUTH_URL` environment variable.
This can happen for multiple reasons. Make sure that you [configured](/configuration/initialization) NextAuth.js correctly, and if you used [`NEXTAUTH_URL`](https://next-auth.js.org/configuration/options#nextauth_url) that it's correctly set.
---
@@ -78,7 +78,7 @@ If you are using an OAuth v1 provider, check your OAuth v1 provider settings, es
3. `openid-client` version mismatch
If you are seeing `expected 200 OK with body but no body was returned`, it might have happened due to `openid-client` (which is peer dependency) node version mismatch. For instance, `openid-client` requires `>=14.2.0` for `lts/fermium` and has similar limits for the other versions. For the full list of the compatible node versions please see [package.json](https://github.com/panva/node-openid-client/blob/2a84e46992e1ebeaf685c3f87b65663d126e81aa/package.json#L78).
If you are seeing `expected 200 OK with body but no body was returned`, it might have happened due to `openid-client` (which is a dependency we rely on) node version mismatch. For instance, `openid-client` requires `>=14.2.0` for `lts/fermium` and has similar limits for the other versions. For the full list of the compatible node versions please see [package.json](https://github.com/panva/node-openid-client/blob/2a84e46992e1ebeaf685c3f87b65663d126e81aa/package.json#L78).
#### OAUTH_CALLBACK_ERROR

View File

@@ -67,7 +67,7 @@ _If you use a custom credentials provider user accounts will not be persisted in
</summary>
<p>
NextAuth.js was originally designed for use with Next.js and Serverless. However, today you could use the NextAuth.js core with any other framework. Checkout the examples for <a href="https://github.com/nextauthjs/next-auth/tree/main/apps/example-gatsby" target="_blank">Gatsby</a> and <a href="https://github.com/nextauthjs/next-auth/tree/main/apps/playground-sveltekit" target="_blank">SvelteKit</a>. If you would add another integration with other frameworks, feel free to work on it and send a pull request. Make sure to check if there's any on-going work before open a new issue.
NextAuth.js was originally designed for use with Next.js and Serverless. However, today you could use the NextAuth.js core with any other framework. Checkout the examples for <a href="https://github.com/nextauthjs/next-auth/tree/main/apps/playground-gatsby" target="_blank">Gatsby</a> and <a href="https://sveltekit.authjs.dev/" target="_blank">SvelteKit</a>. If you would add another integration with other frameworks, feel free to work on it and send a pull request. Make sure to check if there's any on-going work before opening a new issue.
</p>
</details>
@@ -207,7 +207,7 @@ NextAuth.js records Refresh Tokens and Access Tokens on sign in (if supplied by
You can then look them up from the database or persist them to the JSON Web Token.
Note: NextAuth.js does not currently handle Access Token rotation for OAuth providers for you, however you can check out [this tutorial](/tutorials/refresh-token-rotation) if you want to implement it.
Note: NextAuth.js does not currently handle Access Token rotation for OAuth providers for you, however you can check out [this tutorial](https://authjs.dev/guides/basics/refresh-token-rotation) if you want to implement it.
We also have an [example repository](https://github.com/nextauthjs/next-auth-refresh-token-example) / project based upon NextAuth.js v4 where we demonstrate how to use a refresh token to refresh the provided access token.
@@ -289,7 +289,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). Since v4 all our JWT tokens are now encrypted by default with A256GCM.
NextAuth.js by default uses JSON Web Tokens for saving the user's session. However, if you use a [database adapter](https://authjs.dev/reference/adapters), 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>

View File

@@ -65,7 +65,7 @@ export default function Component() {
### Require session
Due to the way how Next.js handles `getServerSideProps` and `getInitialProps`, every protected page load has to make a server-side request to check if the session is valid and then generate the requested page (SSR). This increases server load, and if you are good with making the requests from the client, there is an alternative. You can use `useSession` in a way that makes sure you always have a valid session. If after the initial loading state there was no session found, you can define the appropriate action to respond.
Due to the way Next.js handles `getServerSideProps` and `getInitialProps`, every protected page load has to make a server-side request to check if the session is valid and then generate the requested page (SSR). This increases server load, and if you are good with making the requests from the client, there is an alternative. You can use `useSession` in a way that makes sure you always have a valid session. If after the initial loading state there was no session found, you can define the appropriate action to respond.
The default behavior is to redirect the user to the sign-in page, from where - after a successful login - they will be sent back to the page they started on. You can also define an `onUnauthenticated()` callback, if you would like to do something else:
@@ -148,24 +148,143 @@ Because of how `_app` is written, it won't unnecessarily contact the `/api/auth/
More information can be found in the following [GitHub Issue](https://github.com/nextauthjs/next-auth/issues/1210).
### NextAuth.js + React Query
### Updating the session
You can create your own session management solution using data fetching libraries like [React Query](https://tanstack.com/query/v4/docs/adapters/react-query) or [SWR](https://swr.vercel.app). You can use the [original implementation of `@next-auth/react-query`](https://github.com/nextauthjs/react-query) and look at the [`next-auth/react` source code](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/react/index.tsx) as a starting point.
The `useSession()` hook exposes a `update(data?: any): Promise<Session | null>` method that can be used to update the session, without reloading the page.
You can optionally pass an arbitrary object as the first argument, which will be accessible on the server to merge with the session object.
If you are not passing any argument, the session will be reloaded from the server. (This is useful if you want to update the session after a server-side mutation, like updating in the database.)
:::caution
The data object is coming from the client, so it needs to be validated on the server before saving.
:::
#### Example
```tsx title="pages/profile.tsx"
import { useSession } from "next-auth/react"
export default function Page() {
const { data: session, status, update } = useSession()
if (status === "authenticated") {
return (
<>
<p>Signed in as {session.user.name}</p>
{/* Update the value by sending it to the backend. */}
<button onClick={() => update({ name: "John Doe" })}>
Edit name
</button>
{/*
* Only trigger a session update, assuming you already updated the value server-side.
* All `useSession().data` references will be updated.
*/}
<button onClick={() => update()}>
Edit name
</button>
</>
)
}
return <a href="/api/auth/signin">Sign in</a>
}
```
Assuming a `strategy: "jwt"` is used, the `update()` method will trigger a `jwt` callback with the `trigger: "update"` option. You can use this to update the session object on the server.
```ts title="pages/api/auth/[...nextauth].ts"
...
export default NextAuth({
...
callbacks: {
// Using the `...rest` parameter to be able to narrow down the type based on `trigger`
jwt({ token, trigger, session }) {
if (trigger === "update" && session?.name) {
// Note, that `session` can be any arbitrary object, remember to validate it!
token.name = session.name
}
return token
}
}
})
```
Assuming a `strategy: "database"` is used, the `update()` method will trigger the `session` callback with the `trigger: "update"` option. You can use this to update the session object on the server.
```ts title="pages/api/auth/[...nextauth].ts"
...
const adapter = PrismaAdapter(prisma)
export default NextAuth({
...
adapter,
callbacks: {
// Using the `...rest` parameter to be able to narrow down the type based on `trigger`
async session({ session, trigger, newSession }) {
// Note, that `rest.session` can be any arbitrary object, remember to validate it!
if (trigger === "update" && newSession?.name) {
// You can update the session in the database if it's not already updated.
// await adapter.updateUser(session.user.id, { name: newSession.name })
// Make sure the updated value is reflected on the client
session.name = newSession.name
}
return session
}
}
})
```
### Refetching the session
[`SessionProvider#refetchInterval`](#refetch-interval) and [`SessionProvider#refetchOnWindowFocus`](#refetch-on-window-focus) can be replaced with the `update()` method too.
:::note
The `update()` method won't sync between tabs as the `refetchInterval` and `refetchOnWindowFocus` options do.
:::
```tsx title="pages/profile.tsx"
import {useEffect} from "react"
import { useSession } from "next-auth/react"
export default function Page() {
const { data: session, status, update } = useSession()
// Polling the session every 1 hour
useEffect(() => {
// TIP: You can also use `navigator.onLine` and some extra event handlers
// to check if the user is online and only update the session if they are.
// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine
const interval = setInterval(() => update(), 1000 * 60 * 60)
return () => clearInterval(interval)
}, [update])
// Listen for when the page is visible, if the user switches tabs
// and makes our tab visible again, re-fetch the session
useEffect(() => {
const visibilityHandler = () => document.visibilityState === "visible" && update()
window.addEventListener("visibilitychange", visibilityHandler, false)
return () => window.removeEventListener("visibilitychange", visibilityHandler, false)
}, [update])
return (
<pre>
{JSON.stringify(session, null, 2)}
</pre>
)
}
```
---
## getSession()
- Client Side: **Yes**
- Server Side: **No** (See: [`unstable_getServerSession()`](/configuration/nextjs#unstable_getserversession)
- Server Side: **No** (See: [`getServerSession()`](/configuration/nextjs#unstable_getserversession)
NextAuth.js provides a `getSession()` helper which should be called **client side only** to return the current active session.
On the server side, **this is still available to use**, however, we recommend using `unstable_getServerSession` going forward. The idea behind this is to avoid an additional unnecessary `fetch` call on the server side. For more information, please check out [this issue](https://github.com/nextauthjs/next-auth/issues/1535).
:::note
The `unstable_getServerSession` only has the prefix `unstable_` at the moment, because the API may change in the future. There are no known bugs at the moment and it is safe to use. If you discover any issues, please do report them as a [GitHub Issue](https://github.com/nextauthjs/next-auth/issues) and we will patch them as soon as possible.
:::
On the server side, **this is still available to use**, however, we recommend using `getServerSession` going forward. The idea behind this is to avoid an additional unnecessary `fetch` call on the server side. For more information, please check out [this issue](https://github.com/nextauthjs/next-auth/issues/1535).
This helper is helpful in case you want to read the session outside of the context of React.
@@ -178,7 +297,7 @@ async function myFunction() {
}
```
Read the tutorial [securing pages and API routes](/tutorials/securing-pages-and-api-routes) to know how to fetch the session in server side calls using `unstable_getServerSession()`.
Read the tutorial [securing pages and API routes](/tutorials/securing-pages-and-api-routes) to know how to fetch the session in server side calls using `getServerSession()`.
---
@@ -240,7 +359,7 @@ export default async (req, res) => {
```
:::note
Unlike and `getCsrfToken()`, when calling `getProviders()` server side, you don't need to pass anything, just as calling it client side.
Unlike `getCsrfToken()`, when calling `getProviders()` server side, you don't need to pass anything, just as calling it client side.
:::
---
@@ -400,7 +519,11 @@ where `data.url` is the validated URL you can redirect the user to without any f
## SessionProvider
Using the supplied `<SessionProvider>` allows instances of `useSession()` to share the session object across components, by using [React Context](https://reactjs.org/docs/context.html) under the hood. It also takes care of keeping the session updated and synced between tabs/windows.
:::note
If you are using the App Router, we encourage you to use [`getServerSession`](/configuration/nextjs#getserversession) in server contexts instead. (`SessionProvider` *can* be used in the App Router, which might be the easier choice if you are migrating from pages.)
:::
Using the supplied `<SessionProvider>` allows instances of `useSession()` to share the session object across components, by using [React Context](https://react.dev/learn/passing-data-deeply-with-context) under the hood. It also takes care of keeping the session updated and synced between tabs/windows.
```jsx title="pages/_app.js"
import { SessionProvider } from "next-auth/react"
@@ -422,7 +545,7 @@ If you pass the `session` page prop to the `<SessionProvider>` as in the exa
This only works on pages where you provide the correct `pageProps`, however. This is normally done in `getInitialProps` or `getServerSideProps` on an individual page basis like so:
```js title="pages/index.js"
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from './api/auth/[...nextauth]'
...
@@ -430,7 +553,7 @@ import { authOptions } from './api/auth/[...nextauth]'
export async function getServerSideProps({ req, res }) {
return {
props: {
session: await unstable_getServerSession(req, res, authOptions)
session: await getServerSession(req, res, authOptions)
}
}
}
@@ -483,6 +606,8 @@ If you are using a custom base path, and your application entry point is not at
#### Refetch interval
See [Session Refetching](#refetching-the-session) for an alternative option.
The `refetchInterval` option can be used to contact the server to avoid a session expiring.
When `refetchInterval` is set to `0` (the default) there will be no session polling.
@@ -495,6 +620,8 @@ By default, session polling will keep trying, even when the device has no intern
#### Refetch On Window Focus
See [Session Refetching](#refetching-the-session) for an alternative option.
The `refetchOnWindowFocus` option can be used to control whether it automatically updates the session state when you switch a focus on tabs/windows.
When `refetchOnWindowFocus` is set to `true` (the default) tabs/windows will be updated and initialize the components' state when they gain or lose focus.

View File

@@ -26,6 +26,8 @@ If you are using TypeScript, NextAuth.js comes with its types definitions within
To add NextAuth.js to a project create a file called `[...nextauth].js` in `pages/api/auth`. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
If you're using [Next.js 13.2](https://nextjs.org/blog/next-13-2#custom-route-handlers) or above with the new App Router (`app/`), you can initialize the configuration using the new [Route Handlers](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) by following our [guide](https://next-auth.js.org/configuration/initialization#route-handlers-app).
```javascript title="pages/api/auth/[...nextauth].js" showLineNumbers
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
@@ -74,6 +76,7 @@ Instances of `useSession` will then have access to the session data and status.
:::tip
Check out the [client documentation](/getting-started/client) to see how you can improve the user experience and page performance by using the NextAuth.js client.
If you are using the Next.js App Router, please note that `<SessionProvider />` requires a client component and therefore cannot be put inside the root layout. For more details, check out the [Next.js documentation](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts).
:::
### Frontend - Add React Hook
@@ -106,14 +109,14 @@ You can use the `useSession` hook from anywhere in your application (e.g. in a h
### Backend - API Route
To protect an API Route, you can use the [`unstable_getServerSession()`](/configuration/nextjs#unstable_getserversession) method.
To protect an API Route, you can use the [`getServerSession()`](/configuration/nextjs#unstable_getserversession) method.
```javascript title="pages/api/restricted.js" showLineNumbers
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./auth/[...nextauth]"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
if (session) {
res.send({

View File

@@ -16,7 +16,7 @@ It is designed from the ground up to support Next.js and Serverless.
- Designed to work with any [OAuth service, it supports OAuth 1.0, 1.0A, 2.0 and OpenID Connect](/providers)
- Built-in support for [many popular sign-in services](/configuration/providers/oauth)
- Supports [email / passwordless authentication](/providers/email)
- Supports stateless authentication with [any backend](/adapters/overview) (Active Directory, LDAP, etc)
- Supports stateless authentication with [any backend](https://authjs.dev/reference/adapters) (Active Directory, LDAP, etc)
- Supports both JSON Web Tokens and database sessions
- Designed for Serverless but runs anywhere (AWS Lambda, Docker, Heroku, etc…)

View File

@@ -6,7 +6,7 @@ title: TypeScript
NextAuth.js has its own type definitions to use in your TypeScript projects safely. Even if you don't use TypeScript, IDEs like VSCode will pick this up to provide you with a better developer experience. While you are typing, you will get suggestions about what certain objects/functions look like, and sometimes links to documentation, examples, and other valuable resources.
Check out the example repository showcasing how to use `next-auth` on a Next.js application with TypeScript:
https://github.com/nextauthjs/next-auth-typescript-example
https://github.com/nextauthjs/next-auth-example
---

View File

@@ -311,7 +311,7 @@ export default NextAuth({
3. The `typeorm-legacy` adapter has been upgraded to use the newer adapter API, but has retained the `typeorm-legacy` name. We aim to migrate this to individual lighter weight adapters for each database type in the future, or switch out `typeorm`.
4. MongoDB has been moved to its own adapter under `@next-auth/mongodb-adapter`. See the [MongoDB Adapter docs](/adapters/mongodb).
4. MongoDB has been moved to its own adapter under `@next-auth/mongodb-adapter`. See the [MongoDB Adapter docs](https://authjs.dev/reference/adapter/mongodb).
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.8 and https://github.com/nextauthjs/next-auth/pull/2361
@@ -319,7 +319,7 @@ Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.8
**This does not require any changes from the user - these are adapter specific changes only**
The Adapter API has been rewritten and significantly simplified in NextAuth.js v4. The adapters now have less work to do as some functionality has been migrated to the core of NextAuth, like hashing the [verification token](/adapters/models/#verification-token).
The Adapter API has been rewritten and significantly simplified in NextAuth.js v4. The adapters now have less work to do as some functionality has been migrated to the core of NextAuth, like hashing the [verification token](https://authjs.dev/reference/adapters#verification-token).
If you are an adapter maintainer or are interested in writing your own adapter, you can find more information about this change in https://github.com/nextauthjs/next-auth/pull/2361 and release https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.22.
@@ -351,8 +351,8 @@ User {
id
name
email
- emailVerified
+ email_verified
+ emailVerified
- email_verified
image
- created_at
- updated_at
@@ -405,7 +405,7 @@ VerificationToken {
</pre>
</details>
For more info, see the [Models page](/adapters/models).
For more info, see the [Models page](https://authjs.dev/reference/adapters#models).
### Database migration

View File

@@ -3,7 +3,7 @@ id: fullstack
title: Fullstack
---
### [Refresh Token Rotation](/tutorials/refresh-token-rotation)
### [Refresh Token Rotation](https://authjs.dev/guides/basics/refresh-token-rotation)
- How to implement refresh token rotation.
@@ -21,7 +21,7 @@ title: Fullstack
## Database
### [Custom models with TypeORM](/adapters/typeorm#custom-models)
### [Custom models with TypeORM](https://authjs.dev/reference/adapter/typeorm#custom-models)
- How to use models with custom properties using the TypeORM adapter.
@@ -29,6 +29,6 @@ title: Fullstack
- How to create a custom adapter, to use any database to fetch and store user / account data.
### [Adding role based login to database session strategy](/tutorials/role-based-login-strategy)
### [Adding role based login to database session strategy](https://authjs.dev/guides/basics/role-based-access-control)
- Implement a role based login system by adding a custom session callback.

View File

@@ -4,7 +4,7 @@ title: 42 School
---
:::note
42 returns a field on `Account` called `created_at` which is a number. See the [docs](https://api.intra.42.fr/apidoc/guides/getting_started#make-basic-requests). Make sure to add this field to your database schema, in case if you are using an [Adapter](/adapters/overview).
42 returns a field on `Account` called `created_at` which is a number. See the [docs](https://api.intra.42.fr/apidoc/guides/getting_started#make-basic-requests). Make sure to add this field to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation

View File

@@ -64,7 +64,7 @@ Edit your host file and point your site to `127.0.0.1`.
_Linux/macOS_
```
sudo echo '127.0.0.1 dev.example.com' >> /etc/hosts
echo '127.0.0.1 dev.example.com' | sudo tee -a /etc/hosts
```
_Windows_ (run PowerShell as administrator)

View File

@@ -11,7 +11,7 @@ Azure AD B2C returns the following fields on `Account`:
- `id_token_expires_in` (number)
- `profile_info` (string).
See their [docs](https://docs.microsoft.com/en-us/azure/active-directory-b2c/access-tokens). Remember to add these fields to your database schema, in case if you are using an [Adapter](/adapters/overview).
See their [docs](https://docs.microsoft.com/en-us/azure/active-directory-b2c/access-tokens). Remember to add these fields to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation

View File

@@ -3,6 +3,17 @@ id: azure-ad
title: Azure Active Directory
---
:::note
Azure Active Directory returns the following fields on `Account`:
- `token_type` (string)
- `expires_in` (number)
- `ext_expires_in` (number)
- `access_token` (string).
Remember to add these fields to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation
https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow
@@ -20,7 +31,7 @@ https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-regis
- Pay close attention to "Who can use this application or access this API?"
- This allows you to scope access to specific types of user accounts
- Only your tenant, all azure tenants, or all azure tenants and public Microsoft accounts (Skype, Xbox, Outlook.com, etc.)
- When asked for a redirection URL, use `https://yourapplication.com/api/auth/callback/azure-ad` or for development `http://localhost:3000/api/auth/callback/azure-ad`.
- When asked for a redirection URL, select the platform type "Web" and use `https://yourapplication.com/api/auth/callback/azure-ad` or for development `http://localhost:3000/api/auth/callback/azure-ad`.
- After your App Registration is created, under "Client Credential" create your Client secret.
- Now copy your:
- Application (client) ID
@@ -37,6 +48,10 @@ AZURE_AD_TENANT_ID=<copy the tenant id here>
That will default the tenant to use the `common` authorization endpoint. [For more details see here](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints).
:::note
When you see `ResourceNotFound` error code while accessing an API, make sure to use the correct tenant ID. For instance, when the intended access is for a personal account, the tenant ID should not be provided.
:::
:::note
Azure AD returns the profile picture in an ArrayBuffer, instead of just a URL to the image, so our provider converts it to a base64 encoded image string and returns that instead. See: https://docs.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0#examples. The default image size is 48x48 to avoid [running out of space](https://next-auth.js.org/faq#:~:text=What%20are%20the%20disadvantages%20of%20JSON%20Web%20Tokens%3F) in case the session is saved as a JWT.
:::

View File

@@ -125,7 +125,7 @@ providers: [
return user
},
credentials: {
email: { label: "Username", type: "text ", placeholder: "jsmith" },
username: { label: "Username", type: "text ", placeholder: "jsmith" },
"2fa-key": { label: "2FA Key" },
},
}),

View File

@@ -0,0 +1,53 @@
---
id: duende-identityserver6
title: DuendeIdentityServer6
---
## Documentation
https://docs.duendesoftware.com/identityserver/v6
## Options
The **DuendeIdentityServer6 Provider** comes with a set of default options:
- [DuendeIdentityServer6 Provider options](https://github.com/nextauthjs/next-auth/blob/v4/packages/next-auth/src/providers/duende-identity-server6.ts)
You can override any of the options to suit your own use case.
## Example
```js
import DuendeIDS6Provider from "next-auth/providers/duende-identity-server6"
...
providers: [
DuendeIDS6Provider({
clientId: process.env.DUENDE_IDS6_ID,
clientSecret: process.env.DUENDE_IDS6_SECRET,
issuer: process.env.DUENDE_IDS6_ISSUER,
})
]
...
```
## Demo IdentityServer
The configuration below is for the demo server at https://demo.duendesoftware.com/
If you want to try it out, you can copy and paste the configuration below.
You can sign in to the demo service with either <b>bob/bob</b> or <b>alice/alice</b>.
```js
import DuendeIDS6Provider from "next-auth/providers/duende-identity-server6"
...
providers: [
DuendeIDS6Provider({
clientId: "interactive.confidential",
clientSecret: "secret",
issuer: "https://demo.duendesoftware.com",
})
]
...
```

View File

@@ -32,11 +32,19 @@ You can override any of the options to suit your own use case.
## Configuration
NextAuth.js lets you send emails either via HTTP or SMTP.
### HTTP
Check out our [HTTP-based Email Provider](https://authjs.dev/guides/providers/email-http) guide.
### SMTP
1. NextAuth.js does not include `nodemailer` as a dependency, so you'll need to install it yourself if you want to use the Email Provider. Run `npm install nodemailer` or `yarn add nodemailer`.
2. You will need an SMTP account; ideally for one of the [services known to work with `nodemailer`](https://community.nodemailer.com/2-0-0-beta/setup-smtp/well-known-services/).
3. There are two ways to configure the SMTP server connection.
You can either use a connection string or a `nodemailer` configuration object.
You can either use a connection string or a `nodemailer` configuration object or transport.
2.1 **Using a connection string**
@@ -92,7 +100,7 @@ providers: [
],
```
3. Do not forget to setup one of the database [adapters](/adapters/overview) for storing the Email verification token.
3. Do not forget to setup one of the database [adapters](https://authjs.dev/reference/adapters) for storing the Email verification token.
4. You can now sign in with an email address at `/api/auth/signin`.
@@ -252,3 +260,27 @@ By default, NextAuth.js will normalize the email address. It treats values as ca
:::warning
Always make sure this returns a single e-mail address, even if multiple ones were passed in.
:::
## Sending Magic Links To Existing Users
You can ensure that only existing users are sent a magic login link. You will need to grab the email the user entered and check your database to see if the email already exists in the "User" collection in your database. If it exists, it will send the user a magic link but otherwise, you can send the user to another page, such as "/register".
```js title="pages/api/auth/[...nextauth].js"
import User from "../../../models/User";
import db from "../../../utils/db";
...
callbacks: {
async signIn({ user, account, email }) {
await db.connect();
const userExists = await User.findOne({
email: user.email, //the user object has an email property, which contains the email the user entered.
});
if (userExists) {
return true; //if the email exists in the User collection, email them a magic login link
} else {
return "/register";
}
},
...
```

View File

@@ -4,7 +4,7 @@ title: GitHub
---
:::note
GitHub returns a field on `Account` called `refresh_token_expires_in` which is a number. See their [docs](https://docs.github.com/en/developers/apps/building-github-apps/refreshing-user-to-server-access-tokens#response). Remember to add this field to your database schema, in case if you are using an [Adapter](/adapters/overview).
GitHub returns a field on `Account` called `refresh_token_expires_in` which is a number. See their [docs](https://docs.github.com/en/developers/apps/building-github-apps/refreshing-user-to-server-access-tokens#response). Remember to add this field to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation

View File

@@ -3,6 +3,10 @@ id: gitlab
title: GitLab
---
:::note
GitLab returns a field on `Account` called `created_at` which is a number. See their [docs](https://docs.gitlab.com/ee/api/oauth2.html). Remember to add this field as optional to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation
https://docs.gitlab.com/ee/api/oauth2.html

View File

@@ -35,27 +35,3 @@ providers: [
]
...
```
## Demo IdentityServer
The configuration below is for the demo server at https://demo.identityserver.io/
If you want to try it out, you can copy and paste the configuration below.
You can sign in to the demo service with either <b>bob/bob</b> or <b>alice/alice</b>.
```js
import IdentityServer4Provider from `next-auth/providers/identity-server4`
...
providers: [
IdentityServer4Provider({
id: "demo-identity-server",
name: "Demo IdentityServer4",
authorization: { params: { scope: "openid profile email api offline_access" } },
issuer: "https://demo.identityserver.io/",
clientId: "interactive.confidential",
clientSecret: "secret",
})
}
...
```

View File

@@ -15,7 +15,7 @@ https://developers.kakao.com/docs/latest/en/kakaologin/common
The **Kakao Provider** comes with a set of default options:
- [Kakao Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/kakao.js)
- [Kakao Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/kakao.ts)
You can override any of the options to suit your own use case.

View File

@@ -11,7 +11,7 @@ https://help.salesforce.com/articleView?id=remoteaccess_authenticate.htm&type=5
The **Salesforce Provider** comes with a set of default options:
- [Salesforce Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/salesforce.js)
- [Salesforce Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/salesforce.ts)
You can override any of the options to suit your own use case.

View File

@@ -4,7 +4,7 @@ title: Twitter
---
:::note
Twitter is currently the only built-in provider using the OAuth 1.0 spec. This means that you won't receive an `access_token` or `refresh_token`, but an `oauth_token` and `oauth_token_secret` respectively. Remember to add these to your database schema, in case if you are using an [Adapter](/adapters/overview).
Twitter is currently the only built-in provider using the OAuth 1.0 spec. This means that you won't receive an `access_token` or `refresh_token`, but an `oauth_token` and `oauth_token_secret` respectively. Remember to add these to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation

View File

@@ -15,7 +15,7 @@ https://vk.com/apps?act=manage
The **VK Provider** comes with a set of default options:
- [VK Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/vk.js)
- [VK Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/vk.ts)
You can override any of the options to suit your own use case.
@@ -34,7 +34,7 @@ providers: [
```
:::note
By default the provider uses `5.126` version of the API. See https://vk.com/dev/versions for more info.
By default the provider uses `5.131` version of the API. See https://vk.com/dev/versions for more info.
:::
If you want to use a different version, you can pass it to provider's options object:
@@ -42,7 +42,7 @@ If you want to use a different version, you can pass it to provider's options ob
```js
// pages/api/auth/[...nextauth].js
const apiVersion = "5.126"
const apiVersion = "5.131"
...
providers: [
VkProvider({

View File

@@ -3,6 +3,10 @@ id: zoho
title: Zoho
---
:::note
Zoho returns a field on `Account` called `api_domain` which is a string. See their [docs](https://www.zoho.com/accounts/protocol/oauth/web-apps/access-token.html). Remember to add this field to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation
https://www.zoho.com/accounts/protocol/oauth/web-server-applications.html

View File

@@ -30,7 +30,7 @@ import NextAuth from "next-auth"
export default async function auth(req: NextApiRequest, res: NextApiResponse) {
if(req.method === "HEAD") {
return res.status(200)
return res.status(200).end()
}
...

View File

@@ -7,7 +7,7 @@ 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).
For more information about the data these methods need to manage see [models](https://authjs.dev/reference/adapters#models).
_See the code below for practical example._

View File

@@ -1,137 +0,0 @@
---
id: refresh-token-rotation
title: Refresh Token Rotation
---
While NextAuth.js doesn't automatically handle access token rotation for OAuth providers yet, this functionality can be implemented using [callbacks](https://next-auth.js.org/configuration/callbacks).
## Source Code
A working example can be accessed [here](https://github.com/nextauthjs/next-auth-refresh-token-example).
## Implementation
### Server Side
Using a [JWT callback](https://next-auth.js.org/configuration/callbacks#jwt-callback) and a [session callback](https://next-auth.js.org/configuration/callbacks#session-callback), we can persist OAuth tokens and refresh them when they expire.
Below is a sample implementation using Google's Identity Provider. Please note that the OAuth 2.0 request in the `refreshAccessToken()` function will vary between different providers, but the core logic should remain similar.
```js title="pages/api/auth/[...nextauth].js"
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
const GOOGLE_AUTHORIZATION_URL =
"https://accounts.google.com/o/oauth2/v2/auth?" +
new URLSearchParams({
prompt: "consent",
access_type: "offline",
response_type: "code",
})
/**
* Takes a token, and returns a new token with updated
* `accessToken` and `accessTokenExpires`. If an error occurs,
* returns the old token and an error property
*/
async function refreshAccessToken(token) {
try {
const url =
"https://oauth2.googleapis.com/token?" +
new URLSearchParams({
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
grant_type: "refresh_token",
refresh_token: token.refreshToken,
})
const response = await fetch(url, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
method: "POST",
})
const refreshedTokens = await response.json()
if (!response.ok) {
throw refreshedTokens
}
return {
...token,
accessToken: refreshedTokens.access_token,
accessTokenExpires: Date.now() + refreshedTokens.expires_at * 1000,
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken, // Fall back to old refresh token
}
} catch (error) {
console.log(error)
return {
...token,
error: "RefreshAccessTokenError",
}
}
}
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: GOOGLE_AUTHORIZATION_URL,
}),
],
callbacks: {
async jwt({ token, user, account }) {
// Initial sign in
if (account && user) {
return {
accessToken: account.access_token,
accessTokenExpires: Date.now() + account.expires_at * 1000,
refreshToken: account.refresh_token,
user,
}
}
// Return previous token if the access token has not expired yet
if (Date.now() < token.accessTokenExpires) {
return token
}
// Access token has expired, try to update it
return refreshAccessToken(token)
},
async session({ session, token }) {
session.user = token.user
session.accessToken = token.accessToken
session.error = token.error
return session
},
},
})
```
### Client Side
The `RefreshAccessTokenError` error that is caught in the `refreshAccessToken()` method is passed all the way to the client. This means that you can direct the user to the sign in flow if we cannot refresh their token.
We can handle this functionality as a side effect:
```js title="pages/home.js"
import { signIn, useSession } from "next-auth/react";
import { useEffect } from "react";
const HomePage() {
const { data: session } = useSession();
useEffect(() => {
if (session?.error === "RefreshAccessTokenError") {
signIn(); // Force sign in to hopefully resolve error
}
}, [session]);
return (...)
}
```

View File

@@ -1,61 +0,0 @@
To add role based authentication to your application, you must do three things.
1. Update your database schema
2. Add the `role` to the session object
3. Check for `role` in your pages/components
First modify the `user` table and add a `role` column with the type of `String?`.
Below is an example Prisma schema file.
```javascript title="/prisma/schema.prisma"
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
role String? // New Column
accounts Account[]
sessions Session[]
}
```
Next, implement a custom session callback in the `[...nextauth].js` file, as shown below.
```javascript title="/pages/api/auth/[...nextauth].js"
callbacks: {
async session({ session, token, user }) {
session.user.role = user.role; // Add role value to user object so it is passed along with session
return session;
}
},
```
Going forward, when using the `getSession` hook, check that `session.user.role` matches the required role. The example below assumes the role `'admin'` is required.
```javascript title="/pages/admin.js"
import { getSession } from "next-auth/react"
export default function Page() {
const session = await getSession({ req })
if (session && session.user.role === "admin") {
return (
<div>
<h1>Admin</h1>
<p>Welcome to the Admin Portal!</p>
</div>
)
} else {
return (
<div>
<h1>You are not authorized to view this page!</h1>
</div>
)
}
}
```
Then it is up to you how you manage your roles, either through direct database access or building your own role update API.

View File

@@ -42,7 +42,7 @@ export default function Page() {
### Next.js (Middleware)
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `middleware.js` file in your root `pages` directory which looks like this:
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `middleware.js` file at the root or in the src directory (same level as your `pages`) which looks like this:
```js title="/middleware.js"
export { default } from "next-auth/middleware"
@@ -68,12 +68,12 @@ For other patterns check out the [Next.js Middleware documentation](https://next
### Server Side
You can protect server side rendered pages using the `unstable_getServerSession` method. This is different from the old `getSession()` method, in that it does not do an extra fetch out over the internet to confirm data from itself, increasing performance significantly.
You can protect server side rendered pages using the `getServerSession` method. This is different from the old `getSession()` method, in that it does not do an extra fetch out over the internet to confirm data from itself, increasing performance significantly.
You need to add this to every server rendered page you want to protect. Be aware, `unstable_getServerSession` takes slightly different arguments than the method it is replacing, `getSession`.
You need to add this to every server rendered page you want to protect. Be aware, `getServerSession` takes slightly different arguments than the method it is replacing, `getSession`.
```js title="pages/server-side-example.js"
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import { useSession } from "next-auth/react"
@@ -96,7 +96,7 @@ export default function Page() {
export async function getServerSideProps(context) {
return {
props: {
session: await unstable_getServerSession(
session: await getServerSession(
context.req,
context.res,
authOptions
@@ -128,16 +128,16 @@ export default function App({
## Securing API Routes
### Using unstable_getServerSession()
### Using getServerSession()
You can protect API routes using the `unstable_getServerSession()` method.
You can protect API routes using the `getServerSession()` method.
```js title="pages/api/get-session-example.js"
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./auth/[...nextauth]"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
const session = await getServerSession(req, res, authOptions)
if (session) {
// Signed in
console.log("Session", JSON.stringify(session, null, 2))

View File

@@ -7,8 +7,6 @@ module.exports = {
favicon: "img/favicon.ico",
organizationName: "nextauthjs",
projectName: "next-auth",
// TODO: remove this once BETA is ready
onBrokenLinks: "log",
themeConfig: {
prism: {
theme: require("prism-react-renderer/themes/vsDark"),
@@ -23,8 +21,10 @@ module.exports = {
algolia: {
appId: "OUEDA16KPG",
apiKey: "97c0894508f2d1d4a2fef4fe6db28448",
indexName: "next-auth",
indexName: "next-auth-v4",
searchParameters: {},
contextualSearch: false,
externalUrlRegex: "authjs\\.dev|next-auth\\.js\\.org",
},
navbar: {
title: "NextAuth.js",
@@ -107,13 +107,13 @@ module.exports = {
},
],
},
// announcementBar: {
// id: "new-major-announcement",
// content:
// "The default documentation is for v4 which has been released to GA 🚨 migration to <b>v4</b> docs can be found <a href='/getting-started/upgrade-v4'>here</a> 👈 The old v3 docs can be found <a href='/v3/getting-started/introduction'>here</a>.",
// backgroundColor: "#1786fb",
// textColor: "#fff",
// },
announcementBar: {
id: "new-major-announcement",
content:
"NextAuth.js is becoming Auth.js! 🎉 We're creating Authentication for the Web. Everyone included. You are looking at the NextAuth.js (v4) documentation. For the new documentation go to <a target='_blank' rel='noopener noreferrer' href='https://authjs.dev'>authjs.dev</a>.",
backgroundColor: "#000",
textColor: "#fff",
},
footer: {
links: [
{
@@ -180,7 +180,7 @@ module.exports = {
docs: {
routeBasePath: "/",
sidebarPath: require.resolve("./sidebars.js"),
editUrl: "https://github.com/nextauthjs/next-auth/edit/main/docs",
editUrl: "https://github.com/nextauthjs/next-auth/edit/v4/docs",
lastVersion: "current",
showLastUpdateAuthor: true,
showLastUpdateTime: true,
@@ -196,10 +196,6 @@ module.exports = {
v3: {
label: "v3",
},
beta: {
label: "v4-unreleased",
banner: "unreleased",
},
},
},
theme: {

View File

@@ -7,7 +7,7 @@
"name": "next-auth-docs",
"version": "0.2.0",
"scripts": {
"start": "npm run generate-providers && docusaurus start --no-open --port 8000",
"start": "npm run generate-providers && docusaurus start --no-open",
"dev": "npm run start",
"build": "npm run generate-providers && docusaurus build",
"docusaurus": "docusaurus",
@@ -29,15 +29,20 @@
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-marquee-slider": "^1.1.5",
"remark-github": "^10.1.0",
"styled-components": "5.3.3"
"remark-github": "^10.1.0"
},
"devDependencies": {
"@docusaurus/core": "2.1.0",
"@docusaurus/module-type-aliases": "2.1.0",
"@docusaurus/preset-classic": "2.1.0",
"@docusaurus/theme-common": "2.1.0",
"@docusaurus/types": "2.1.0"
"@docusaurus/types": "2.1.0",
"autoprefixer": "^10.4.7",
"framer-motion": "^10.16.4",
"postcss": "^8.4.14",
"postcss-nested": "^5.0.6",
"styled-components": "5.3.3",
"tailwindcss": "^3.3.3"
},
"browserslist": {
"production": [

Some files were not shown because too many files have changed in this diff Show More