Compare commits

..

128 Commits

Author SHA1 Message Date
ndom91
657dd57ef7 fix(docs): clean up v5 migration intro 2023-05-07 14:30:01 +02:00
ndom91
39691313fb feat(docs): initial v5 next-auth upgrade guide doc 2023-05-07 14:17:32 +02:00
Balázs Orbán
a7e02266cf fix value 2023-05-05 16:14:16 +02:00
Balázs Orbán
bac8b8d13a add getServerSession, simplify auth() return 2023-05-05 14:33:45 +02:00
Balázs Orbán
bb4d5ce29b update dev app 2023-05-05 14:32:40 +02:00
Balázs Orbán
436d46ab89 tweak docs 2023-05-05 02:57:19 +02:00
Balázs Orbán
b17dc76a70 Merge branch 'main' into feat/nextjs-auth 2023-05-05 02:38:57 +02:00
Balázs Orbán
b96f01319c chore: tweak manual release version 2023-05-05 02:38:47 +02:00
Balázs Orbán
5fb4caa485 whitespace 2023-05-05 02:32:04 +02:00
Balázs Orbán
24e8100a61 move 2023-05-05 02:31:52 +02:00
Balázs Orbán
b17c5deafb add installation 2023-05-05 02:31:40 +02:00
Balázs Orbán
7da32563d6 docs 2023-05-05 02:30:33 +02:00
Balázs Orbán
c470960d93 docs 2023-05-05 02:23:00 +02:00
Balázs Orbán
8cfd1aeb15 improve docs 2023-05-05 02:20:41 +02:00
Balázs Orbán
af81776e4b upgrade dev app 2023-05-05 01:57:23 +02:00
Balázs Orbán
3ba510c0e0 forward all set-cookie headers 2023-05-05 01:57:00 +02:00
Balázs Orbán
65fe0ef363 fix imports 2023-05-05 00:14:16 +02:00
Balázs Orbán
587d3666fc Merge branch 'main' into feat/nextjs-auth 2023-05-04 23:59:06 +02:00
Balázs Orbán
8f416b68ec chore: tweaks 2023-05-04 23:58:54 +02:00
Balázs Orbán
e4d568c220 fix redirects 2023-05-04 23:55:36 +02:00
Balázs Orbán
aaff906c68 add readme 2023-05-04 23:52:39 +02:00
Balázs Orbán
8f40883de5 Merge branch 'main' into feat/nextjs-auth 2023-05-04 23:51:00 +02:00
Balázs Orbán
eaf5080721 chore: tweak 2023-05-04 23:50:49 +02:00
Balázs Orbán
601c8c915f Merge branch 'main' into feat/nextjs-auth 2023-05-04 23:42:20 +02:00
Balázs Orbán
e0b5f18c5b chore: skip test for manual release 2023-05-04 23:42:05 +02:00
Balázs Orbán
7fae8744b2 Merge branch 'main' into feat/nextjs-auth 2023-05-04 23:41:33 +02:00
Balázs Orbán
99247ce446 chore: separate manual release job 2023-05-04 23:40:37 +02:00
Balázs Orbán
0afb1797ba Merge branch 'main' into feat/nextjs-auth 2023-05-04 23:25:39 +02:00
Balázs Orbán
d6bc65f0d8 chore: support release any package as experimental 2023-05-04 23:25:29 +02:00
Balázs Orbán
0b80c65a0c update lock file 2023-05-04 22:45:58 +02:00
Balázs Orbán
a7991aed15 revert 2023-05-04 22:38:54 +02:00
Balázs Orbán
c47a2eb7ac Merge branch 'main' into feat/nextjs-auth 2023-05-04 22:22:00 +02:00
Balázs Orbán
6f5a50313f chore: use @ts-ignore 2023-05-04 22:21:36 +02:00
Balázs Orbán
3c23a4f4e2 add docs 2023-05-04 22:14:15 +02:00
Balázs Orbán
52c04fe89e update turbo 2023-05-04 22:11:43 +02:00
Balázs Orbán
440317aa2f update turbo 2023-05-04 22:10:39 +02:00
Balázs Orbán
18a4e8b255 update turbo 2023-05-04 22:09:20 +02:00
Balázs Orbán
c411c6f5dc update gitignore 2023-05-04 22:06:08 +02:00
Balázs Orbán
46f622a5b4 Merge branch 'main' into feat/nextjs-auth 2023-05-04 22:05:27 +02:00
Balázs Orbán
1b984f09ab fix docs references 2023-05-04 21:51:11 +02:00
Balázs Orbán
fbc1ed857c space 2023-05-04 21:43:43 +02:00
Balázs Orbán
0d6ad6beb6 update lock file 2023-05-04 21:43:15 +02:00
Balázs Orbán
b972742171 Update settings.json 2023-05-04 20:42:31 +01:00
Balázs Orbán
01d6f86538 Update .prettierignore 2023-05-04 20:42:16 +01:00
Balázs Orbán
bf89d9fabb re-add next-auth 4 2023-05-04 21:41:36 +02:00
Balázs Orbán
90b01c4613 Merge branch 'feat/nextjs-auth' of github.com:nextauthjs/next-auth into feat/nextjs-auth 2023-05-04 21:39:40 +02:00
Balázs Orbán
47794e68cc move back to @auth/nextjs 2023-05-04 21:39:37 +02:00
Balázs Orbán
0c6b8581a7 revert 2023-05-04 20:30:08 +01:00
Balázs Orbán
7ece5a0a9d chore: fix framework builds 2023-05-04 21:26:53 +02:00
Balázs Orbán
828e38c976 ignore type errors 2023-05-04 21:19:11 +02:00
Balázs Orbán
47d4a3f80f mark import as type 2023-05-04 20:52:20 +02:00
Balázs Orbán
14f9388148 remove unnecessary type import 2023-05-04 20:30:23 +02:00
Balázs Orbán
46659f04b7 update deps 2023-05-04 19:55:45 +02:00
Balázs Orbán
fc4abd174f Merge branch 'main' into feat/nextjs-auth 2023-05-04 10:58:03 +02:00
Balázs Orbán
ebefd25bd6 improve docs 2023-05-04 10:57:42 +02:00
Balázs Orbán
e3bdb38df2 fix(docs): remove extra heading
Fixes #7426
2023-05-03 12:40:30 +02:00
Balázs Orbán
da9ce95677 add redirects 2023-05-01 14:18:56 +02:00
Balázs Orbán
8c99f5c9cf Merge branch 'main' into feat/nextjs-auth 2023-05-01 13:49:29 +02:00
Balázs Orbán
92a0fc42fa fix: allow handling OAuth callback error response
related #7407
2023-05-01 13:49:17 +02:00
Balázs Orbán
62e2ad115c chore: type fixes 2023-05-01 13:46:23 +02:00
Balázs Orbán
5551c4f147 add more providers 2023-05-01 13:42:35 +02:00
Balázs Orbán
e2ef07688c Merge branch 'main' into feat/nextjs-auth 2023-05-01 13:22:31 +02:00
Balázs Orbán
542c35d729 fix: loosen profile types 2023-05-01 13:22:16 +02:00
Balázs Orbán
e62fa3a0af infer issuer 2023-05-01 13:21:42 +02:00
Balázs Orbán
771e993ce9 fix import 2023-05-01 13:03:49 +02:00
Balázs Orbán
c4a15ae3dd bump versions 2023-05-01 12:56:32 +02:00
Balázs Orbán
80d1a8fd70 mention NA5 status in docs 2023-05-01 12:54:56 +02:00
Balázs Orbán
54876744fe Merge branch 'feat/nextjs-auth' into feat/nextjs-auth-example-app 2023-05-01 12:52:34 +02:00
Balázs Orbán
28cbb3aac5 rename @auth/nextjs to next-auth 2023-05-01 12:41:12 +02:00
Balázs Orbán
ac0ca51278 Merge branch 'main' into feat/nextjs-auth 2023-05-01 11:32:56 +02:00
Balázs Orbán
5400645221 chore: improve errors, add more docs (#7415)
* JWT Token -> JWT

* document some errors

* improve errors, docs
2023-05-01 10:32:20 +01:00
Balázs Orbán
d739e8e04e feat(adapters): add Account mapping before database write (#7369)
* feat: map Account before saving to database

* document `acconut()`, explain default behaviour

* generate `expires_at` based on `expires_in`

Fixes #6538

* rename

* strip undefined on `defaultProfile`

* don't forward defaults to account callback

* improve internal namings, types, docs
2023-04-30 12:25:26 +01:00
Victor
c2eb9b3ad4 fix(docs): fix default maxAge formula (#7406) 2023-04-30 10:34:05 +02:00
Balázs Orbán
4f54840014 bump to next@canary 2023-04-28 12:59:48 +02:00
Balázs Orbán
d938333750 Merge branch 'main' into feat/nextjs-auth 2023-04-28 12:29:49 +02:00
ndom91
d837dfaea1 fix: app router style updates for example app 2023-04-27 14:17:03 +02:00
ndom91
a99f4bd8c6 fix: remove dependency on 'next-auth' from example package.json 2023-04-27 13:39:06 +02:00
Balázs Orbán
a96b8597b1 Merge branch 'main' into feat/nextjs-auth 2023-04-27 11:07:20 +02:00
Balázs Orbán
29ce4cb4d4 fix imports 2023-04-27 10:58:02 +02:00
Balázs Orbán
da40242e48 bump next 2023-04-27 10:57:56 +02:00
Balázs Orbán
3f211e7ad0 Merge branch 'main' into feat/nextjs-auth 2023-04-27 10:14:56 +02:00
ndom91
5f369b0981 fix: update README.md to '@auth/nextjs' 2023-04-26 16:25:52 +02:00
ndom91
4a056c774f fix: rm 'pages' dir 2023-04-26 16:25:41 +02:00
ndom91
038b9bccad fix: remove unnecessary header links in example app 2023-04-25 19:05:33 +02:00
ndom91
dfb20849c5 fix: pages/server page on dev and example app 2023-04-25 19:05:11 +02:00
ndom91
4a7a7ab757 fix: minor .env.local.example update 2023-04-25 18:44:05 +02:00
ndom91
f94b604397 fix: move pages to backup position in example app 2023-04-25 18:41:28 +02:00
ndom91
535f9276f6 feat: move nextjs example app to new primitives 2023-04-25 18:37:23 +02:00
Balázs Orbán
cd2872de89 Merge branch 'main' into feat/nextjs-auth 2023-04-24 12:00:11 +03:00
Balázs Orbán
2de2dc9bb3 set version 2023-04-21 12:38:15 +02:00
Balázs Orbán
6f96004d75 tweak docs 2023-04-21 12:37:21 +02:00
Balázs Orbán
f834bc2a99 mark getCsrfToken as internal 2023-04-21 12:35:19 +02:00
Balázs Orbán
551dcbd2d5 show client api in sidebar 2023-04-21 12:34:04 +02:00
Balázs Orbán
316b344930 remove gitignored file 2023-04-21 12:31:07 +02:00
Balázs Orbán
97ff6406cb Merge branch 'main' into feat/nextjs-auth 2023-04-21 12:30:48 +02:00
Balázs Orbán
1b9559fbb1 add docs, fix types 2023-04-21 13:21:55 +03:00
Balázs Orbán
27864eea2f handle JSX 2023-04-21 11:46:16 +02:00
Balázs Orbán
e5f18e3266 add @auth/nextjs/client 2023-04-21 11:46:08 +02:00
Balázs Orbán
47eec2c498 update pages 2023-04-21 11:45:05 +02:00
Balázs Orbán
77bba4ada7 App Router updates 2023-04-21 11:40:46 +02:00
Balázs Orbán
f081fcd31d remove supabase pages 2023-04-21 11:39:17 +02:00
Balázs Orbán
5f079930cc update imports 2023-04-21 11:38:45 +02:00
Balázs Orbán
4cc4b45e52 bump package versions 2023-04-21 11:37:37 +02:00
Balázs Orbán
c0cfb13c88 Merge branch 'main' into feat/nextjs-auth 2023-04-20 11:51:37 +02:00
Balázs Orbán
537112a306 Merge branch 'main' into feat/nextjs-auth 2023-04-19 10:57:14 +02:00
Balázs Orbán
6663003c7c remove crypto polyfill 2023-04-18 13:57:16 +02:00
Balázs Orbán
68559941a5 support __Secure session token cookie 2023-04-18 13:50:47 +02:00
Balázs Orbán
cec1fd753e ignore next-2 2023-04-18 10:40:26 +02:00
Balázs Orbán
c97c40c9cb fix types, default envs 2023-04-18 10:29:06 +02:00
Balázs Orbán
defc2233be update session expiry 2023-04-14 13:50:12 +02:00
Balázs Orbán
e0450c9d52 remove log 2023-04-14 12:19:28 +02:00
Balázs Orbán
04021c6d47 respect AUTH_SECRET 2023-04-14 12:14:17 +02:00
Balázs Orbán
210d28b6b0 add lib to package files 2023-04-14 12:14:07 +02:00
Balázs Orbán
fcd9bfc6f8 update node types 2023-04-14 12:01:56 +02:00
Balázs Orbán
0a027cf35d update deps/lock file 2023-04-14 11:58:32 +02:00
Balázs Orbán
47ac2e94ce document source code 2023-04-14 11:43:26 +02:00
Balázs Orbán
30e3672708 generate docs 2023-04-14 11:42:47 +02:00
Balázs Orbán
635a9b0c50 update dev app 2023-04-14 11:41:15 +02:00
Balázs Orbán
510b9764f5 add session rotation 2023-04-13 14:44:06 +02:00
Balázs Orbán
7329725702 update deps 2023-04-13 14:43:48 +02:00
Balázs Orbán
23ea9428e0 update dev app 2023-04-13 14:43:25 +02:00
Balázs Orbán
319f7af866 Merge branch 'main' into feat/nextjs-auth 2023-04-12 12:41:41 +02:00
Balázs Orbán
58be169b10 update dev app 2023-04-07 12:51:41 +02:00
Balázs Orbán
c87fdd9060 add implicit env reading, simplified API 2023-04-07 12:51:34 +02:00
Balázs Orbán
28263f52bd Merge branch 'main' into feat/nextjs-auth 2023-04-07 12:39:10 +02:00
Balázs Orbán
27869b70b8 Merge branch 'main' into feat/nextjs-auth 2023-04-01 14:39:34 +02:00
Balázs Orbán
7af7ca4d1c chore: bump turbo and pnpm 2023-03-31 15:50:44 +02:00
Balázs Orbán
30948fbada chore: update configs, dependencies 2023-03-30 18:13:07 +02:00
351 changed files with 14955 additions and 20561 deletions

View File

@@ -11,7 +11,7 @@ body:
### Important :exclamation:
_Providing incorrect/insufficient information or skipping steps to reproduce the issue will result in closing the issue and/or converting to a discussion without further explanation._
_Providing incorrect/insufficient information or skipping steps to reproduce the issue may result in closing the issue or converting to a discussion without further explanation._
If you have a generic question specific to your project, it is best asked in Discussions under the [Questions category](https://github.com/nextauthjs/next-auth/discussions/new?category=Questions)
# Let's wait with this until adoption in other frameworks.

View File

@@ -31,17 +31,13 @@ body:
- "Authentik"
- "Azure Active Directory"
- "Azure Active Directory B2C"
- "Azure DevOps"
- "Battlenet"
- "Beyond Identity"
- "Box"
- "Bungie"
- "ClickUp"
- "Cognito"
- "Coinbase"
- "Descope"
- "Discord"
- "Dribbble"
- "Dropbox"
- "EVE Online"
- "Facebook"
@@ -60,7 +56,6 @@ body:
- "LinkedIn"
- "Mailchimp"
- "Mail.ru"
- "Mastodon"
- "Medium"
- "Naver"
- "Netlify"
@@ -76,7 +71,6 @@ body:
- "Slack"
- "Spotify"
- "Strava"
- "Tiktok"
- "Todoist"
- "Trakt"
- "Twitch"

View File

@@ -21,22 +21,20 @@ body:
multiple: true
options:
- "Custom adapter"
- "@auth/dgraph-adapter"
- "@auth/drizzle-adapter"
- "@auth/dynamodb-adapter"
- "@auth/fauna-adapter"
- "@auth/firebase-adapter"
- "@auth/kysely-adapter"
- "@auth/mikro-orm-adapter"
- "@auth/mongodb-adapter"
- "@auth/neo4j-adapter"
- "@auth/pouchdb-adapter"
- "@auth/prisma-adapter"
- "@auth/sequelize-adapter"
- "@auth/supabase-adapter"
- "@auth/typeorm-adapter"
- "@auth/upstash-redis-adapter"
- "@auth/xata-adapter"
- "@next-auth/dgraph-adapter"
- "@next-auth/dynamodb-adapter"
- "@next-auth/fauna-adapter"
- "@next-auth/firebase-adapter"
- "@next-auth/mikro-orm-adapter"
- "@next-auth/mongodb-adapter"
- "@next-auth/neo4j-adapter"
- "@next-auth/pouchdb-adapter"
- "@next-auth/prisma-adapter"
- "@next-auth/sequelize-adapter"
- "@next-auth/supabase-adapter"
- "@next-auth/typeorm-legacy-adapter"
- "@next-auth/upstash-redis-adapter"
- "@next-auth/xata-adapter"
validations:
required: true
- type: textarea

View File

@@ -1,49 +1,43 @@
# https://github.com/github/issue-labeler#basic-examples
dgraph:
- "@auth/dgraph-adapter"
drizzle:
- "@auth/drizzle-adapter"
- "@next-auth/dgraph-adapter"
dynamodb:
- "@auth/dynamodb-adapter"
- "@next-auth/dynamodb-adapter"
fauna:
- "@auth/fauna-adapter"
- "@next-auth/fauna-adapter"
firebase:
- "@auth/firebase-adapter"
kysely:
- "@auth/kysely-adapter"
- "@next-auth/firebase-adapter"
mikro-orm:
- "@auth/mikro-orm-adapter"
- "@next-auth/mikro-orm-adapter"
mongodb:
- "@auth/mongodb-adapter"
- "@next-auth/mongodb-adapter"
neo4j:
- "@auth/neo4j-adapter"
- "@next-auth/neo4j-adapter"
pouchdb:
- "@auth/pouchdb-adapter"
- "@next-auth/pouchdb-adapter"
prisma:
- "@auth/prisma-adapter"
- "@next-auth/prisma-adapter"
sequelize:
- "@auth/sequelize-adapter"
- "@next-auth/sequelize-adapter"
supabase:
- "@auth/supabase-adapter"
- "@next-auth/supabase-adapter"
typeorm:
- "@auth/typeorm-adapter"
typeorm-legacy:
- "@next-auth/typeorm-legacy-adapter"
upstash-redis:
- "@auth/upstash-redis-adapter"
- "@next-auth/upstash-redis-adapter"
xata:
- "@auth/xata-adapter"
- "@next-auth/xata-adapter"

View File

@@ -15,13 +15,12 @@ neo4j: ["packages/adapter-neo4j/**/*"]
playgrounds: ["apps/playgrounds/**/*"]
pouchdb: ["packages/adapter-pouchdb/**/*"]
prisma: ["packages/adapter-prisma/**/*"]
kysely: ["packages/adapter-kysely/**/*"]
providers: ["packages/core/src/providers/**/*"]
sequelize: ["packages/adapter-sequelize/**/*"]
solidjs: ["packages/frameworks-solid-start/**/*"]
supabase: ["packages/adapter-supabase/**/*"]
svelte: ["packages/frameworks-sveltekit/**/*"]
test: ["**test**/*"]
typeorm: ["packages/adapter-typeorm/**/*"]
typeorm-legacy: ["packages/adapter-typeorm-legacy/**/*"]
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
xata: ["packages/adapter-xata/**/*"]

View File

@@ -11,54 +11,21 @@ on:
# TODO: Support latest releases
workflow_dispatch:
inputs:
name:
name:
type: choice
description: Package name (npm)
options:
- "@auth/core"
- "@auth/dgraph-adapter"
- "@auth/drizzle-adapter"
- "@auth/dynamodb-adapter"
- "@auth/fauna-adapter"
- "@auth/firebase-adapter"
- "@auth/mikro-orm-adapter"
- "@auth/mongodb-adapter"
- "@auth/neo4j-adapter"
- "@auth/pouchdb-adapter"
- "@auth/prisma-adapter"
- "@auth/sequelize-adapter"
- "@auth/supabase-adapter"
- "@auth/typeorm-adapter"
- "@auth/upstash-redis-adapter"
- "@auth/xata-adapter"
- "next-auth"
- "@auth/nextjs"
- "@auth/core"
- "next-auth"
# TODO: Infer from package name
path:
type: choice
description: Directory name (packages/*)
options:
- "core"
- "frameworks-nextjs"
- "adapter-dgraph"
- "adapter-drizzle"
- "adapter-dynamodb"
- "adapter-fauna"
- "adapter-firebase"
- "adapter-mikro-orm"
- "adapter-mongodb"
- "adapter-neo4j"
- "adapter-pouchdb"
- "adapter-prisma"
- "adapter-sequelize"
- "adapter-supabase"
- "adapter-typeorm"
- "adapter-upstash-redis"
- "adapter-xata"
- "next-auth"
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
FORCE_COLOR: true
- "frameworks-nextjs"
- "core"
- "next-auth"
jobs:
test:
@@ -75,17 +42,16 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Run tests
run: pnpm test
timeout-minutes: 15
env:
UPSTASH_REDIS_URL: ${{ secrets.UPSTASH_REDIS_URL }}
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
# - name: Run E2E tests
# if: github.repository == 'nextauthjs/next-auth'
# run: pnpm e2e
@@ -94,7 +60,7 @@ jobs:
# AUTH0_USERNAME: ${{ secrets.AUTH0_USERNAME }}
# AUTH0_PASSWORD: ${{ secrets.AUTH0_PASSWORD }}
# TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
# TURBO_TEAM: ${{ vars.TURBO_TEAM }}
# TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
# - name: Upload E2E artifacts
# if: github.repository == 'nextauthjs/next-auth'
# uses: actions/upload-artifact@v3
@@ -125,7 +91,6 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Publish to npm and GitHub
@@ -150,7 +115,6 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Determine version
@@ -189,7 +153,6 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: 18
cache: "pnpm"
- name: Install dependencies
run: pnpm install
- name: Determine version
@@ -199,7 +162,6 @@ jobs:
PACKAGE_PATH: ${{ github.event.inputs.path }}
- name: Publish to npm
run: |
pnpm build
cd packages/$PACKAGE_PATH
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc
pnpm publish --no-git-checks --access public --tag experimental

11
.gitignore vendored
View File

@@ -6,8 +6,6 @@
.env.development.local
.env.test.local
.env.production.local
packages/*/.npmrc
npm-debug.log*
yarn-debug.log*
@@ -40,7 +38,6 @@ packages/next-auth/next
packages/*/*.js
packages/*/*.d.ts
packages/*/*.d.ts.map
packages/*/lib
# Development app
apps/dev/src/css
@@ -67,7 +64,6 @@ packages/adapter-prisma/prisma/dev.db
packages/adapter-prisma/prisma/migrations
db.sqlite
packages/adapter-supabase/supabase/.branches
packages/adapter-drizzle/.drizzle
# Tests
coverage
@@ -89,7 +85,10 @@ packages/core/providers
packages/core/src/lib/pages/styles.ts
docs/docs/reference/core
docs/docs/reference/sveltekit
docs/docs/reference/nextjs
# Next.js
packages/frameworks-nextjs/lib
# SvelteKit
packages/frameworks-sveltekit/index.*
@@ -100,7 +99,5 @@ packages/frameworks-sveltekit/vite.config.js.timestamp-*
packages/frameworks-sveltekit/vite.config.ts.timestamp-*
# Adapters
docs/docs/reference/adapter
## Drizzle migration folder
.drizzle
docs/docs/reference/adapter

153
README.md
View File

@@ -1,153 +0,0 @@
<p align="center">
<br/>
<a href="https://authjs.dev" target="_blank"><img width="96px" src="https://authjs.dev/img/logo/logo-sm.png" /></a>
<h3 align="center">Auth.js</h3>
<p align="center">Authentication for the Web.</p>
<p align="center">Open Source. Full Stack. Own Your Data.</p>
<p align="center" style="align: center;">
<a href="https://npm.im/@auth/prisma-adapter">
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
</a>
<a href="https://www.npmtrends.com/next-auth">
<img src="https://img.shields.io/npm/dm/next-auth?style=flat-square" alt="Downloads" />
</a>
<a href="https://github.com/nextauthjs/next-auth/stargazers">
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
</a>
<a href="https://www.npmjs.com/package/next-auth">
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?label=latest&style=flat-square" alt="Github Stable Release" />
</a>
</p>
</p>
Auth.js is a set of open-source packages that are built on Web Standard APIs for authentication in modern applications with any framework on any platform in any JS runtime.
See [authjs.dev](https://authjs.dev) for our framework-specific libraries, or check out [next-auth.js.org](https://next-auth.js.org) for `next-auth` (Next.js).
## Features
### Flexible and easy to use
- Designed to work with any OAuth service, it supports 2.0+, OIDC
- Built-in support for [many popular sign-in services](https://github.com/nextauthjs/next-auth/tree/main/packages/core/src/providers)
- Email/Passwordless authentication
- Bring Your Database - or none! - stateless authentication with any backend (Active Directory, LDAP, etc.)
- Runtime-agnostic, runs anywhere! (Vercel Edge Functions, Node.js, Serverless, etc.)
### Own your data
Auth.js can be used with or without a database.
- An open-source solution that allows you to keep control of your data
- Built-in support for [MySQL, MariaDB, Postgres, Microsoft SQL Server, MongoDB, SQLite, etc.](https://adapters.authjs.dev)
- Works great with databases from popular hosting providers
### Secure by default
- Promotes the use of passwordless sign-in mechanisms
- Designed to be secure by default and encourage best practices for safeguarding user data
- Uses Cross-Site Request Forgery (CSRF) Tokens on POST routes (sign in, sign out)
- Default cookie policy aims for the most restrictive policy appropriate for each cookie
- When JSON Web Tokens are used, they are encrypted by default (JWE) with A256GCM
- Features tab/window syncing and session polling to support short-lived sessions
- Attempts to implement the latest guidance published by [Open Web Application Security Project](https://owasp.org)
Advanced configuration allows you to define your routines to handle controlling what accounts are allowed to sign in, for encoding and decoding JSON Web Tokens and to set custom cookie security policies and session properties, so you can control who can sign in and how often sessions have to be re-validated.
### TypeScript
Auth.js libraries are written with type safety in mind. [Check out the docs](https://authjs.dev/getting-started/typescript) for more information.
## Security
If you think you have found a vulnerability (or are not sure) in Auth.js or any of the related packages (i.e. Adapters), we ask you to read our [Security Policy](https://authjs.dev/security) to reach out responsibly. Please do not open Pull Requests/Issues/Discussions before consulting with us.
## Acknowledgments
[Auth.js is made possible thanks to all of its contributors.](https://authjs.dev/contributors)
<a href="https://github.com/nextauthjs/next-auth/graphs/contributors">
<img width="500px" src="https://contrib.rocks/image?repo=nextauthjs/next-auth" />
</a>
<div>
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss"></a>
</div>
### Support
We have an [OpenCollective](https://opencollective.com/nextauth) for individuals and companies looking to contribute financially to the project!
<!--sponsors start-->
<table>
<tbody>
<tr>
<td align="center" valign="top">
<a href="https://vercel.com" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/14985020?v=4" alt="Vercel Logo" />
</a><br />
<div>Vercel</div><br />
<sub>🥉 Bronze Financial Sponsor <br /> ☁️ Infrastructure Support</sub>
</td>
<td align="center" valign="top">
<a href="https://prisma.io" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/17219288?v=4" alt="Prisma Logo" />
</a><br />
<div>Prisma</div><br />
<sub>🥉 Bronze Financial Sponsor</sub>
</td>
<td align="center" valign="top">
<a href="https://clerk.com" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/49538330?s=200&v=4" alt="Clerk Logo" />
</a><br />
<div>Clerk</div><br />
<sub>🥉 Bronze Financial Sponsor</sub>
</td>
<td align="center" valign="top">
<a href="https://lowdefy.com" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/47087496?s=200&v=4" alt="Lowdefy Logo" />
</a><br />
<div>Lowdefy</div><br />
<sub>🥉 Bronze Financial Sponsor</sub>
</td>
<td align="center" valign="top">
<a href="https://workos.com" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/47638084?s=200&v=4" alt="WorkOS Logo" />
</a><br />
<div>WorkOS</div><br />
<sub>🥉 Bronze Financial Sponsor</sub>
</td>
<td align="center" valign="top">
<a href="https://www.descope.com" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/97479186?v=4" alt="Descope Logo" />
</a><br />
<div>Descope</div><br />
<sub>🥉 Bronze Financial Sponsor</sub>
</td>
<td align="center" valign="top">
<a href="https://checklyhq.com" target="_blank">
<img width="128px" src="https://avatars.githubusercontent.com/u/25982255?v=4" alt="Checkly Logo" />
</a><br />
<div>Checkly</div><br />
<sub>☁️ Infrastructure Support</sub>
</td>
<td align="center" valign="top">
<a href="https://superblog.ai/" target="_blank">
<img width="128px" src="https://d33wubrfki0l68.cloudfront.net/cdc4a3833bd878933fcc131655878dbf226ac1c5/10cd6/images/logo_bolt_small.png" alt="superblog Logo" />
</a><br />
<div>superblog</div><br />
<sub>☁️ Infrastructure Support</sub>
</td>
</tr><tr></tr>
</tbody>
</table>
<br />
<!--sponsors end-->
## Contributing
We're open to all community contributions! If you'd like to contribute in any way, please first read
our [Contributing Guide](https://github.com/nextauthjs/.github/blob/main/CONTRIBUTING.md).
## License
ISC

1
README.md Symbolic link
View File

@@ -0,0 +1 @@
packages/next-auth/README.md

View File

@@ -13,9 +13,6 @@ AUTH0_ID=
AUTH0_SECRET=
AUTH0_ISSUER=
DESCOPE_ID=
DESCOPE_SECRET=
KEYCLOAK_ID=
KEYCLOAK_SECRET=
KEYCLOAK_ISSUER=

View File

@@ -3,4 +3,4 @@
This folder contains a Next.js app using NextAuth.js for local development. See the following section on how to start:
[Setting up local environment
](https://github.com/nextauthjs/.github/blob/main/CONTRIBUTING.md#setting-up-local-environment)
](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md#setting-up-local-environment)

View File

@@ -14,10 +14,10 @@
},
"license": "ISC",
"dependencies": {
"@auth/fauna-adapter": "workspace:*",
"@auth/prisma-adapter": "workspace:*",
"@auth/supabase-adapter": "workspace:*",
"@auth/typeorm-adapter": "workspace:*",
"@next-auth/fauna-adapter": "workspace:*",
"@next-auth/prisma-adapter": "workspace:*",
"@next-auth/supabase-adapter": "workspace:*",
"@next-auth/typeorm-legacy-adapter": "workspace:*",
"@prisma/client": "^3",
"@supabase/supabase-js": "^2.0.5",
"faunadb": "^4",

View File

@@ -37,22 +37,22 @@ import WorkOS from "next-auth/providers/workos"
// // Prisma
// import { PrismaClient } from "@prisma/client"
// import { PrismaAdapter } from "@auth/prisma-adapter"
// 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 "@auth/fauna-adapter"
// 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 { TypeORMAdapter } from "@auth/typeorm-adapter"
// const adapter = TypeORMAdapter({
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
// const adapter = TypeORMLegacyAdapter({
// type: "sqlite",
// name: "next-auth-test-memory",
// database: "./typeorm/dev.db",
@@ -60,7 +60,7 @@ import WorkOS from "next-auth/providers/workos"
// })
// // Supabase
// import { SupabaseAdapter } from "@auth/supabase-adapter"
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
// const adapter = SupabaseAdapter({
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
@@ -78,130 +78,45 @@ export const authOptions: NextAuthOptions = {
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: "",
}
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,
}),
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",
}),
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,
}),
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,
}),
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,
}),
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,
}),
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,
}),
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
],
}

View File

@@ -22,9 +22,6 @@ BEYOND_IDENTITY_CLIENT_ID=
BEYOND_IDENTITY_CLIENT_SECRET=
BEYOND_IDENTITY_ISSUER=
DESCOPE_ID=
DESCOPE_SECRET=
GITHUB_ID=
GITHUB_SECRET=
@@ -59,10 +56,6 @@ WIKIMEDIA_SECRET=
YANDEX_ID=
YANDEX_SECRET=
# ClickUp OAuth. https://clickup.com/api/
CLICK_UP_ID=
CLICK_UP_SECRET=
# Example configuration for a Gmail account (will need SMTP enabled)
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
EMAIL_FROM=user@gmail.com

View File

@@ -2,4 +2,3 @@ node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
dbschema/edgeql-js

View File

@@ -0,0 +1,3 @@
import { handlers } from "auth"
export const { GET, POST } = handlers
export const runtime = "edge"

View File

@@ -0,0 +1,10 @@
import { auth } from "auth"
import { NextResponse } from "next/server"
export const GET = auth(function GET(req) {
if (req.auth) {
return NextResponse.json(req.auth)
}
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
})

View File

@@ -0,0 +1,10 @@
"use client"
import { useEffect } from "react"
export default function Client({ session }: any) {
useEffect(() => {
console.log(window.location)
})
return <div>{JSON.stringify(session)}</div>
}

View File

@@ -0,0 +1,3 @@
export default function Page() {
return <h1>This page is protected.</h1>
}

View File

@@ -1,12 +1,54 @@
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
import { auth } from "auth"
import Footer from "components/footer"
import { Header } from "components/header"
import { cookies, headers } from "next/headers"
import styles from "components/header.module.css"
import "./styles.css"
export default function RootLayout(props: { children: React.ReactNode }) {
return (
<html>
<head></head>
<body>{children}</body>
<body>
{/* @ts-expect-error */}
<AppHeader />
<main>{props.children}</main>
<Footer />
</body>
</html>
)
}
function SignIn({ id, ...props }: any) {
const $cookies = cookies()
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
const action = id ? `/api/auth/signin/${id}` : "/api/auth/signin"
return (
<form action={action} method="post">
<button {...props} />
<input type="hidden" name="csrfToken" value={csrfToken} />
</form>
)
}
function SignOut(props: any) {
const $cookies = cookies()
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
return (
<form action="/api/auth/signout" method="post">
<button {...props} />
<input type="hidden" name="csrfToken" value={csrfToken} />
</form>
)
}
export async function AppHeader() {
const session = await auth(headers())
return (
<Header
session={session}
signIn={<SignIn className={styles.buttonPrimary}>Sign in</SignIn>}
signOut={<SignOut className={styles.button}>Sign out</SignOut>}
/>
)
}

View File

@@ -0,0 +1,17 @@
import { auth } from "auth"
import { headers } from "next/headers"
import Client from "./client"
export default async function Page() {
const session = await auth(headers())
return (
<>
<Client session={session} />
<h1>NextAuth.js Example</h1>
<p>
This is an example site to demonstrate how to use{" "}
<a href="https://nextjs.authjs.dev">NextAuth.js</a> for authentication.
</p>
</>
)
}

View File

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

View File

@@ -6,7 +6,7 @@ body {
max-width: 680px;
margin: 0 auto;
background: #fff;
color: #333;
color: var(--color-text);
}
li,

31
apps/dev/nextjs/auth.ts Normal file
View File

@@ -0,0 +1,31 @@
import NextAuth from "@auth/nextjs"
import Auth0 from "@auth/core/providers/auth0"
import Facebook from "@auth/core/providers/facebook"
import GitHub from "@auth/core/providers/github"
import Google from "@auth/core/providers/google"
import Twitter from "@auth/core/providers/twitter"
import Credentials from "@auth/core/providers/credentials"
export const { handlers, auth, getServerSession } = NextAuth({
debug: true,
providers: [
GitHub,
Auth0,
Facebook,
Google,
Twitter,
Credentials({
credentials: { password: { label: "Password", type: "password" } },
authorize(c) {
if (c.password !== "password") return null
return { id: "test", name: "Test User", email: "test@example.com" }
},
}),
],
callbacks: {
async authorized({ request: { nextUrl }, auth }) {
if (nextUrl.pathname === "/dashboard") return !!auth.user
return true
},
},
})

View File

@@ -1,4 +1,4 @@
import { signIn } from "next-auth/react"
import { signIn } from "@auth/nextjs/react"
export default function AccessDenied() {
return (

View File

@@ -1,6 +1,6 @@
import Link from "next/link"
import styles from "./footer.module.css"
import packageJSON from "package.json"
import packageJSON from "@auth/nextjs/package.json"
export default function Footer() {
return (

View File

@@ -1,89 +0,0 @@
import Link from "next/link"
import { useSession } from "next-auth/react"
import styles from "./header.module.css"
// The approach used in this component shows how to built a sign in and sign out
// component that works on pages which support both client and server side
// rendering, and avoids any flash incorrect content on initial page load.
export default function Header() {
const { data: session, status } = useSession()
return (
<header>
<noscript>
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
</noscript>
<div className={styles.signedInStatus}>
<p
className={`nojs-show ${
!session && status === "loading" ? styles.loading : styles.loaded
}`}
>
{!session && (
<>
<span className={styles.notSignedInText}>
You are not signed in
</span>
<a href="/api/auth/signin" className={styles.buttonPrimary}>
Sign in
</a>
</>
)}
{session && (
<>
{session.user.image && (
<img src={session.user.image} className={styles.avatar} />
)}
<span className={styles.signedInText}>
<small>Signed in as</small>
<br />
<strong>{session.user.email} </strong>
{session.user.name ? `(${session.user.name})` : null}
</span>
<a href="/api/auth/signout" className={styles.button}>
Sign out
</a>
</>
)}
</p>
</div>
<nav>
<ul className={styles.navItems}>
<li className={styles.navItem}>
<Link href="/">Home</Link>
</li>
<li className={styles.navItem}>
<Link href="/client">Client</Link>
</li>
<li className={styles.navItem}>
<Link href="/server">Server</Link>
</li>
<li className={styles.navItem}>
<Link href="/protected">Protected</Link>
</li>
<li className={styles.navItem}>
<Link href="/protected-ssr">Protected(SSR)</Link>
</li>
<li className={styles.navItem}>
<Link href="/api-example">API</Link>
</li>
<li className={styles.navItem}>
<Link href="/credentials">Credentials</Link>
</li>
<li className={styles.navItem}>
<Link href="/email">Email</Link>
</li>
<li className={styles.navItem}>
<Link href="/middleware-protected">Middleware protected</Link>
</li>
<li className={styles.navItem}>
<Link href="/supabase-client-rls">Supabase RLS</Link>
</li>
<li className={styles.navItem}>
<Link href="/supabase-ssr">Supabase RLS(SSR)</Link>
</li>
</ul>
</nav>
</header>
)
}

View File

@@ -1,6 +1,7 @@
/* Set min-height to avoid page reflow while session loading */
.signedInStatus {
display: block;
display: flex;
align-items: center;
min-height: 4rem;
width: 100%;
}
@@ -25,16 +26,13 @@
.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;
flex: 1;
}
.signedInText {
@@ -47,6 +45,7 @@
float: left;
height: 2.8rem;
width: 2.8rem;
margin-right: 1rem;
background-color: white;
background-size: cover;
background-repeat: no-repeat;
@@ -54,10 +53,11 @@
.button,
.buttonPrimary {
float: right;
margin-right: -0.4rem;
justify-self: end;
font-weight: 500;
border-radius: 0.3rem;
border: none;
font-weight: bold;
cursor: pointer;
font-size: 1rem;
line-height: 1.4rem;

View File

@@ -0,0 +1,55 @@
import Link from "next/link"
import styles from "./header.module.css"
export function Header({ session, signIn, signOut }: any) {
return (
<header>
<div className={styles.signedInStatus}>
{!session && (
<>
<span className={styles.notSignedInText}>
You are not signed in
</span>
{signIn}
</>
)}
{session && (
<>
{session.user.picture && (
<img src={session.user.picture} className={styles.avatar} />
)}
<span className={styles.signedInText}>
<small>Signed in as</small>
<br />
<strong>{session.user.email} </strong>
{session.user.name ? `(${session.user.name})` : null}
</span>
{signOut}
</>
)}
</div>
<nav>
<ul className={styles.navItems}>
<li className={styles.navItem}>
<Link href="/">Home (app)</Link>
</li>
<li className={styles.navItem}>
<Link href="/dashboard">Dashboard (app)</Link>
</li>
<li className={styles.navItem}>
<Link href="/policy">Policy (pages)</Link>
</li>
<li className={styles.navItem}>
<Link href="/credentials">Credentials (pages)</Link>
</li>
<li className={styles.navItem}>
<Link href="/protected-ssr">getServerSideProps (pages)</Link>
</li>
<li className={styles.navItem}>
<Link href="/api/examples/protected">API Route (pages)</Link>
</li>
</ul>
</nav>
</header>
)
}

View File

@@ -1,12 +0,0 @@
import Header from "components/header"
import Footer from "components/footer"
export default function Layout({ children }) {
return (
<>
<Header />
<main>{children}</main>
<Footer />
</>
)
}

View File

@@ -1,71 +0,0 @@
module default {
type User {
property name -> str;
required property email -> str {
constraint exclusive;
}
property emailVerified -> datetime;
property image -> str;
multi link accounts := .<user[is Account];
multi link sessions := .<user[is Session];
property createdAt -> datetime {
default := datetime_current();
};
}
type Account {
required property userId := .user.id;
required property type -> str;
required property provider -> str;
required property providerAccountId -> str {
constraint exclusive;
};
property refresh_token -> str;
property access_token -> str;
property expires_at -> int64;
property token_type -> str;
property scope -> str;
property id_token -> str;
property session_state -> str;
required link user -> User {
on target delete delete source;
};
property createdAt -> datetime {
default := datetime_current();
};
constraint exclusive on ((.provider, .providerAccountId))
}
type Session {
required property sessionToken -> str {
constraint exclusive;
}
required property userId := .user.id;
required property expires -> datetime;
required link user -> User {
on target delete delete source;
};
property createdAt -> datetime {
default := datetime_current();
};
}
type VerificationToken {
required property identifier -> str;
required property token -> str {
constraint exclusive;
}
required property expires -> datetime;
property createdAt -> datetime {
default := datetime_current();
};
constraint exclusive on ((.identifier, .token))
}
}
# Disable the application of access policies within access policies
# themselves. This behavior will become the default in EdgeDB 3.0.
# See: https://www.edgedb.com/docs/reference/ddl/access_policies#nonrecursive
using future nonrecursive_access_policies;

View File

@@ -1,2 +0,0 @@
[edgedb]
server-version = "2.6"

View File

@@ -1,45 +1 @@
export { default } from "next-auth/middleware"
export const config = { matcher: ["/middleware-protected"] }
// Other ways to use this middleware
// import withAuth from "next-auth/middleware"
// import { withAuth } from "next-auth/middleware"
// export function middleware(req, ev) {
// return withAuth(req)
// }
// export function middleware(req, ev) {
// return withAuth(req, ev)
// }
// export function middleware(req, ev) {
// return withAuth(req, {
// callbacks: {
// authorized: ({ token }) => !!token,
// },
// })
// }
// export default withAuth(function middleware(req, ev) {
// console.log(req.nextauth.token)
// })
// export default withAuth(
// function middleware(req, ev) {
// console.log(req, ev)
// },
// {
// callbacks: {
// authorized: ({ token }) => token.name === "Balázs Orbán",
// },
// }
// )
// export default withAuth({
// callbacks: {
// authorized: ({ token }) => !!token,
// },
// })
export { auth as default } from "auth"

View File

@@ -15,13 +15,12 @@
"license": "ISC",
"dependencies": {
"@auth/core": "workspace:*",
"@auth/edgedb-adapter": "workspace:*",
"@auth/fauna-adapter": "workspace:*",
"@auth/prisma-adapter": "workspace:*",
"@auth/supabase-adapter": "workspace:*",
"@auth/typeorm-adapter": "workspace:*",
"@auth/nextjs": "workspace:*",
"@next-auth/fauna-adapter": "workspace:*",
"@next-auth/prisma-adapter": "workspace:*",
"@next-auth/supabase-adapter": "workspace:*",
"@next-auth/typeorm-legacy-adapter": "workspace:*",
"@prisma/client": "^3",
"edgedb": "^1.0.1",
"@supabase/supabase-js": "^2.0.5",
"faunadb": "^4",
"next": "13.4.0",
@@ -31,7 +30,6 @@
"react-dom": "^18"
},
"devDependencies": {
"@edgedb/generate": "^0.0.4",
"@playwright/test": "1.29.2",
"@types/jsonwebtoken": "^8.5.5",
"@types/react": "18.0.37",

View File

@@ -1,10 +0,0 @@
import { SessionProvider } from "next-auth/react"
import "./styles.css"
export default function App({ Component, pageProps }) {
return (
<SessionProvider session={pageProps.session}>
<Component {...pageProps} />
</SessionProvider>
)
}

View File

@@ -0,0 +1,39 @@
import {
SessionProvider,
signIn,
signOut,
useSession,
} from "@auth/nextjs/react"
import "./styles.css"
import { Header } from "components/header"
import styles from "components/header.module.css"
import Footer from "components/footer"
export default function App({ Component, pageProps }) {
return (
<SessionProvider session={pageProps.session}>
<PagesHeader />
<Component {...pageProps} />
<Footer />
</SessionProvider>
)
}
function PagesHeader() {
const { data: session } = useSession()
return (
<Header
session={session}
signIn={
<button onClick={() => signIn()} className={styles.buttonPrimary}>
Sign in
</button>
}
signOut={
<button onClick={() => signOut()} className={styles.button}>
Sign out
</button>
}
/>
)
}

View File

@@ -2,15 +2,14 @@ import { Auth, type AuthConfig } from "@auth/core"
// Providers
import Apple from "@auth/core/providers/apple"
// import Asgardeo from "@auth/core/providers/asgardeo"
import Asgardeo from "@auth/core/providers/asgardeo"
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 BeyondIdentity from "@auth/core/providers/beyondidentity"
import BeyondIdentity from "@auth/core/providers/beyondidentity"
import BoxyHQSAML from "@auth/core/providers/boxyhq-saml"
// import Cognito from "@auth/core/providers/cognito"
import Credentials from "@auth/core/providers/credentials"
import Descope from "@auth/core/providers/descope"
import Discord from "@auth/core/providers/discord"
import DuendeIDS6 from "@auth/core/providers/duende-identity-server6"
// import Email from "@auth/core/providers/email"
@@ -39,25 +38,25 @@ import Yandex from "@auth/core/providers/yandex"
import Vk from "@auth/core/providers/vk"
import Wikimedia from "@auth/core/providers/wikimedia"
import WorkOS from "@auth/core/providers/workos"
import ClickUp from '@auth/core/providers/click-up'
// // Prisma
// import { PrismaClient } from "@prisma/client"
// import { PrismaAdapter } from "@auth/prisma-adapter"
// 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 "@auth/fauna-adapter"
// 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 { TypeORMAdapter } from "@auth/typeorm-adapter"
// const adapter = TypeORMAdapter({
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
// const adapter = TypeORMLegacyAdapter({
// type: "sqlite",
// name: "next-auth-test-memory",
// database: "./typeorm/dev.db",
@@ -65,18 +64,12 @@ import ClickUp from '@auth/core/providers/click-up'
// })
// // Supabase
// import { SupabaseAdapter } from "@auth/supabase-adapter"
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
// const adapter = SupabaseAdapter({
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
// })
// // EdgeDB
// import { EdgeDBAdapter } from "@auth/edgedb-adapter"
// import { createHttpClient } from "edgedb"
// const client = createHttpClient()
// const adapter = EdgeDBAdapter(client)
export const authConfig: AuthConfig = {
// adapter,
debug: process.env.NODE_ENV !== "production",
@@ -92,8 +85,8 @@ export const authConfig: AuthConfig = {
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 as string }),
// Asgardeo({ clientId: process.env.ASGARDEO_CLIENT_ID, clientSecret: process.env.ASGARDEO_CLIENT_SECRET, issuer: process.env.ASGARDEO_ISSUER }),
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET }),
Asgardeo({ clientId: process.env.ASGARDEO_CLIENT_ID, clientSecret: process.env.ASGARDEO_CLIENT_SECRET, issuer: process.env.ASGARDEO_ISSUER }),
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
AzureAD({
clientId: process.env.AZURE_AD_CLIENT_ID,
@@ -101,20 +94,19 @@ export const authConfig: AuthConfig = {
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 }),
// BeyondIdentity({
// clientId: process.env.BEYOND_IDENTITY_CLIENT_ID,
// clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET,
// issuer: process.env.BEYOND_IDENTITY_ISSUER,
// }),
BeyondIdentity({
clientId: process.env.BEYOND_IDENTITY_CLIENT_ID,
clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET,
issuer: process.env.BEYOND_IDENTITY_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 }),
Descope({ clientId: process.env.DESCOPE_ID, clientSecret: process.env.DESCOPE_SECRET }),
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, redirectProxyUrl: process.env.AUTH_REDIRECT_PROXY_URL }),
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, redirectProxy: process.env.AUTH_REDIRECT_PROXY_URL }),
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 }),
@@ -123,7 +115,7 @@ export const authConfig: AuthConfig = {
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 }),
Notion({ clientId: process.env.NOTION_ID, clientSecret: process.env.NOTION_SECRET, redirectUri: process.env.NOTION_REDIRECT_URI as string }),
Notion({ clientId: process.env.NOTION_ID, clientSecret: process.env.NOTION_SECRET, redirectUri: process.env.NOTION_REDIRECT_URI }),
// 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 }),
@@ -137,7 +129,6 @@ export const authConfig: AuthConfig = {
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 }),
ClickUp({ clientId: process.env.CLICK_UP_ID, clientSecret: process.env.CLICK_UP_SECRET })
],
// debug: process.env.NODE_ENV !== "production",
}

View File

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

View File

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

View File

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

View File

@@ -1,30 +0,0 @@
// 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 { authOptions } from "../auth/[...nextauth]"
import { createClient } from "@supabase/supabase-js"
export default async (req, res) => {
const session = await unstable_getServerSession(req, res, authOptions)
if (!session)
return res.send(JSON.stringify({ error: "No session!" }, null, 2))
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("*")
res.send(JSON.stringify({ supabaseAccessToken, data, error }, null, 2))
}

View File

@@ -1,67 +0,0 @@
// eslint-disable-next-line no-use-before-define
import * as React from "react"
import { signIn, signOut, useSession } from "next-auth/react"
import Layout from "components/layout"
export default function Page() {
const [response, setResponse] = React.useState(null)
const handleLogin = (options) => async () => {
if (options.redirect) {
return signIn("credentials", options)
}
const response = await signIn("credentials", options)
setResponse(response)
}
const handleLogout = (options) => async () => {
if (options.redirect) {
return signOut(options)
}
const response = await signOut(options)
setResponse(response)
}
const { data: session } = useSession()
if (session) {
return (
<Layout>
<h1>Test different flows for Credentials logout</h1>
<span className="spacing">Default:</span>
<button onClick={handleLogout({ redirect: true })}>Logout</button>
<br />
<span className="spacing">No redirect:</span>
<button onClick={handleLogout({ redirect: false })}>Logout</button>
<br />
<p>Response:</p>
<pre style={{ background: "#eee", padding: 16 }}>
{JSON.stringify(response, null, 2)}
</pre>
</Layout>
)
}
return (
<Layout>
<h1>Test different flows for Credentials login</h1>
<span className="spacing">Default:</span>
<button onClick={handleLogin({ redirect: true, password: "password" })}>
Login
</button>
<br />
<span className="spacing">No redirect:</span>
<button onClick={handleLogin({ redirect: false, password: "password" })}>
Login
</button>
<br />
<span className="spacing">No redirect, wrong password:</span>
<button onClick={handleLogin({ redirect: false, password: "" })}>
Login
</button>
<p>Response:</p>
<pre style={{ background: "#eee", padding: 16 }}>
{JSON.stringify(response, null, 2)}
</pre>
</Layout>
)
}

View File

@@ -0,0 +1,67 @@
import * as React from "react"
import { signIn, signOut, useSession } from "@auth/nextjs/react"
import { SignInResponse, SignOutResponse } from "@auth/nextjs/lib/client"
export default function Page() {
const [response, setResponse] = React.useState<
SignInResponse | SignOutResponse
>()
const { data: session } = useSession()
if (session) {
return (
<>
<h1>Test different flows for Credentials logout</h1>
<span className="spacing">Default: </span>
<button onClick={() => signOut()}>Logout</button>
<br />
<span className="spacing">No redirect: </span>
<button onClick={() => signOut({ redirect: false }).then(setResponse)}>
Logout
</button>
<br />
<p>{response ? "Response:" : "Session:"}</p>
<pre style={{ background: "#eee", padding: 16 }}>
{JSON.stringify(response ?? session, null, 2)}
</pre>
</>
)
}
return (
<>
<h1>Test different flows for Credentials login</h1>
<span className="spacing">Default: </span>
<button onClick={() => signIn("credentials", { password: "password" })}>
Login
</button>
<br />
<span className="spacing">No redirect: </span>
<button
onClick={() =>
signIn("credentials", { redirect: false, password: "password" }).then(
setResponse
)
}
>
Login
</button>
<br />
<span className="spacing">No redirect, wrong password: </span>
<button
onClick={() =>
signIn("credentials", { redirect: false, password: "wrong" }).then(
setResponse
)
}
>
Login
</button>
<p>Response:</p>
<pre style={{ background: "#eee", padding: 16 }}>
{JSON.stringify(response, null, 2)}
</pre>
</>
)
}

View File

@@ -1,9 +0,0 @@
import Layout from "components/layout"
export default function Page() {
return (
<Layout>
<h1>Page protected by Middleware</h1>
</Layout>
)
}

View File

@@ -1,8 +1,6 @@
import Layout from "../components/layout"
export default function Page() {
return (
<Layout>
<>
<p>
This is an example site to demonstrate how to use{" "}
<a href="https://authjs.dev">Auth.js</a> for authentication.
@@ -18,15 +16,11 @@ export default function Page() {
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</p>
<h2>Privacy Policy</h2>
<p>
This site uses JSON Web Tokens and an in-memory database which resets
every ~2 hours.
</p>
<p>
Data provided to this site is exclusively used to support signing in and
is not passed to any third party services, other than via SMTP or OAuth
for the purposes of authentication.
</p>
</Layout>
</>
)
}

View File

@@ -1,52 +1,34 @@
// This is an example of how to protect content using server rendering
import { unstable_getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import Layout from "../components/layout"
import AccessDenied from "../components/access-denied"
import { getServerSession } from "auth"
import AccessDenied from "components/access-denied"
export default function Page({ content, session }) {
// If no session exists, display access denied message
if (!session) {
return (
<Layout>
<AccessDenied />
</Layout>
)
}
if (!session) return <AccessDenied />
// If session exists, display content
return (
<Layout>
<>
<h1>Protected Page</h1>
<p>
<strong>{content}</strong>
</p>
</Layout>
</>
)
}
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
let content = null
const session = await getServerSession(context.req, context.res)
if (session) {
// Note usually you don't need to fetch from an API route in getServerSideProps
// This is done here to demonstrate how you can fetch from a third-party API
// with a valid session. Likely you would also not pass cookies but an `Authorization` header
const hostname = process.env.NEXTAUTH_URL || "http://localhost:3000"
const options = { headers: { cookie: context.req.headers.cookie } }
const res = await fetch(`${hostname}/api/examples/protected`, options)
const json = await res.json()
if (json.content) {
content = json.content
}
const res = await fetch(`${hostname}/api/examples/protected`, {
headers: { cookie: context.req.headers.cookie },
})
return { props: { session, content: (await res.json()).content } }
}
return {
props: {
session,
content,
},
}
return { props: {} }
}

View File

@@ -1,50 +0,0 @@
import { unstable_getServerSession } from "next-auth/next"
import Layout from "../components/layout"
import { authOptions } from "./api/auth/[...nextauth]"
export default function Page() {
// As this page uses Server Side Rendering, the `session` will be already
// populated on render without needing to go through a loading stage.
// This is possible because of the shared context configured in `_app.js` that
// is used by `useSession()`.
return (
<Layout>
<h1>Server Side Rendering</h1>
<p>
This page uses the <strong>unstable_getServerSession()</strong> method
in <strong>getServerSideProps()</strong>.
</p>
<p>
Using <strong>unstable_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.
</p>
<p>
Using <strong>getSession()</strong> is still recommended on the client.
</p>
<p>
The advantage of Server Side Rendering is this page does not require
client side JavaScript.
</p>
<p>
The disadvantage of Server Side Rendering is that this page is slower to
render.
</p>
</Layout>
)
}
// Export the `session` prop to use sessions with Server Side Rendering
export async function getServerSideProps(context) {
return {
props: {
session: await unstable_getServerSession(
context.req,
context.res,
authOptions
),
},
}
}

View File

@@ -1,48 +0,0 @@
import Layout from "../components/layout"
import { useState, useEffect } from "react"
import { useSession } from "next-auth/react"
import { createClient } from "@supabase/supabase-js"
export default function Page() {
const { data: session } = useSession()
const [data, setData] = useState(null)
useEffect(() => {
if (session) {
// User is logged in, let's fetch their data.
const { supabaseAccessToken } = session
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
global: {
headers: { Authorization: `Bearer ${supabaseAccessToken}` },
},
}
)
// Fetch data with RLS enabled.
supabase
.from("users")
.select("*")
.then(({ data }) => setData(data))
}
}, [session])
return (
<Layout>
<h1>Fetch Data from Supabase with RLS</h1>
<h2>Client-side data fetching with RLS:</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
<h2>API Example</h2>
<p>
You can also use Supabase in API routes. See the code in the
`/pages/api/examples/supabase-rls.js` file.
</p>
<p>
<em>You must be signed in to see responses.</em>
</p>
<p>/api/examples/supabase-rls</p>
<iframe src="/api/examples/supabase-rls" />
</Layout>
)
}

View File

@@ -1,68 +0,0 @@
// 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 { authOptions } from "./api/auth/[...nextauth]"
import { createClient } from "@supabase/supabase-js"
import Layout from "../components/layout"
import AccessDenied from "../components/access-denied"
export default function Page({ data, session }) {
// If no session exists, display access denied message
if (!session) {
return (
<Layout>
<AccessDenied />
</Layout>
)
}
// If session exists, display content
return (
<Layout>
<h1>Protected Page</h1>
<p>Data fetched during SSR from Supabase with RSL enabled:</p>
<pre>{JSON.stringify(data, null, 2)}</pre>
</Layout>
)
}
export async function getServerSideProps(context) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
)
if (!session)
return {
props: {
session,
data: null,
error: "No 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("*")
return {
props: {
session,
data,
error,
},
}
}

View File

@@ -18,3 +18,12 @@ declare module "next-auth" {
foo: string
}
}
declare global {
namespace NodeJS {
interface ProcessEnv {
[key: string]: string;
}
}
}

View File

@@ -15,8 +15,8 @@
"@sveltejs/kit": "next",
"svelte": "3.55.0",
"svelte-check": "2.10.2",
"typescript": "5.2.2",
"vite": "4.0.5"
"typescript": "4.9.4",
"vite": "4.0.1"
},
"dependencies": {
"@auth/core": "workspace:*",

View File

@@ -0,0 +1,4 @@
/** @type {import("next").NextConfig} */
module.exports = {
reactStrictMode: true,
}

View File

@@ -1,22 +1,17 @@
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
AUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32
AUTH_AUTH0_ID=
AUTH_AUTH0_SECRET=
AUTH_AUTH0_ISSUER=
AUTH0_ID=
AUTH0_SECRET=
AUTH0_ISSUER=
AUTH_FACEBOOK_ID=
AUTH_FACEBOOK_SECRET=
DESCOPE_ID=
DESCOPE_SECRET=
AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
FACEBOOK_ID=
FACEBOOK_SECRET=
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=
GITHUB_ID=
GITHUB_SECRET=
GOOGLE_ID=
GOOGLE_SECRET=
TWITTER_ID=
TWITTER_SECRET=
AUTH_TWITTER_ID=
AUTH_TWITTER_SECRET=

View File

@@ -8,7 +8,7 @@
<a href="https://nextjs.org" target="_blank">
<img height="64" src="https://nextjs.org/static/favicon/android-chrome-192x192.png" />
</a>
<h3 align="center"><b>NextAuth.js</b> - Example App</h3>
<h3 align="center"><b>next-auth</b> - Example App</h3>
<p align="center">
Open Source. Full Stack. Own Your Data.
</p>
@@ -36,7 +36,7 @@ This is an example application that shows how `next-auth` is applied to a basic
The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app)
Go to [next-auth.js.org](https://next-auth.js.org) for more information and documentation.
Go to [authjs.dev](https://authjs.dev) for more information and documentation.
## Getting Started
@@ -66,7 +66,7 @@ You **can** skip configuring a database and come back to it later if you want.
For more information about setting up a database, please check out the following links:
- Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
- Docs: [authjs.dev/reference/adapters](https://authjs.dev/reference/adapters)
### 3. Configure Authentication Providers
@@ -76,7 +76,7 @@ For more information about setting up a database, please check out the following
e.g. For Google OAuth you would use: `http://localhost:3000/api/auth/callback/google`
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at https://next-auth.js.org/configuration/providers/oauth
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at [authjs.dev/getting-started/oauth-tutorial](https://authjs.dev/getting-started/oauth-tutorial)
3. You can also choose to specify an SMTP server for passwordless sign in via email.
@@ -106,4 +106,4 @@ Follow the [Deployment documentation](https://authjs.dev/guides/basics/deploymen
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss">
<img width="170px" src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg" alt="Powered By Vercel" />
</a>
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire Auth.js Team</p>
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire Auth.js Team</p>

View File

@@ -1,5 +1,3 @@
import NextAuth from "next-auth/next"
import { config } from "auth"
const handler = NextAuth(config)
export { handler as GET, handler as POST }
import { handlers } from "auth"
export const { GET, POST } = handlers
export const runtime = "edge"

View File

@@ -0,0 +1,10 @@
import { auth } from "auth"
import { NextResponse } from "next/server"
export const GET = auth(function GET(req) {
if (req.auth) {
return NextResponse.json(req.auth)
}
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
})

View File

@@ -1,15 +1,13 @@
import Layout from "../components/layout"
export default function ClientPage() {
export default function Page() {
return (
<Layout>
<>
<h1>Client Side Rendering</h1>
<p>
This page uses the <strong>useSession()</strong> React Hook in the{" "}
<strong>&lt;Header/&gt;</strong> component.
<strong>&lt;/Header&gt;</strong> component.
</p>
<p>
The <strong>useSession()</strong> React Hook is easy to use and allows
The <strong>useSession()</strong> React Hook easy to use and allows
pages to render very quickly.
</p>
<p>
@@ -22,6 +20,6 @@ export default function ClientPage() {
The disadvantage of <strong>useSession()</strong> is that it requires
client side JavaScript.
</p>
</Layout>
</>
)
}

View File

@@ -0,0 +1,24 @@
import Header from "components/header"
import Footer from "components/footer"
import './styles.css'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<head></head>
<body>
<Header />
<main>
{children}
</main>
<Footer />
</body>
</html>
)
}
export const runtime = "experimental-edge"

View File

@@ -1,13 +1,13 @@
import Layout from "components/layout"
export default function Page() {
return (
<Layout>
<>
<h1>NextAuth.js Example</h1>
<p>
This is an example site to demonstrate how to use{" "}
<a href="https://authjs.dev">NextAuth.js</a> for authentication.
</p>
</Layout>
</>
)
}
export const runtime = "experimental-edge"

View File

@@ -0,0 +1,39 @@
import { auth } from "auth"
import { cookies, headers } from "next/headers"
function SignIn({ id, children, className }: any) {
const $cookies = cookies()
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
return (
<form action={`/api/auth/signin/${id}`} method="post">
<button className={className} type="submit">{children}</button>
<input type="hidden" name="csrfToken" value={csrfToken} />
</form>
)
}
function SignOut({ children }: any) {
const $cookies = cookies()
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
return (
<form action="/api/auth/signout" method="post">
<button type="submit">{children}</button>
<input type="hidden" name="csrfToken" value={csrfToken} />
</form>
)
}
export default async function Page() {
const session = await auth(headers())
if (session) {
return (
<>
<pre>{JSON.stringify(session, null, 2)}</pre>
<SignOut>Sign out</SignOut>
</>
)
}
return <SignIn id="github">Sign in with github</SignIn>
}
export const runtime = "experimental-edge"

View File

@@ -0,0 +1,33 @@
body {
color: red;
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: var(--color-text);
}
li,
p {
line-height: 1.5rem;
}
a {
font-weight: 500;
}
hr {
border: 1px solid #ddd;
}
iframe {
background: #ccc;
border: 1px solid #ccc;
height: 10rem;
width: 100%;
border-radius: 0.5rem;
filter: invert(1);
}

View File

@@ -1,294 +1,25 @@
import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from "next"
import type { NextAuthOptions as NextAuthConfig } from "next-auth"
import { getServerSession } from "next-auth"
import NextAuth from "next-auth"
import Auth0 from "@auth/core/providers/github"
import Facebook from "@auth/core/providers/facebook"
import GitHub from "@auth/core/providers/github"
import Google from "@auth/core/providers/google"
import Twitter from "@auth/core/providers/twitter"
import Apple from "next-auth/providers/apple"
import Atlassian from "next-auth/providers/atlassian"
import Auth0 from "next-auth/providers/auth0"
import Authentik from "next-auth/providers/authentik"
import AzureAD from "next-auth/providers/azure-ad"
import AzureB2C from "next-auth/providers/azure-ad-b2c"
import Battlenet from "next-auth/providers/battlenet"
import Box from "next-auth/providers/box"
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
import Bungie from "next-auth/providers/bungie"
import Cognito from "next-auth/providers/cognito"
import Coinbase from "next-auth/providers/coinbase"
import Discord from "next-auth/providers/discord"
import Dropbox from "next-auth/providers/dropbox"
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
import Eveonline from "next-auth/providers/eveonline"
import Facebook from "next-auth/providers/facebook"
import Faceit from "next-auth/providers/faceit"
import FortyTwoSchool from "next-auth/providers/42-school"
import Foursquare from "next-auth/providers/foursquare"
import Freshbooks from "next-auth/providers/freshbooks"
import Fusionauth from "next-auth/providers/fusionauth"
import GitHub from "next-auth/providers/github"
import Gitlab from "next-auth/providers/gitlab"
import Google from "next-auth/providers/google"
import Hubspot from "next-auth/providers/hubspot"
import Instagram from "next-auth/providers/instagram"
import Kakao from "next-auth/providers/kakao"
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 Mailru from "next-auth/providers/mailru"
import Medium from "next-auth/providers/medium"
import Naver from "next-auth/providers/naver"
import Netlify from "next-auth/providers/netlify"
import Okta from "next-auth/providers/okta"
import Onelogin from "next-auth/providers/onelogin"
import Osso from "next-auth/providers/osso"
import Osu from "next-auth/providers/osu"
import Passage from "next-auth/providers/passage"
import Patreon from "next-auth/providers/patreon"
import Pinterest from "next-auth/providers/pinterest"
import Pipedrive from "next-auth/providers/pipedrive"
import Reddit from "next-auth/providers/reddit"
import Salesforce from "next-auth/providers/salesforce"
import Slack from "next-auth/providers/slack"
import Spotify from "next-auth/providers/spotify"
import Strava from "next-auth/providers/strava"
import Todoist from "next-auth/providers/todoist"
import Trakt from "next-auth/providers/trakt"
import Twitch from "next-auth/providers/twitch"
import Twitter from "next-auth/providers/twitter"
import UnitedEffects from "next-auth/providers/united-effects"
import Vk from "next-auth/providers/vk"
import Wikimedia from "next-auth/providers/wikimedia"
import Wordpress from "next-auth/providers/wordpress"
import WorkOS from "next-auth/providers/workos"
import Yandex from "next-auth/providers/yandex"
import Zitadel from "next-auth/providers/zitadel"
import Zoho from "next-auth/providers/zoho"
import Zoom from "next-auth/providers/zoom"
// Read more at: https://next-auth.js.org/getting-started/typescript#module-augmentation
declare module "next-auth/jwt" {
interface JWT {
/** The user's role. */
userRole?: "admin"
}
}
export const config = {
// https://next-auth.js.org/configuration/providers/oauth
providers: [
Apple({ clientId: process.env.AUTH_APPLE_ID, clientSecret: process.env.AUTH_APPLE_SECRET }),
Atlassian({ clientId: process.env.AUTH_ATLASSIAN_ID, clientSecret: process.env.AUTH_ATLASSIAN_SECRET }),
Auth0({ clientId: process.env.AUTH_AUTH0_ID, clientSecret: process.env.AUTH_AUTH0_SECRET, issuer: process.env.AUTH_AUTH0_ISSUER }),
Authentik({ clientId: process.env.AUTH_AUTHENTIK_ID, clientSecret: process.env.AUTH_AUTHENTIK_SECRET }),
AzureAD({ clientId: process.env.AUTH_AZUREAD_ID, clientSecret: process.env.AUTH_AZUREAD_SECRET }),
AzureB2C({ clientId: process.env.AUTH_AZUREB2C_ID, clientSecret: process.env.AUTH_AZUREB2C_SECRET }),
Battlenet({ clientId: process.env.AUTH_BN_ID, clientSecret: process.env.AUTH_BN_SECRET, issuer: process.env.AUTH_BN_ISSUER }),
Box({ clientId: process.env.AUTH_BOX_ID, clientSecret: process.env.AUTH_BOX_SECRET }),
BoxyHQSAML({ clientId: process.env.AUTH_BOXYHQ_ID, clientSecret: process.env.AUTH_BOXYHQ_SECRET, issuer: process.env.AUTH_BOXYHQ_ISSUER }),
Bungie({ clientId: process.env.AUTH_BUNGIE_ID, clientSecret: process.env.AUTH_BUNGIE_SECRET }),
Cognito({ clientId: process.env.AUTH_COGNITO_ID, clientSecret: process.env.AUTH_COGNITO_SECRET }),
Coinbase({ clientId: process.env.AUTH_COINBASE_ID, clientSecret: process.env.AUTH_COINBASE_SECRET }),
Discord({ clientId: process.env.AUTH_DISCORD_ID, clientSecret: process.env.AUTH_DISCORD_SECRET }),
Dropbox({ clientId: process.env.AUTH_DROPBOX_ID, clientSecret: process.env.AUTH_DROPBOX_SECRET }),
DuendeIDS6({ clientId: process.env.AUTH_DUENDEIDS6_ID, clientSecret: process.env.AUTH_DUENDEIDS6_SECRET }),
Eveonline({ clientId: process.env.AUTH_EVEONLINE_ID, clientSecret: process.env.AUTH_EVEONLINE_SECRET }),
Facebook({ clientId: process.env.AUTH_FACEBOOK_ID, clientSecret: process.env.AUTH_FACEBOOK_SECRET }),
Faceit({ clientId: process.env.AUTH_FACEIT_ID, clientSecret: process.env.AUTH_FACEIT_SECRET }),
FortyTwoSchool({ clientId: process.env.AUTH_FORTYTWOSCHOOL_ID, clientSecret: process.env.AUTH_FORTYTWOSCHOOL_SECRET }),
Foursquare({ clientId: process.env.AUTH_FOURSQUARE_ID, clientSecret: process.env.AUTH_FOURSQUARE_SECRET }),
Freshbooks({ clientId: process.env.AUTH_FRESHBOOKS_ID, clientSecret: process.env.AUTH_FRESHBOOKS_SECRET }),
Fusionauth({ clientId: process.env.AUTH_FUSIONAUTH_ID, clientSecret: process.env.AUTH_FUSIONAUTH_SECRET }),
GitHub({ clientId: process.env.AUTH_GITHUB_ID, clientSecret: process.env.AUTH_GITHUB_SECRET }),
Gitlab({ clientId: process.env.AUTH_GITLAB_ID, clientSecret: process.env.AUTH_GITLAB_SECRET }),
Google({ clientId: process.env.AUTH_GOOGLE_ID, clientSecret: process.env.AUTH_GOOGLE_SECRET }),
Hubspot({ clientId: process.env.AUTH_HUBSPOT_ID, clientSecret: process.env.AUTH_HUBSPOT_SECRET }),
Instagram({ clientId: process.env.AUTH_INSTAGRAM_ID, clientSecret: process.env.AUTH_INSTAGRAM_SECRET }),
Kakao({ clientId: process.env.AUTH_KAKAO_ID, clientSecret: process.env.AUTH_KAKAO_SECRET }),
Keycloak({ clientId: process.env.AUTH_KEYCLOAK_ID, clientSecret: process.env.AUTH_KEYCLOAK_SECRET }),
Line({ clientId: process.env.AUTH_LINE_ID, clientSecret: process.env.AUTH_LINE_SECRET }),
LinkedIn({ clientId: process.env.AUTH_LINKEDIN_ID, clientSecret: process.env.AUTH_LINKEDIN_SECRET }),
Mailchimp({ clientId: process.env.AUTH_MAILCHIMP_ID, clientSecret: process.env.AUTH_MAILCHIMP_SECRET }),
Mailru({ clientId: process.env.AUTH_MAILRU_ID, clientSecret: process.env.AUTH_MAILRU_SECRET }),
Medium({ clientId: process.env.AUTH_MEDIUM_ID, clientSecret: process.env.AUTH_MEDIUM_SECRET }),
Naver({ clientId: process.env.AUTH_NAVER_ID, clientSecret: process.env.AUTH_NAVER_SECRET }),
Netlify({ clientId: process.env.AUTH_NETLIFY_ID, clientSecret: process.env.AUTH_NETLIFY_SECRET }),
Okta({ clientId: process.env.AUTH_OKTA_ID, clientSecret: process.env.AUTH_OKTA_SECRET }),
Onelogin({ clientId: process.env.AUTH_ONELOGIN_ID, clientSecret: process.env.AUTH_ONELOGIN_SECRET }),
Osso({ clientId: process.env.AUTH_OSSO_ID, clientSecret: process.env.AUTH_OSSO_SECRET, issuer: process.env.AUTH_OSSO_ISSUER }),
Osu({ clientId: process.env.AUTH_OSU_ID, clientSecret: process.env.AUTH_OSU_SECRET }),
Passage({ clientId: process.env.AUTH_PASSAGE_ID, clientSecret: process.env.AUTH_PASSAGE_SECRET, issuer: process.env.AUTH_PASSAGE_ISSUER }),
Patreon({ clientId: process.env.AUTH_PATREON_ID, clientSecret: process.env.AUTH_PATREON_SECRET }),
Pinterest({ clientId: process.env.AUTH_PINTEREST_ID, clientSecret: process.env.AUTH_PINTEREST_SECRET }),
Pipedrive({ clientId: process.env.AUTH_PIPEDRIVE_ID, clientSecret: process.env.AUTH_PIPEDRIVE_SECRET }),
Reddit({ clientId: process.env.AUTH_REDDIT_ID, clientSecret: process.env.AUTH_REDDIT_SECRET }),
Salesforce({ clientId: process.env.AUTH_SALESFORCE_ID, clientSecret: process.env.AUTH_SALESFORCE_SECRET }),
Slack({ clientId: process.env.AUTH_SLACK_ID, clientSecret: process.env.AUTH_SLACK_SECRET }),
Spotify({ clientId: process.env.AUTH_SPOTIFY_ID, clientSecret: process.env.AUTH_SPOTIFY_SECRET }),
Strava({ clientId: process.env.AUTH_STRAVA_ID, clientSecret: process.env.AUTH_STRAVA_SECRET }),
Todoist({ clientId: process.env.AUTH_TODOIST_ID, clientSecret: process.env.AUTH_TODOIST_SECRET }),
Trakt({ clientId: process.env.AUTH_TRAKT_ID, clientSecret: process.env.AUTH_TRAKT_SECRET }),
Twitch({ clientId: process.env.AUTH_TWITCH_ID, clientSecret: process.env.AUTH_TWITCH_SECRET }),
Twitter({ clientId: process.env.AUTH_TWITTER_ID, clientSecret: process.env.AUTH_TWITTER_SECRET, version: "2.0" }),
UnitedEffects({ clientId: process.env.AUTH_UE_ID, clientSecret: process.env.AUTH_UE_SECRET, issuer: process.env.AUTH_UE_ISSUER }),
Vk({ clientId: process.env.AUTH_VK_ID, clientSecret: process.env.AUTH_VK_SECRET }),
Wikimedia({ clientId: process.env.AUTH_WIKIMEDIA_ID, clientSecret: process.env.AUTH_WIKIMEDIA_SECRET }),
Wordpress({ clientId: process.env.AUTH_WORDPRESS_ID, clientSecret: process.env.AUTH_WORDPRESS_SECRET }),
WorkOS({ clientId: process.env.AUTH_WORKOS_ID, clientSecret: process.env.AUTH_WORKOS_SECRET }),
Yandex({ clientId: process.env.AUTH_YANDEX_ID, clientSecret: process.env.AUTH_YANDEX_SECRET }),
Zitadel({ clientId: process.env.AUTH_ZITADEL_ID, clientSecret: process.env.AUTH_ZITADEL_SECRET }),
Zoho({ clientId: process.env.AUTH_ZOHO_ID, clientSecret: process.env.AUTH_ZOHO_SECRET }),
Zoom({ clientId: process.env.AUTH_ZOOM_ID, clientSecret: process.env.AUTH_ZOOM_SECRET }),
],
export const { handlers, auth } = NextAuth({
providers: [GitHub, Auth0, Facebook, Google, Twitter],
callbacks: {
async jwt({ token }) {
token.userRole = "admin"
return token
async authorized({ request, auth }) {
// if (request.method === "POST") {
// const [, token] = request.headers.get("Authorization")?.split(" ")
// const valid = validateToken(token)
// // If the request has a valid auth token, it is authorized
// if (valid) return true
// return NextResponse.json("Invalid auth token", { status: 401 })
// }
// Logged in users are authorized, otherwise, will redirect to login
// You could also return a custom redirect instead of the sign-in page
return !!auth
},
},
} satisfies NextAuthConfig
// Helper function to get session without passing config every time
// https://next-auth.js.org/configuration/nextjs#getserversession
export function auth(...args: [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]] | [NextApiRequest, NextApiResponse] | []) {
return getServerSession(...args, config)
}
// We recommend doing your own environment variable validation
declare global {
namespace NodeJS {
export interface ProcessEnv {
NEXTAUTH_SECRET: string
AUTH_APPLE_ID: string
AUTH_APPLE_SECRET: string
AUTH_ATLASSIAN_ID: string
AUTH_ATLASSIAN_SECRET: string
AUTH_AUTH0_ID: string
AUTH_AUTH0_ISSUER: string
AUTH_AUTH0_SECRET: string
AUTH_AUTHENTIK_ID: string
AUTH_AUTHENTIK_SECRET: string
AUTH_AZUREAD_ID: string
AUTH_AZUREAD_SECRET: string
AUTH_AZUREB2C_ID: string
AUTH_AZUREB2C_SECRET: string
AUTH_BN_ID: string
AUTH_BN_ISSUER: any
AUTH_BN_SECRET: string
AUTH_BOX_ID: string
AUTH_BOX_SECRET: string
AUTH_BOXYHQ_ID: string
AUTH_BOXYHQ_ISSUER: string
AUTH_BOXYHQ_SECRET: string
AUTH_BUNGIE_ID: string
AUTH_BUNGIE_SECRET: string
AUTH_COGNITO_ID: string
AUTH_COGNITO_SECRET: string
AUTH_COINBASE_ID: string
AUTH_COINBASE_SECRET: string
AUTH_DISCORD_ID: string
AUTH_DISCORD_SECRET: string
AUTH_DROPBOX_ID: string
AUTH_DROPBOX_SECRET: string
AUTH_DUENDEIDS6_ID: string
AUTH_DUENDEIDS6_SECRET: string
AUTH_EVEONLINE_ID: string
AUTH_EVEONLINE_SECRET: string
AUTH_FACEBOOK_ID: string
AUTH_FACEBOOK_SECRET: string
AUTH_FACEIT_ID: string
AUTH_FACEIT_SECRET: string
AUTH_FORTYTWOSCHOOL_ID: string
AUTH_FORTYTWOSCHOOL_SECRET: string
AUTH_FOURSQUARE_ID: string
AUTH_FOURSQUARE_SECRET: string
AUTH_FRESHBOOKS_ID: string
AUTH_FRESHBOOKS_SECRET: string
AUTH_FUSIONAUTH_ID: string
AUTH_FUSIONAUTH_SECRET: string
AUTH_GITHUB_ID: string
AUTH_GITHUB_SECRET: string
AUTH_GITLAB_ID: string
AUTH_GITLAB_SECRET: string
AUTH_GOOGLE_ID: string
AUTH_GOOGLE_SECRET: string
AUTH_HUBSPOT_ID: string
AUTH_HUBSPOT_SECRET: string
AUTH_INSTAGRAM_ID: string
AUTH_INSTAGRAM_SECRET: string
AUTH_KAKAO_ID: string
AUTH_KAKAO_SECRET: string
AUTH_KEYCLOAK_ID: string
AUTH_KEYCLOAK_SECRET: string
AUTH_LINE_ID: string
AUTH_LINE_SECRET: string
AUTH_LINKEDIN_ID: string
AUTH_LINKEDIN_SECRET: string
AUTH_MAILCHIMP_ID: string
AUTH_MAILCHIMP_SECRET: string
AUTH_MAILRU_ID: string
AUTH_MAILRU_SECRET: string
AUTH_MEDIUM_ID: string
AUTH_MEDIUM_SECRET: string
AUTH_NAVER_ID: string
AUTH_NAVER_SECRET: string
AUTH_NETLIFY_ID: string
AUTH_NETLIFY_SECRET: string
AUTH_OKTA_ID: string
AUTH_OKTA_SECRET: string
AUTH_ONELOGIN_ID: string
AUTH_ONELOGIN_SECRET: string
AUTH_OSSO_ID: string
AUTH_OSSO_ISSUER: string
AUTH_OSSO_SECRET: string
AUTH_OSU_ID: string
AUTH_OSU_SECRET: string
AUTH_PASSAGE_ID: string
AUTH_PASSAGE_ISSUER: string
AUTH_PASSAGE_SECRET: string
AUTH_PATREON_ID: string
AUTH_PATREON_SECRET: string
AUTH_PINTEREST_ID: string
AUTH_PINTEREST_SECRET: string
AUTH_PIPEDRIVE_ID: string
AUTH_PIPEDRIVE_SECRET: string
AUTH_REDDIT_ID: string
AUTH_REDDIT_SECRET: string
AUTH_SALESFORCE_ID: string
AUTH_SALESFORCE_SECRET: string
AUTH_SLACK_ID: string
AUTH_SLACK_SECRET: string
AUTH_SPOTIFY_ID: string
AUTH_SPOTIFY_SECRET: string
AUTH_STRAVA_ID: string
AUTH_STRAVA_SECRET: string
AUTH_TODOIST_ID: string
AUTH_TODOIST_SECRET: string
AUTH_TRAKT_ID: string
AUTH_TRAKT_SECRET: string
AUTH_TWITCH_ID: string
AUTH_TWITCH_SECRET: string
AUTH_TWITTER_ID: string
AUTH_TWITTER_SECRET: string
AUTH_UE_ID: string
AUTH_UE_ISSUER: string
AUTH_UE_SECRET: string
AUTH_VK_ID: string
AUTH_VK_SECRET: string
AUTH_WIKIMEDIA_ID: string
AUTH_WIKIMEDIA_SECRET: string
AUTH_WORDPRESS_ID: string
AUTH_WORDPRESS_SECRET: string
AUTH_WORKOS_ID: string
AUTH_WORKOS_SECRET: string
AUTH_YANDEX_ID: string
AUTH_YANDEX_SECRET: string
AUTH_ZITADEL_ID: string
AUTH_ZITADEL_SECRET: string
AUTH_ZOHO_ID: string
AUTH_ZOHO_SECRET: string
AUTH_ZOOM_ID: string
AUTH_ZOOM_SECRET: string
}
}
}
})

View File

@@ -1,6 +1,6 @@
import Link from "next/link"
import styles from "./footer.module.css"
import packageJSON from "../package.json"
import packageJSON from "next-auth/package.json"
export default function Footer() {
return (
@@ -8,10 +8,10 @@ export default function Footer() {
<hr />
<ul className={styles.navItems}>
<li className={styles.navItem}>
<a href="https://next-auth.js.org">Documentation</a>
<a href="https://authjs.dev">Documentation</a>
</li>
<li className={styles.navItem}>
<a href="https://www.npmjs.com/package/next-auth">NPM</a>
<a href="https://www.npmjs.com/package/@auth/core">NPM</a>
</li>
<li className={styles.navItem}>
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
@@ -20,7 +20,7 @@ export default function Footer() {
<Link href="/policy">Policy</Link>
</li>
<li className={styles.navItem}>
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
<em>{packageJSON.version}</em>
</li>
</ul>
</footer>

View File

@@ -1,5 +1,6 @@
/* Set min-height to avoid page reflow while session loading */
.signedInStatus {
position: relative;
display: block;
min-height: 4rem;
width: 100%;

View File

@@ -1,65 +1,63 @@
import Link from "next/link"
import { signIn, signOut, useSession } from "next-auth/react"
import { auth } from "auth"
import { cookies, headers } from "next/headers"
import styles from "./header.module.css"
// The approach used in this component shows how to build a sign in and sign out
function SignIn({ id, children, className }: any) {
const $cookies = cookies()
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
return (
<form action={`/api/auth/signin/${id}`} method="post">
<button className={className} type="submit">{children}</button>
<input type="hidden" name="csrfToken" value={csrfToken} />
</form>
)
}
function SignOut({ children, className }: any) {
const $cookies = cookies()
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
return (
<form action="/api/auth/signout" method="post">
<button className={className} type="submit">{children}</button>
<input type="hidden" name="csrfToken" value={csrfToken} />
</form>
)
}
// The approach used in this component shows how to built a sign in and sign out
// component that works on pages which support both client and server side
// rendering, and avoids any flash incorrect content on initial page load.
export default function Header() {
const { data: session, status } = useSession()
const loading = status === "loading"
export default async function Header() {
const session = await auth(headers())
return (
<header>
<noscript>
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
</noscript>
<div className={styles.signedInStatus}>
<p
className={`nojs-show ${
!session && loading ? styles.loading : styles.loaded
}`}
>
<p className={`nojs-show ${styles.loaded}`}>
{!session && (
<>
<span className={styles.notSignedInText}>
You are not signed in
</span>
<a
href={`/api/auth/signin`}
className={styles.buttonPrimary}
onClick={(e) => {
e.preventDefault()
signIn()
}}
>
Sign in
</a>
<SignIn className={styles.buttonPrimary}>Sign In</SignIn>
</>
)}
{session?.user && (
{session && (
<>
{session.user.image && (
<span
style={{ backgroundImage: `url('${session.user.image}')` }}
className={styles.avatar}
/>
<img src={session.user.image} className={styles.avatar} />
)}
<span className={styles.signedInText}>
<small>Signed in as</small>
<br />
<strong>{session.user.email ?? session.user.name}</strong>
<strong>{session.user.email} </strong>
{session.user.name ? `(${session.user.name})` : null}
</span>
<a
href={`/api/auth/signout`}
className={styles.button}
onClick={(e) => {
e.preventDefault()
signOut()
}}
>
Sign out
</a>
<SignOut className={styles.button}>Sign Out</SignOut>
</>
)}
</p>
@@ -73,7 +71,7 @@ export default function Header() {
<Link href="/client">Client</Link>
</li>
<li className={styles.navItem}>
<Link href="/server">Server</Link>
<Link href="/server-component">Server</Link>
</li>
<li className={styles.navItem}>
<Link href="/protected">Protected</Link>
@@ -82,13 +80,12 @@ export default function Header() {
<Link href="/api-example">API</Link>
</li>
<li className={styles.navItem}>
<Link href="/admin">Admin</Link>
</li>
<li className={styles.navItem}>
<Link href="/me">Me</Link>
<Link href="/middleware-protected">Middleware protected</Link>
</li>
</ul>
</nav>
</header>
)
}
export const runtime = "experimental-edge"

View File

@@ -1,13 +0,0 @@
import Header from "./header"
import Footer from "./footer"
import type { ReactNode } from "react"
export default function Layout({ children }: { children: ReactNode }) {
return (
<>
<Header />
<main>{children}</main>
<Footer />
</>
)
}

View File

@@ -1,17 +1,10 @@
import { withAuth } from "next-auth/middleware"
// export { auth as default } from "auth"
import { auth } from "auth"
import { NextResponse } from "next/server"
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
export default withAuth({
callbacks: {
authorized({ req, token }) {
// `/admin` requires admin role
if (req.nextUrl.pathname === "/admin") {
return token?.userRole === "admin"
}
// `/me` only requires the user to be logged in
return !!token
},
},
export default auth((req) => {
if (req.auth) return NextResponse.json(req.auth)
return NextResponse.json("Not authorized", { status: 401 })
})
export const config = { matcher: ["/admin", "/me"] }
export const config = { matcher: ["/middleware-protected"] }

View File

@@ -1,4 +1,9 @@
/** @type {import("next").NextConfig} */
module.exports = {
reactStrictMode: true,
webpack(config) {
config.experiments = { ...config.experiments, topLevelAwait: true }
return config
},
experimental: { appDir: true },
typescript: { ignoreBuildErrors: true },
}

View File

@@ -1,5 +1,6 @@
{
"private": true,
"name": "nextjs-example-app",
"description": "An example project for NextAuth.js with Next.js",
"repository": "https://github.com/nextauthjs/next-auth-example.git",
"bugs": {
@@ -18,14 +19,15 @@
"Lluis Agusti <hi@llu.lu>"
],
"dependencies": {
"@auth/core": "workspace:*",
"next": "latest",
"next-auth": "latest",
"next-auth": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "^18.16.2",
"@types/react": "^18.2.0",
"typescript": "5.2.2"
"typescript": "^5.0.4"
}
}

View File

@@ -1,18 +0,0 @@
import { SessionProvider } from "next-auth/react"
import "./styles.css"
import type { AppProps } from "next/app"
import type { Session } from "next-auth"
// Use of the <SessionProvider> is mandatory to allow components that call
// `useSession()` anywhere in your application to access the `session` object.
export default function App({
Component,
pageProps: { session, ...pageProps },
}: AppProps<{ session: Session }>) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
)
}

View File

@@ -1,17 +0,0 @@
import Layout from "../components/layout"
export default function Page() {
return (
<Layout>
<h1>This page is protected by Middleware</h1>
<p>Only admin users can see this page.</p>
<p>
To learn more about the NextAuth middleware see&nbsp;
<a href="https://next-auth.js.org/configuration/nextjs#middleware">
the docs
</a>
.
</p>
</Layout>
)
}

View File

@@ -1,19 +0,0 @@
import Layout from "../components/layout"
export default function ApiExamplePage() {
return (
<Layout>
<h1>API Example</h1>
<p>The examples below show responses from the example API endpoints.</p>
<p>
<em>You must be signed in to see responses.</em>
</p>
<h2>Session</h2>
<p>/api/examples/session</p>
<iframe src="/api/examples/session" />
<h2>JSON Web Token</h2>
<p>/api/examples/jwt</p>
<iframe src="/api/examples/jwt" />
</Layout>
)
}

View File

@@ -1,14 +0,0 @@
// This is an example of how to read a JSON Web Token from an API route
import { getToken } from "next-auth/jwt"
import type { NextApiRequest, NextApiResponse } from "next"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// If you don't have the NEXTAUTH_SECRET environment variable set,
// you will have to pass your secret as `secret` to `getToken`
const token = await getToken({ req })
res.send(JSON.stringify(token, null, 2))
}

View File

@@ -1,22 +0,0 @@
// This is an example of to protect an API route
import { auth } from "auth"
import type { NextApiRequest, NextApiResponse } from "next"
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const session = await auth(req, res)
if (session) {
return res.send({
content:
"This is protected content. You can access this content because you are signed in.",
})
}
res.send({
error: "You must be signed in to view the protected content on this page.",
})
}

View File

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

View File

@@ -1,13 +0,0 @@
import Layout from "../components/layout"
export default function IndexPage() {
return (
<Layout>
<h1>NextAuth.js Example</h1>
<p>
This is an example site to demonstrate how to use{" "}
<a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
</p>
</Layout>
)
}

View File

@@ -1,12 +0,0 @@
import { useSession } from "next-auth/react"
import Layout from "../components/layout"
export default function MePage() {
const { data } = useSession()
return (
<Layout>
<pre>{JSON.stringify(data, null, 2)}</pre>
</Layout>
)
}

View File

@@ -1,32 +0,0 @@
import Layout from "../components/layout"
export default function PolicyPage() {
return (
<Layout>
<p>
This is an example site to demonstrate how to use{" "}
<a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
</p>
<h2>Terms of Service</h2>
<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
</p>
<h2>Privacy Policy</h2>
<p>
This site uses JSON Web Tokens and an in-memory database which resets
every ~2 hours.
</p>
<p>
Data provided to this site is exclusively used to support signing in and
is not passed to any third party services, other than via SMTP or OAuth
for the purposes of authentication.
</p>
</Layout>
)
}

View File

@@ -1,40 +0,0 @@
import { useState, useEffect } from "react"
import { useSession } from "next-auth/react"
import Layout from "../components/layout"
import AccessDenied from "../components/access-denied"
export default function ProtectedPage() {
const { data: session } = useSession()
const [content, setContent] = useState()
// Fetch content from protected route
useEffect(() => {
const fetchData = async () => {
const res = await fetch("/api/examples/protected")
const json = await res.json()
if (json.content) {
setContent(json.content)
}
}
fetchData()
}, [session])
// If no session exists, display access denied message
if (!session) {
return (
<Layout>
<AccessDenied />
</Layout>
)
}
// If session exists, display content
return (
<Layout>
<h1>Protected Page</h1>
<p>
<strong>{content ?? "\u00a0"}</strong>
</p>
</Layout>
)
}

View File

@@ -1,39 +0,0 @@
import { auth } from "auth"
import Layout from "../components/layout"
import type { GetServerSidePropsContext } from "next"
import { useSession } from "next-auth/react"
export default function ServerSidePage() {
const { data: session } = useSession()
// As this page uses Server Side Rendering, the `session` will be already
// populated on render without needing to go through a loading stage.
return (
<Layout>
<h1>Server Side Rendering</h1>
<p>
This page uses the <strong>getServerSession()</strong> method in{" "}
<strong>getServerSideProps()</strong>.
</p>
<p>
Using <strong>getServerSession()</strong> in{" "}
<strong>getServerSideProps()</strong> is the recommended approach if you
need to support Server Side Rendering with authentication.
</p>
<p>
The advantage of Server Side Rendering is this page does not require
client side JavaScript.
</p>
<p>
The disadvantage of Server Side Rendering is that this page is slower to
render.
</p>
<pre>{JSON.stringify(session, null, 2)}</pre>
</Layout>
)
}
// Export the `session` prop to use sessions with Server Side Rendering
export async function getServerSideProps(context: GetServerSidePropsContext) {
return { props: { session: await auth(context.req, context.res) } }
}

16
apps/examples/nextjs/process.d.ts vendored Normal file
View File

@@ -0,0 +1,16 @@
declare namespace NodeJS {
export interface ProcessEnv {
NEXTAUTH_URL: string
NEXTAUTH_SECRET: string
GITHUB_ID: string
GITHUB_SECRET: string
FACEBOOK_ID: string
FACEBOOK_SECRET: string
TWITTER_ID: string
TWITTER_SECRET: string
GOOGLE_ID: string
GOOGLE_SECRET: string
AUTH0_ID: string
AUTH0_SECRET: string
}
}

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "esnext",
"lib": [
"dom",
"dom.iterable",
@@ -8,7 +8,7 @@
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
@@ -16,23 +16,24 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"jsx": "preserve",
"baseUrl": ".",
"plugins": [
{
"name": "next"
}
]
],
"strictNullChecks": true
},
"include": [
"process.d.ts",
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules"
"node_modules",
"jest.config.js"
]
}

View File

@@ -13,7 +13,7 @@
"solid-start-node": "^0.2.9",
"solid-start-vercel": "^0.2.9",
"tailwindcss": "^3.2.4",
"typescript": "5.2.2",
"typescript": "^4.8.3",
"vite": "^3.1.0"
},
"dependencies": {

View File

@@ -18,7 +18,7 @@
"@sveltejs/kit": "next",
"svelte": "3.55.0",
"svelte-check": "2.10.2",
"typescript": "5.2.2",
"typescript": "4.9.4",
"vite": "4.0.1"
},
"dependencies": {

View File

@@ -1,4 +1,4 @@
import { Session } from "@auth/core/types"
import { Session } from "@auth/core"
export default function useSession() {
return useState<Session | null>("session", () => null)

View File

@@ -43,7 +43,7 @@ export async function signIn<
// TODO: Handle custom base path
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
const { csrfToken } = await $fetch<{ csrfToken: string }>("/api/auth/csrf")
const { csrfToken } = await $fetch("/api/auth/csrf")
console.log(_signInUrl)

View File

@@ -1,14 +1,13 @@
import { AuthConfig, Session } from "@auth/core/types"
import { Auth } from "@auth/core"
import { AuthHandler, AuthOptions, Session } from "@auth/core"
import { fromNodeMiddleware, H3Event } from "h3"
import getURL from "requrl"
import { createMiddleware } from "@hattip/adapter-node"
export function NuxtAuthHandler(options: AuthConfig) {
export function NuxtAuthHandler(options: AuthOptions) {
async function handler(ctx: { request: Request }) {
options.trustHost ??= true
return Auth(ctx.request, options)
return AuthHandler(ctx.request, options)
}
const middleware = createMiddleware(handler)
@@ -18,7 +17,7 @@ export function NuxtAuthHandler(options: AuthConfig) {
export async function getSession(
event: H3Event,
options: AuthConfig
options: AuthOptions
): Promise<Session | null> {
options.trustHost ??= true
@@ -31,7 +30,7 @@ export async function getSession(
nodeHeaders.append(key, headers[key] as any)
})
const response = await Auth(
const response = await AuthHandler(
new Request(url, { headers: nodeHeaders }),
options
)

View File

@@ -1,21 +1,21 @@
{
"name": "next-auth-nuxt",
"name": "playground-nuxt",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt prepare && nuxt dev",
"build": "nuxt prepare && nuxt build",
"dev": "nuxt prepare && export NODE_OPTIONS='--no-experimental-fetch' && nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"@nuxt/eslint-config": "^0.1.1",
"eslint": "^8.29.0",
"h3": "1.6.6",
"nuxt": "3.5.1"
"h3": "1.0.2",
"nuxt": "3.0.0"
},
"dependencies": {
"@auth/core": "workspace:*",
"@hattip/adapter-node": "^0.0.34",
"@hattip/adapter-node": "^0.0.22",
"requrl": "^3.0.2"
}
}

View File

@@ -1,4 +1,4 @@
import { Session } from "@auth/core/types"
import { Session } from "@auth/core"
export default defineNuxtPlugin(async () => {
const session = useSession()

View File

@@ -1,10 +1,10 @@
import { NuxtAuthHandler } from "@/lib/auth/server"
import GithubProvider from "@auth/core/providers/github"
import type { AuthConfig } from "@auth/core"
import type { AuthOptions } from "@auth/core"
const runtimeConfig = useRuntimeConfig()
export const authOptions = {
export const authOptions: AuthOptions = {
secret: runtimeConfig.secret,
providers: [
GithubProvider({
@@ -12,6 +12,6 @@ export const authOptions = {
clientSecret: runtimeConfig.github.clientSecret,
}),
],
} as AuthConfig
}
export default NuxtAuthHandler(authOptions)

View File

@@ -37,31 +37,22 @@ This documentation site is based on the [Docusaurus](https://docusaurus.io) fram
To start a local environment of this project, please do the following.
1. Clone the repo:
```sh
git clone git@github.com:nextauthjs/next-auth.git
cd next-auth
```
2. Set up the correct pnpm version, using [Corepack](https://nodejs.org/api/corepack.html). Run the following in the project'a root:
```sh
corepack enable pnpm
```
(Now, if you run `pnpm --version`, it should print the same verion as the `packageManager` property in the [`package.json` file](https://github.com/nextauthjs/next-auth/blob/main/package.json))
3. Install packages. Developing requires Node.js v18:
```sh
pnpm install
```
4. Start the development server
1. Clone the repository.
```bash
$ pnpm dev:docs
$ git clone https://github.com/nextauthjs/docs.git
```
2. Install dependencies
```bash
$ npm install
```
3. Start the development server
```bash
$ npm start
```
And thats all! Now you should have a local copy of this docs site running at [localhost:3000](http://localhost:3000)!

View File

@@ -7,7 +7,7 @@ title: Frequently Asked Questions
### Is Auth.js commercial software?
Auth.js is an open-source project built by individual contributors.
Auth.js is an open source project built by individual contributors.
It is not commercial software and is not associated with a commercial organization.
@@ -17,7 +17,7 @@ It is not commercial software and is not associated with a commercial organizati
<details>
<summary>
<h3 style={{display: "inline-block"}}>What databases does Auth.js support?</h3>
<h3 style={{display:"inline-block"}}>What databases does Auth.js support?</h3>
</summary>
<p>
@@ -30,7 +30,7 @@ You can use also Auth.js with any database using a custom database adapter, or b
<details>
<summary>
<h3 style={{display: "inline-block"}}>What authentication services does Auth.js support?</h3>
<h3 style={{display:"inline-block"}}>What authentication services does Auth.js support?</h3>
</summary>
<p>
@@ -38,16 +38,16 @@ You can use also Auth.js with any database using a custom database adapter, or b
(See also: <a href="/reference/providers/oauth-builtin">Providers</a>)
</p>
Auth.js also supports email for passwordless sign-in, which is useful for account recovery or for people who are not able to use an account with the configured OAuth services (e.g. due to service outage, account suspension or otherwise becoming locked out of an account).
Auth.js also supports email for passwordless sign in, which is useful for account recovery or for people who are not able to use an account with the configured OAuth services (e.g. due to service outage, account suspension or otherwise becoming locked out of an account).
You can also use a custom-based provider to support signing in with a username and password stored in an external database and/or using two-factor authentication.
You can also use a custom based provider to support signing in with a username and password stored in an external database and/or using two factor authentication.
</p>
</details>
<details>
<summary>
<h3 style={{display: "inline-block"}}>Does Auth.js support signing in with a username and password?</h3>
<h3 style={{display:"inline-block"}}>Does Auth.js support signing in with a username and password?</h3>
</summary>
<p>
@@ -55,44 +55,44 @@ Auth.js is designed to avoid the need to store passwords for user accounts.
If you have an existing database of usernames and passwords, you can use a custom credentials provider to allow signing in with a username and password stored in an existing database.
_If you use a custom credentials provider user accounts will not be persisted in a database by Auth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign-in without using a session database) must be enabled to use a custom credentials provider._
_If you use a custom credentials provider user accounts will not be persisted in a database by Auth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign in without using a session database) must be enabled to use a custom credentials provider._
</p>
</details>
<details>
<summary>
<h3 style={{display: "inline-block"}}>Can I use Auth.js with a website that does not use Next.js?</h3>
<h3 style={{display:"inline-block"}}>Can I use Auth.js with a website that does not use Next.js?</h3>
</summary>
<p>
Auth.js is designed for use with Next.js and Serverless.
If you are using a different framework for your website, you can create a website that handles sign-in with Next.js and then access those sessions on a website that does not use Next.js as long as the websites are on the same domain.
If you are using a different framework for your website, you can create a website that handles sign in with Next.js and then access those sessions on a website that does not use Next.js as long as the websites are on the same domain.
If you use Auth.js on a website with a different subdomain than the rest of your website (e.g. `auth.example.com` vs `www.example.com`) you will need to set a custom cookie domain policy for the Session Token cookie. (See also: [Cookies](/reference/configuration/auth-config#cookies))
If you use Auth.js on a website with a different subdomain then the rest of your website (e.g. `auth.example.com` vs `www.example.com`) you will need to set a custom cookie domain policy for the Session Token cookie. (See also: [Cookies](/reference/configuration/auth-config#cookies))
Auth.js does not currently support automatically signing into sites on different top-level domains (e.g. `www.example.com` vs `www.example.org`) using a single session.
Auth.js does not currently support automatically signing into sites on different top level domains (e.g. `www.example.com` vs `www.example.org`) using a single session.
</p>
</details>
<details>
<summary>
<h3 style={{display: "inline-block"}}>Can I use Auth.js with React Native?</h3>
<h3 style={{display:"inline-block"}}>Can I use Auth.js with React Native?</h3>
</summary>
<p>
Auth.js is designed as a secure, confidential client and implements a server-side authentication flow.
Auth.js is designed as a secure, confidential client and implements a server side authentication flow.
It is not intended to be used in native applications on desktop or mobile applications, which typically implement public clients (e.g. with client/secrets embedded in the application).
It is not intended to be used in native applications on desktop or mobile applications, which typically implement public clients (e.g. with client / secrets embedded in the application).
</p>
</details>
<details>
<summary>
<h3 style={{display: "inline-block"}}>Is Auth.js supporting TypeScript?</h3>
<h3 style={{display:"inline-block"}}>Is Auth.js supporting TypeScript?</h3>
</summary>
<p>
@@ -103,11 +103,11 @@ Yes! Check out the [TypeScript docs](/getting-started/typescript)
<details>
<summary>
<h3 style={{display: "inline-block"}}>Is Auth.js compatible with Next.js 12 Middleware?</h3>
<h3 style={{display:"inline-block"}}>Is Auth.js compatible with Next.js 12 Middleware?</h3>
</summary>
<p>
[Next.js Middleware](https://nextjs.org/docs/middleware) is supported. Head over to [this page](https://next-auth.js.org/configuration/nextjs#middleware)
[Next.js Middleware](https://nextjs.org/docs/middleware) is supported. Head over to the [this page](/reference/nextjs/#middleware)
</p>
</details>
@@ -118,7 +118,7 @@ Yes! Check out the [TypeScript docs](/getting-started/typescript)
<details>
<summary>
<h3 style={{display: "inline-block"}}>What databases are supported by Auth.js?</h3>
<h3 style={{display:"inline-block"}}>What databases are supported by Auth.js?</h3>
</summary>
<p>
@@ -131,13 +131,13 @@ It also provides an Adapter API which allows you to connect it to any database.
<details>
<summary>
<h3 style={{display: "inline-block"}}>What does Auth.js use databases for?</h3>
<h3 style={{display:"inline-block"}}>What does Auth.js use databases for?</h3>
</summary>
<p>
Databases in Auth.js are used for persisting users, OAuth accounts, email sign-in tokens and sessions.
Databases in Auth.js are used for persisting users, OAuth accounts, email sign in tokens and sessions.
Specifying a database is optional if you don't need to persist user data or support email sign-in. If you don't specify a database then JSON Web Tokens will be enabled for session storage and used to store session data.
Specifying a database is optional if you don't need to persist user data or support email sign in. If you don't specify a database then JSON Web Tokens will be enabled for session storage and used to store session data.
If you are using a database with Auth.js, you can still explicitly enable JSON Web Tokens for sessions (instead of using database sessions).
@@ -146,24 +146,24 @@ If you are using a database with Auth.js, you can still explicitly enable JSON W
<details>
<summary>
<h3 style={{display: "inline-block"}}>Should I use a database?</h3>
<h3 style={{display:"inline-block"}}>Should I use a database?</h3>
</summary>
<p>
- Using Auth.js without a database works well for internal tools - where you need to control who can sign in, but when you do not need to create user accounts for them in your application.
- Using Auth.js without a database works well for internal tools - where you need to control who is able to sign in, but when you do not need to create user accounts for them in your application.
- Using Auth.js with a database is usually a better approach for a consumer-facing application where you need to persist accounts (e.g. for billing, to contact customers, etc).
- Using Auth.js with a database is usually a better approach for a consumer facing application where you need to persist accounts (e.g. for billing, to contact customers, etc).
</p>
</details>
<details>
<summary>
<h3 style={{display: "inline-block"}}>What database should I use?</h3>
<h3 style={{display:"inline-block"}}>What database should I use?</h3>
</summary>
<p>
Managed database solutions for MySQL, Postgres and MongoDB (and compatible databases) are well supported by cloud providers such as Amazon, Google, Microsoft and Atlas.
Managed database solutions for MySQL, Postgres and MongoDB (and compatible databases) are well supported from cloud providers such as Amazon, Google, Microsoft and Atlas.
If you are deploying directly to a particular cloud platform you may also want to consider serverless database offerings they have (e.g. [Amazon Aurora Serverless on AWS](https://aws.amazon.com/rds/aurora/serverless/)).
@@ -174,49 +174,51 @@ If you are deploying directly to a particular cloud platform you may also want t
## Security
Parts of this section have been moved to their [page](/security)](/security).
Parts of this section has been moved to its [own page](/security).
<details>
<summary>
<h3 style={{display: "inline-block"}}>How do I get Refresh Tokens and Access Tokens for an OAuth account?</h3>
<h3 style={{display:"inline-block"}}>How do I get Refresh Tokens and Access Tokens for an OAuth account?</h3>
</summary>
<p>
Auth.js provides a solution for authentication, session management and user account creation.
Auth.js records Refresh Tokens and Access Tokens on sign-in (if supplied by the provider) and it will pass them, along with the User ID, Provider and Provider Account ID, to either:
Auth.js records Refresh Tokens and Access Tokens on sign in (if supplied by the provider) and it will pass them, along with the User ID, Provider and Provider Account ID, to either:
1. A database - if a database connection string is provided
2. The JSON Web Token callback - if JWT sessions are enabled (e.g. if no database is specified)
2. The JSON Web Token callback - if JWT sessions are enabled (e.g. if no database specified)
You can then look them up from the database or persist them to the JSON Web Token.
Note: Auth.js does not currently handle Access Token rotation for OAuth providers for you, however, you can check out [this tutorial](/guides/basics/refresh-token-rotation) if you want to implement it.
Note: Auth.js does not currently handle Access Token rotation for OAuth providers for you, however you can check out [this tutorial](/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 Auth.js v4 where we demonstrate how to use a refresh token to refresh the provided access token.
</p>
</details>
<details>
<summary>
<h3 style={{display: "inline-block"}}>When I sign in with another account with the same email address, why are accounts not linked automatically?</h3>
<h3 style={{display:"inline-block"}}>When I sign in with another account with the same email address, why are accounts not linked automatically?</h3>
</summary>
<p>
Automatic account linking on sign-in is not secure between arbitrary providers - except for allowing users to sign in via email addresses as a fallback (as they must verify their email address as part of the flow).
Automatic account linking on sign in is not secure between arbitrary providers - with the exception of allowing users to sign in via an email addresses as a fallback (as they must verify their email address as part of the flow).
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to the account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
With automatic account linking on sign-in, this can be exploited by bad parties to hijack accounts by creating an OAuth account associated with the email address of another user.
With automatic account linking on sign in, this can be exploited by bad actors to hijack accounts by creating an OAuth account associated with the email address of another user.
For this reason, it is not secure to automatically link accounts between arbitrary providers on sign-in, which is why this feature is generally not provided by an authentication service and is not provided by Auth.js.
For this reason it is not secure to automatically link accounts between arbitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by Auth.js.
Automatic account linking is seen on some sites, sometimes insecurely. It can be technically possible to do automatic account linking securely if you trust all the providers involved to ensure they have securely verified the email address associated with the account, but requires placing trust (and transferring the risk) to those providers to handle the process securely.
Examples of scenarios where this is secure include an OAuth provider you control (e.g. that only authorizes users internal to your organization) or a provider you explicitly trust to have verified the users' email address.
Examples of scenarios where this is secure include with an OAuth provider you control (e.g. that only authorizes users internal to your organization) or with a provider you explicitly trust to have verified the users email address.
Automatic account linking is not a planned feature of Auth.js, however, there is scope to improve the user experience of account linking and of handling this flow, securely. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved.
Automatic account linking is not a planned feature of Auth.js, however there is scope to improve the user experience of account linking and of handling this flow, in a secure way. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved on.
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in - was originally a feature in v1.x but has not been present since v2.0, and is planned to return in a future release.
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in already - was originally a feature in v1.x but has not been present since v2.0, is planned to return in a future release.
</p>
</details>
@@ -227,11 +229,11 @@ Providing support for secure account linking and unlinking of additional provide
<details>
<summary>
<h3 style={{display: "inline-block"}}>Why doesn't Auth.js support [a particular feature]?</h3>
<h3 style={{display:"inline-block"}}>Why doesn't Auth.js support [a particular feature]?</h3>
</summary>
<p>
Auth.js is an open-source project built by individual contributors who are volunteers writing code and providing support in their spare time.
Auth.js is an open source project built by individual contributors who are volunteers writing code and providing support in their spare time.
If you would like Auth.js to support a particular feature, the best way to help make it happen is to raise a feature request describing the feature and offer to work with other contributors to develop and test it.
@@ -242,13 +244,13 @@ If you are not able to develop a feature yourself, you can offer to sponsor some
<details>
<summary>
<h3 style={{display: "inline-block"}}>I disagree with a design decision, how can I change your mind?</h3>
<h3 style={{display:"inline-block"}}>I disagree with a design decision, how can I change your mind?</h3>
</summary>
<p>
Product design decisions on Auth.js are made by core team members.
You can raise suggestions as feature requests for enhancement.
You can raise suggestions as feature requests / requests for enhancement.
Requests that provide the detail requested in the template and follow the format requested may be more likely to be supported, as additional detail prompted in the templates often provides important context.
@@ -284,7 +286,7 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
- JSON Web Tokens in Auth.js are secured using cryptographic encryption (JWE) to store the included information directly in a JWT session token. You may then use the token to pass information between services and APIs on the same domain without having to contact a database to verify the included information.
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only cookie so data in the JWT is not accessible to third-party JavaScript running on your site.
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only cookie so data in the JWT is not accessible to third party JavaScript running on your site.
</p>
</details>
@@ -295,15 +297,15 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
</summary>
<p>
- It's difficult to invalidate a JSON Web Token - doing so requires maintaining a server-side blocklist of the tokens (at least until they expire) and checking every token against the list every time a token is presented.
- You cannot as easily expire a JSON Web Token - doing so requires maintaining a server side blocklist of invalid tokens (at least until they expire) and checking every token against the list every time a token is presented.
Shorter session expiry times are used when using JSON Web Tokens as session tokens to allow sessions to be invalidated sooner and simplify this problem.
Auth.js client includes advanced features to mitigate the downsides of using shorter session expiry times on the user experience, including automatic session token rotation, optionally sending keep-alive messages to prevent short-lived sessions from expiring if there is a window or tab opened, background re-validation, and automatic tab/window syncing that keeps sessions in sync across windows any time session state changes or a window or tab gains or loses focus.
Auth.js client includes advanced features to mitigate the downsides of using shorter session expiry times on the user experience, including automatic session token rotation, optionally sending keep alive messages to prevent short lived sessions from expiring if there is an window or tab open, background re-validation, and automatic tab/window syncing that keeps sessions in sync across windows any time session state changes or a window or tab gains or loses focus.
- As with database session tokens, JSON Web Tokens are limited in the amount of data you can store in them. There is typically a limit of around 4096 bytes per cookie, though the exact limit varies between browsers, proxies and hosting services. If you want to support most browsers, then do not exceed 4096 bytes per cookie. If you want to save more data, you will need to persist your sessions in a database (Source: [browsercookielimits.iain.guru](http://browsercookielimits.iain.guru/))
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. Auth.js uses cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing. However, since this data needs to be transmitted on every request, in case you wish to store more than ~4 KB of data you're probably at the point where you want to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing. However since this data needs to be transmitted on every request, if you wish to store more than ~4 KB of data you're probably at the point where you want to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
- Data stored in an encrypted JSON Web Token (JWE) may be compromised at some point.
@@ -311,7 +313,7 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
Avoid storing any data in a token that might be problematic if it were to be decrypted in the future.
- If you do not explicitly specify a secret for Auth.js, existing sessions will be invalidated any time your Auth.js configuration changes, as Auth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
- If you do not explicitly specify a secret for for Auth.js, existing sessions will be invalidated any time your Auth.js configuration changes, as Auth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
</p>
</details>
@@ -322,10 +324,12 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
</summary>
<p>
By default, tokens are encrypted (JWE).
By default tokens are not signed (JWS) but are encrypted (JWE). Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing.
You can specify other valid algorithms - [as specified in RFC 7518](https://tools.ietf.org/html/rfc7517) - with either a secret (for symmetric encryption) or a public/private key pair (for asymmetric encryption).
Auth.js will generate keys for you, but this will generate a warning at start up.
Using explicit public/private keys for signing is strongly recommended.
</p>

View File

@@ -2,9 +2,6 @@
title: Credentials authentication
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
Auth.js is built in a way that is flexible to integrate it with any authentication back-end you or your company may already have.
This library has been designed to handle the user session client-wise, to support multiple authentication methods (OAuth, Email, etc...) so that you're not forced to run your own authentication service.
@@ -19,49 +16,34 @@ The functionality provided for credentials based authentication is intentionally
Integrating the Credentials Provider is as simple as initializing it in the Auth.js configuration file:
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials) {
const authResponse = await fetch("/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
})
export default NextAuth({
providers: [
CredentialsProvider({
async authorize(credentials) {
const authResponse = await fetch("/users/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(credentials),
})
if (!authResponse.ok) {
return null
}
if (!authResponse.ok) {
return null
}
const user = await authResponse.json()
const user = await authResponse.json()
return user
},
}),
],
})
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
return user
},
}),
],
})
```
:::note
Check the [Credentials Provider options](/reference/core/providers_credentials) for further customization

View File

@@ -7,8 +7,6 @@ import startPageImg from "./img/email-tutorial-start.png"
import checkPageImg from "./img/email-tutorial-check.png"
import mailboxImg from "./img/email-tutorial-mailbox.png"
import loggedInImg from "./img/email-tutorial-logged.png"
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
Aside from authenticating users in Auth.js via [OAuth](/getting-started/oauth-tutorial), you can also enable the option to authenticate them via "magic links". These are links that are sent to the user's email and when clicking on them they'll sign up the user automatically.
@@ -36,7 +34,7 @@ npm install -D nodemailer
## 2. Setting up a SMTP service
Next we need a [SMTP service](https://sendgrid.com/blog/what-is-an-smtp-server/) which will be in charge of sending emails from our application. There's a number of services available for this, however [here are the ones](https://community.nodemailer.com/2-0-0-beta/setup-smtp/well-known-services) known to work with `nodemailer`.
Next we need a [SMTP service](https://sendgrid.com/blog/what-is-an-smtp-server/) which will be in charge of sending emails from our application. There's a number of services available for this, however [here are the ones](http://nodemailer.com/smtp/well-known/) known to work with `nodemailer`.
:::info
For this tutorial, we're going to be using [Sendgrid](https://sendgrid.com/), but any of the services linked above should work the same
@@ -66,43 +64,26 @@ Note that we're also specifying from which domain email are going to be sent fro
Nice! We're getting there. Now we need to read supply this values as the configuration for our Email Provider. Open `pages/api/auth/[...nextauth].ts` and do the following:
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Email from "next-auth/providers/email"
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Email from "next-auth/providers/email"
export default NextAuth({
providers: [
Email({
server: {
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
},
export default NextAuth({
providers: [
Email({
server: {
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
},
from: process.env.EMAIL_FROM,
}),
],
})
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
},
from: process.env.EMAIL_FROM,
}),
],
})
```
## 3. Setting up an adapter
@@ -110,12 +91,12 @@ Finally, we'll need to set up a database adapter to store verification tokens th
An **Adapter** in Auth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc...
For this tutorial, we're going to use the **MongoDB** adapter, but any of the other adapters will work just fine.
For this tutorial, we're going to use the **MongoDB** adapter, other any of the other adapters will work just fine.
First, let's start by installing the adapter package:
```bash npm2yarn2pnpm
npm install -D @auth/mongodb-adapter mongodb
npm install -D @next-auth/mongodb-adapter mongodb
```
and create a simple MongoDB client:
@@ -158,46 +139,30 @@ export default clientPromise
And now let's reference this new adapter from our Auth.js configuration file:
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```diff title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import EmailProvider from "next-auth/providers/email"
+ import { MongoDBAdapter } from "@auth/mongodb-adapter"
+ import clientPromise from "../../../lib/mongodb/client"
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
+ adapter: MongoDBAdapter(clientPromise),
providers: [
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
})
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
```diff title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import EmailProvider from "next-auth/providers/email"
+ import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
+ import clientPromise from "../../../lib/mongodb/client"
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
+ adapter: MongoDBAdapter(clientPromise),
providers: [
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: process.env.EMAIL_SERVER_PORT,
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD
}
},
from: process.env.EMAIL_FROM
}),
],
})
```
## 4. Wiring all together

View File

@@ -36,10 +36,6 @@ This tutorial assumes you have a Next.js application set up. If you don't, you c
npm install next-auth
```
:::info
We are working on a new release of `next-auth` that will make it easier to set up Auth.js with Next.js. You can follow the development [on this PR](https://github.com/nextauthjs/next-auth/pull/7443)
:::
### Creating the server config
Create the following [API route](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes) file. This route contains the necessary configuration for NextAuth.js, as well as the dynamic route handler:
@@ -100,12 +96,11 @@ NextAuth.js provides [`useSession()`](/reference/react/#usesession) - a [React H
```ts title="pages/_app.tsx"
import { SessionProvider } from "next-auth/react"
import type { AppProps } from "next/app"
export default function App({
Component,
pageProps: { session, ...pageProps },
}: AppProps) {
}) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
@@ -156,7 +151,7 @@ export default function CamperVanPage() {
### Protecting API Routes
To protect your API Routes (blocking unauthorized access to resources), you can use [`getServerSession()`](https://next-auth.js.org/configuration/nextjs#getserversession) to know whether a session exists or not:
To protect your API Routes (blocking unauthorized access to resources), you can use [`getServerSession()`](/reference/nextjs#getserversession) to know whether a session exists or not:
```ts title="pages/api/movies/list.ts"
import { getServerSession } from "next-auth/next"
@@ -182,127 +177,7 @@ export default async function listMovies(req, res) {
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
:::warning
`@auth/sveltekit` is currently experimental. The API _will_ change in the future.
:::
### Prerequisites
This tutorial assumes you have a SvelteKit application set up. If you don't, you can follow the [SvelteKit tutorial](https://kit.svelte.dev/docs/creating-a-project) to get started.
### Installing Auth.js
```bash npm2yarn
npm install @auth/core @auth/sveltekit
```
### Create server hook
Create the following [Server hook](https://kit.svelte.dev/docs/hooks) file. This route contains the necessary configuration for Auth.js, as well as the dynamic route handler:
```ts title="src/hooks.server.ts"
import { SvelteKitAuth } from "@auth/sveltekit"
import GitHub from "@auth/core/providers/github"
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
*
export const handle = SvelteKitAuth({
providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
})
```
:::info
Behind the scenes, this creates all the relevant OAuth API routes within `/api/auth/*` so that auth API requests to:
- [GET `/api/auth/signin`](https://authjs.dev/reference/rest-api#get--apiauthsignin)
- [POST `/api/auth/signin/:provider`](https://authjs.dev/reference/rest-api#post--apiauthsigninprovider)
- [GET/POST `/api/auth/callback/:provider`](https://authjs.dev/reference/rest-api#get--post--apiauthcallbackprovider)
- [GET `/api/auth/signout`](https://authjs.dev/reference/rest-api#get--apiauthsignout)
- [POST `/api/auth/signout`](https://authjs.dev/reference/rest-api#post--apiauthsignout)
- [GET `/api/auth/session`](https://authjs.dev/reference/rest-api#get--apiauthsession)
- [GET `/api/auth/csrf`](https://authjs.dev/reference/rest-api#get--apiauthcsrf)
- [GET `/api/auth/providers`](https://authjs.dev/reference/rest-api#get--apiauthproviders)
can be handled by Auth.js. In this way, Auth.js stays in charge of the whole application's authentication request/response flow.
Auth.js is fully customizable - [our guides section](/guides/overview) teaches you how to set it up to handle auth in different ways. All the possible configuration options are [listed here](/reference/configuration/auth-config).
:::
### Adding environment variables
You may notice we are using environment variables in the code example above. We take the value of `GITHUB_ID` and `GITHUB_SECRET` from the GitHub Developer OAuth Portal. See [Configuring OAuth Provider](/getting-started/oauth-tutorial#2-configuring-oauth-provider) section on how to get those.
In your project root, create a `.env.local` file and add the `AUTH_SECRET` environment variable:
```title=".env.local"
AUTH_SECRET="This is an example"
```
`AUTH_SECRET` is a random string used by the library to encrypt tokens and email verification hashes, and **it's mandatory to keep things secure**! 🔥 🔐 . You can use:
```
$ openssl rand -base64 32
```
or https://generate-secret.vercel.app/32 to generate a random value for it.
### Exposing the session via page store
Auth.js provides us a getSession, function to access the session data and status, to call from the `event.locals` variable. We can now just call it and add it to our `$page` store.
```ts
import type { LayoutServerLoad } from './$types';
*
export const load: LayoutServerLoad = async (event) => {
return {
session: await event.locals.getSession()
};
};
```
### Consuming the session via page store
You can use the `$page.data.session` variable from anywhere on your page. Learn more about SvelteKit's page store in the [SvelteKit docs](https://learn.svelte.dev/tutorial/page-store).
```ts title="route/+page.svelte"
<script>
import { signIn, signOut } from '@auth/sveltekit/client'
import { page } from '$app/stores'
</script>
{#if $page.data.session?.user}
<p>Signed in as {$page.data.session.user.email}</p>
<button on:click={signOut}>Sign out</button>
<img src="https://cdn.pixabay.com/photo/2017/08/11/19/36/vw-2632486_1280.png" />
{:else}
<p>Not signed in.</p>
<button on:click={() => signIn('github')}>Sign in</button>
{/if}
```
### Protecting API Routes
To protect your API Routes (blocking unauthorized access to resources), you can use `locals.getSessions()` just like in the layouts file to know whether a session exists or not:
```ts title="routes/api/movies/+server.ts"
import { json, error } from "@sveltejs/kit";
import type { RequestEvent } from "./$types";
export async function GET({ locals }: RequestEvent) {
const session = await locals.getSession()
if (!session?.user) {
throw error(401, "You must sign in to view movies.");
}
return json({
movies: [
{ title: "Alien vs Predator", id: 1 },
{ title: "Reservoir Dogs", id: 2 },
]
})
}
```
TODO: SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO: SolidStart
@@ -338,7 +213,7 @@ The callback URL we insert should have the following pattern:
In this case, given we want to try our authentication working locally on our machine and we're using **GitHub** as our OAuth provider, it'll be:
<Tabs groupId="frameworks" queryString>
<Tabs groupId="frameworks">
<TabItem value="next" label="Next.js" default>
```
@@ -364,13 +239,10 @@ http://localhost:5173/auth/callback/github
TODO Core
</TabItem>
</Tabs>
:::info
The last part of the URL, `[provider]`, is the ID of the provider you're using. In this case, we're using GitHub, so it's `github`. If you're using Google, it'll be `google`, etc... We keep track of the provider IDs internally.
The same id is used in the `signIn()` method we saw earlier.
:::
To register, tap on "Register application" button.
The next screen shows all the configurations for your newly created OAuth app. For now, we need two things from it - the **Client ID** and **Client Secret**:
@@ -409,7 +281,7 @@ GITHUB_SECRET=67890
Here is our server configuration file again:
<Tabs groupId="frameworks" queryString>
<Tabs groupId="frameworks">
<TabItem value="next" label="Next.js" default>
```ts title="pages/api/auth/[...nextauth].ts"
@@ -434,24 +306,7 @@ $ npm run next dev
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
```ts title="src/hooks.server.ts"
import { SvelteKitAuth } from "@auth/sveltekit"
import GitHub from "@auth/core/providers/github"
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
*
export const handle = SvelteKitAuth({
providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
})
```
Great! We're now ready to run our application locally. Start the Svelte app by running on your terminal the following command and navigating to [`http://localhost:5173`](http://localhost:5173):
```
$ npm run vite dev
```
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart

View File

@@ -9,9 +9,6 @@ https://github.com/nextauthjs/next-auth-example
---
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
## Adapters
If you're writing your own custom Adapter, you can take advantage of the types to make sure your implementation conforms to what's expected:
@@ -49,45 +46,30 @@ This will work in code editors with a strong TypeScript integration like VSCode
Let's look at `Session`:
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
export default NextAuth({
callbacks: {
session({ session, token, user }) {
return session // The return type will match the one returned in `useSession()`
},
export default NextAuth({
callbacks: {
session({ session, token, user }) {
return session // The return type will match the one returned in `useSession()`
},
})
```
},
})
```
```ts title="pages/index.ts"
import { useSession } from "next-auth/react"
```ts title="pages/index.ts"
import { useSession } from "next-auth/react"
export default function IndexPage() {
// `session` will match the returned value of `callbacks.session()` from `NextAuth()`
const { data: session } = useSession()
export default function IndexPage() {
// `session` will match the returned value of `callbacks.session()` from `NextAuth()`
const { data: session } = useSession()
return (
// Your component
)
}
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
return (
// Your component
)
}
```
To extend/augment this type, create a `types/next-auth.d.ts` file in your project:

View File

@@ -0,0 +1,32 @@
---
title: Upgrade Guide (v5)
---
NextAuth.js version 5 will continue to be shipped as `next-auth` *for the Next.js version only*. We're here to help you upgrade your applications as smoothly as possible. It is possible to upgrade from any version of 4.x to the latest v5 release by following the migration steps below.
Upgrade to the latest version by running:
```bash npm2yarn2pnpm
npm install next-auth
```
## Getting Started
Below is a summary of the high-level API changes in `next-auth` v5.
```
| Where | Old | New |
| ------------------------- | --------------------------------------------------- | -------------- |
| API Route (Node) | getServerSession(req, res, authOptions) | auth() wrapper |
| API Route (Edge) | - | auth() wrapper |
| getServerSideProps | getServerSession(ctx.req, ctx.res, authOptions) | auth() wrapper |
| Middleware | withAuth(middleware, subset of authOptions) wrapper | auth() wrapper |
| Route Handler | - | auth() wrapper |
| Server Component | getServerSession(authOptions) | auth() call |
| Client Component | useSession() hook | useAuth() hook |
```
## Summary
We hope this migration goes smoothly for each and every one of you! If you have any questions or get stuck anywhere, feel free to create [a new issue](https://github.com/nextauthjs/next-auth/issues/new) on GitHub.

View File

@@ -2,12 +2,12 @@
title: Using a database adapter
---
An **Adapter** in Auth.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](/getting-started/email-tutorial) requires an adapter to be able to save [Verification Tokens](/reference/adapters#verification-token).
An **Adapter** in Auth.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](/getting-started/email-tutorial) requires an adapter to be able to save [Verification Tokens](/reference/adapters/models#verification-token).
:::tip
When using a database, you can still use JWT for session handling for fast access. See the [`session.strategy`](/reference/configuration/auth-config#session) option. Read about the trade-offs of JWT in the [FAQ](/concepts/faq#json-web-tokens).
:::
We have a list of official adapters that are distributed as their own packages under the `@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):
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):
- [All available adapters](/reference/adapters)

View File

@@ -12,7 +12,7 @@ If you want to pass data such as an Access Token or User ID to the browser when
You can specify a handler for any of the callbacks below.
```js title="auth.js"
```js title="pages/api/auth/[...nextauth].js"s
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
return true
@@ -35,7 +35,7 @@ The documentation below shows how to implement each callback, their default beha
Use the `signIn()` callback to control if a user is allowed to sign in.
```js title="auth.js"
```js title="pages/api/auth/[...nextauth].js"
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
const isAllowedToSignIn = true
@@ -79,7 +79,7 @@ By default only URLs on the same URL as the site are allowed, you can use the re
The default redirect callback looks like this:
```js title="auth.js"
```js title="pages/api/auth/[...nextauth].js"
callbacks: {
async redirect({ url, baseUrl }) {
// Allows relative callback URLs
@@ -107,7 +107,7 @@ Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`,
The contents _user_, _account_, _profile_ and _isNewUser_ will vary depending on the provider and on if you are using a database or not. You can persist data such as User ID, OAuth Access Token in this token. To make it available in the browser, check out the [`session()` callback](#session-callback) as well.
```js title="auth.js"
```js title="pages/api/auth/[...nextauth].js"
callbacks: {
async jwt({ token, account }) {
// Persist the OAuth access_token to the token right after signin
@@ -132,7 +132,7 @@ 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.
```js title="auth.js"
```js title="pages/api/auth/[...nextauth].js"
callbacks: {
async session({ session, token, user }) {
// Send properties to the client, like an access_token from a provider.

View File

@@ -34,7 +34,7 @@ Most OAuth providers cannot be configured with multiple callback URLs or using a
However, Auth.js **supports Preview deployments**, even **with OAuth providers**:
1. Determine a stable deployment URL. Eg.: A deployment whose URL does not change between builds, for example. `auth.yourdomain.com` (using a subdomain is not a requirement, this can simply be the main site's URL too.),
1. Determine a stable deployment URL. Eg.: A deployment whose URL does not change between builds, for example. `auth.yourdomain.com`),
2. Set `AUTH_REDIRECT_PROXY_URL` to that URL, adding the path up until your `[...nextauth]` route. Eg.: (`https://auth.yourdomain.com/api/auth`)
3. For your OAuth provider, set the callback URL using the stable deployment URL. Eg.: For GitHub `https://auth.yourdomain.com/api/auth/callback/github`)
@@ -42,9 +42,6 @@ However, Auth.js **supports Preview deployments**, even **with OAuth providers**
To support preview deployments, the `AUTH_SECRET` value needs to be the same for the stable deployment and deployments that will need OAuth support.
:::
:::note
If you are storing users in a [database](reference/adapters), we recommend using a different OAuth app for development/production so that you don't mix your test and production user base.
:::
<details>
<summary>

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