mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
75 Commits
feat/nextj
...
@auth/core
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
50a88bb878 | ||
|
|
a359a562ce | ||
|
|
7edb9cf53f | ||
|
|
018b086c4f | ||
|
|
173000a068 | ||
|
|
8fcd46b0fc | ||
|
|
d5d1313914 | ||
|
|
3285d04241 | ||
|
|
fe442522ef | ||
|
|
6c9dfff45f | ||
|
|
ef50916ec2 | ||
|
|
8e771a2993 | ||
|
|
06a7149b66 | ||
|
|
662e0942cb | ||
|
|
91c71a175b | ||
|
|
3b8c75297b | ||
|
|
5d06fa5852 | ||
|
|
e7a52077c5 | ||
|
|
6e4516a9f8 | ||
|
|
8a0b11fcd6 | ||
|
|
f925e0c2a5 | ||
|
|
de4e20cc04 | ||
|
|
65f4b9c942 | ||
|
|
1d29b0d220 | ||
|
|
cd92aa0c82 | ||
|
|
d414e01181 | ||
|
|
43deda5bfb | ||
|
|
7e79d8c509 | ||
|
|
ab051162a7 | ||
|
|
87298a0150 | ||
|
|
d6abccd9a0 | ||
|
|
2f35daae37 | ||
|
|
a0f3b04c43 | ||
|
|
c7dec376a1 | ||
|
|
925a52e0ec | ||
|
|
2318e44de4 | ||
|
|
d73812bce5 | ||
|
|
ee36d09a08 | ||
|
|
0cb7fd2e7c | ||
|
|
3b414bd7b5 | ||
|
|
37bb6ebd2c | ||
|
|
2ecf52c342 | ||
|
|
cda07c239e | ||
|
|
fa60b79abe | ||
|
|
39e1a76e8f | ||
|
|
953ef9d04a | ||
|
|
94f3031765 | ||
|
|
ad7bf07ddf | ||
|
|
f30308ac30 | ||
|
|
6eaaeb15e9 | ||
|
|
8b3f0696a5 | ||
|
|
c69a157832 | ||
|
|
60af446338 | ||
|
|
ce85444760 | ||
|
|
142abe3eea | ||
|
|
da211e6cbe | ||
|
|
79ad6156ed | ||
|
|
28f287d63e | ||
|
|
1ab77d0e11 | ||
|
|
787c1ff7d0 | ||
|
|
208b3b4a43 | ||
|
|
c4f6330f70 | ||
|
|
44127068e1 | ||
|
|
9e3f1aacf7 | ||
|
|
83051c6862 | ||
|
|
f1acab67e6 | ||
|
|
6a31ed3216 | ||
|
|
0998fc0b98 | ||
|
|
bd20d750c2 | ||
|
|
8e29b4df0c | ||
|
|
9632a56d45 | ||
|
|
12161b9613 | ||
|
|
a3b5276a5a | ||
|
|
7c1078b9a9 | ||
|
|
37d3461155 |
28
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
28
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -21,20 +21,20 @@ body:
|
|||||||
multiple: true
|
multiple: true
|
||||||
options:
|
options:
|
||||||
- "Custom adapter"
|
- "Custom adapter"
|
||||||
- "@next-auth/dgraph-adapter"
|
- "@auth/dgraph-adapter"
|
||||||
- "@next-auth/dynamodb-adapter"
|
- "@auth/dynamodb-adapter"
|
||||||
- "@next-auth/fauna-adapter"
|
- "@auth/fauna-adapter"
|
||||||
- "@next-auth/firebase-adapter"
|
- "@auth/firebase-adapter"
|
||||||
- "@next-auth/mikro-orm-adapter"
|
- "@auth/mikro-orm-adapter"
|
||||||
- "@next-auth/mongodb-adapter"
|
- "@auth/mongodb-adapter"
|
||||||
- "@next-auth/neo4j-adapter"
|
- "@auth/neo4j-adapter"
|
||||||
- "@next-auth/pouchdb-adapter"
|
- "@auth/pouchdb-adapter"
|
||||||
- "@next-auth/prisma-adapter"
|
- "@auth/prisma-adapter"
|
||||||
- "@next-auth/sequelize-adapter"
|
- "@auth/sequelize-adapter"
|
||||||
- "@next-auth/supabase-adapter"
|
- "@auth/supabase-adapter"
|
||||||
- "@next-auth/typeorm-legacy-adapter"
|
- "@auth/typeorm-adapter"
|
||||||
- "@next-auth/upstash-redis-adapter"
|
- "@auth/upstash-redis-adapter"
|
||||||
- "@next-auth/xata-adapter"
|
- "@auth/xata-adapter"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
|||||||
30
.github/issue-labeler.yml
vendored
30
.github/issue-labeler.yml
vendored
@@ -1,43 +1,43 @@
|
|||||||
# https://github.com/github/issue-labeler#basic-examples
|
# https://github.com/github/issue-labeler#basic-examples
|
||||||
|
|
||||||
dgraph:
|
dgraph:
|
||||||
- "@next-auth/dgraph-adapter"
|
- "@auth/dgraph-adapter"
|
||||||
|
|
||||||
dynamodb:
|
dynamodb:
|
||||||
- "@next-auth/dynamodb-adapter"
|
- "@auth/dynamodb-adapter"
|
||||||
|
|
||||||
fauna:
|
fauna:
|
||||||
- "@next-auth/fauna-adapter"
|
- "@auth/fauna-adapter"
|
||||||
|
|
||||||
firebase:
|
firebase:
|
||||||
- "@next-auth/firebase-adapter"
|
- "@auth/firebase-adapter"
|
||||||
|
|
||||||
mikro-orm:
|
mikro-orm:
|
||||||
- "@next-auth/mikro-orm-adapter"
|
- "@auth/mikro-orm-adapter"
|
||||||
|
|
||||||
mongodb:
|
mongodb:
|
||||||
- "@next-auth/mongodb-adapter"
|
- "@auth/mongodb-adapter"
|
||||||
|
|
||||||
neo4j:
|
neo4j:
|
||||||
- "@next-auth/neo4j-adapter"
|
- "@auth/neo4j-adapter"
|
||||||
|
|
||||||
pouchdb:
|
pouchdb:
|
||||||
- "@next-auth/pouchdb-adapter"
|
- "@auth/pouchdb-adapter"
|
||||||
|
|
||||||
prisma:
|
prisma:
|
||||||
- "@next-auth/prisma-adapter"
|
- "@auth/prisma-adapter"
|
||||||
|
|
||||||
sequelize:
|
sequelize:
|
||||||
- "@next-auth/sequelize-adapter"
|
- "@auth/sequelize-adapter"
|
||||||
|
|
||||||
supabase:
|
supabase:
|
||||||
- "@next-auth/supabase-adapter"
|
- "@auth/supabase-adapter"
|
||||||
|
|
||||||
typeorm-legacy:
|
typeorm:
|
||||||
- "@next-auth/typeorm-legacy-adapter"
|
- "@auth/typeorm-adapter"
|
||||||
|
|
||||||
upstash-redis:
|
upstash-redis:
|
||||||
- "@next-auth/upstash-redis-adapter"
|
- "@auth/upstash-redis-adapter"
|
||||||
|
|
||||||
xata:
|
xata:
|
||||||
- "@next-auth/xata-adapter"
|
- "@auth/xata-adapter"
|
||||||
|
|||||||
2
.github/pr-labeler.yml
vendored
2
.github/pr-labeler.yml
vendored
@@ -21,6 +21,6 @@ solidjs: ["packages/frameworks-solid-start/**/*"]
|
|||||||
supabase: ["packages/adapter-supabase/**/*"]
|
supabase: ["packages/adapter-supabase/**/*"]
|
||||||
svelte: ["packages/frameworks-sveltekit/**/*"]
|
svelte: ["packages/frameworks-sveltekit/**/*"]
|
||||||
test: ["**test**/*"]
|
test: ["**test**/*"]
|
||||||
typeorm-legacy: ["packages/adapter-typeorm-legacy/**/*"]
|
typeorm: ["packages/adapter-typeorm/**/*"]
|
||||||
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
|
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
|
||||||
xata: ["packages/adapter-xata/**/*"]
|
xata: ["packages/adapter-xata/**/*"]
|
||||||
|
|||||||
9
.github/version-pr/index.js
vendored
9
.github/version-pr/index.js
vendored
@@ -5,14 +5,15 @@ const core = require("@actions/core")
|
|||||||
try {
|
try {
|
||||||
const packageJSONPath = path.join(
|
const packageJSONPath = path.join(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
"packages/next-auth/package.json"
|
`packages/${process.env.PACKAGE_PATH || "next-auth"}/package.json`
|
||||||
)
|
)
|
||||||
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"))
|
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"))
|
||||||
|
|
||||||
const sha8 = process.env.GITHUB_SHA.substring(0, 8)
|
const sha8 = process.env.GITHUB_SHA.substring(0, 8)
|
||||||
const prNumber = process.env.PR_NUMBER
|
const prefix = "0.0.0-"
|
||||||
|
const pr = process.env.PR_NUMBER
|
||||||
const packageVersion = `0.0.0-pr.${prNumber}.${sha8}`
|
const source = pr ? `pr.${pr}` : "manual"
|
||||||
|
const packageVersion = `${prefix}${source}.${sha8}`
|
||||||
packageJSON.version = packageVersion
|
packageJSON.version = packageVersion
|
||||||
core.setOutput("version", packageVersion)
|
core.setOutput("version", packageVersion)
|
||||||
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON))
|
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON))
|
||||||
|
|||||||
84
.github/workflows/release.yml
vendored
84
.github/workflows/release.yml
vendored
@@ -8,6 +8,54 @@ on:
|
|||||||
- next
|
- next
|
||||||
- 3.x
|
- 3.x
|
||||||
pull_request:
|
pull_request:
|
||||||
|
# TODO: Support latest releases
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
name:
|
||||||
|
type: choice
|
||||||
|
description: Package name (npm)
|
||||||
|
options:
|
||||||
|
- "@auth/core"
|
||||||
|
- "@auth/nextjs"
|
||||||
|
- "@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"
|
||||||
|
# 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"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
@@ -24,6 +72,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
cache: "pnpm"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
@@ -73,6 +122,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
cache: "pnpm"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
- name: Publish to npm and GitHub
|
- name: Publish to npm and GitHub
|
||||||
@@ -97,6 +147,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 18
|
||||||
|
cache: "pnpm"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install
|
run: pnpm install
|
||||||
- name: Determine version
|
- name: Determine version
|
||||||
@@ -122,3 +173,36 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
VERSION: ${{ steps.determine-version.outputs.version }}
|
VERSION: ${{ steps.determine-version.outputs.version }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
|
||||||
|
release-manual:
|
||||||
|
name: Publish manually
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||||
|
steps:
|
||||||
|
- name: Init
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install pnpm
|
||||||
|
uses: pnpm/action-setup@v2.2.4
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
cache: "pnpm"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: pnpm install
|
||||||
|
- name: Determine version
|
||||||
|
uses: ./.github/version-pr
|
||||||
|
id: determine-version
|
||||||
|
env:
|
||||||
|
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
|
||||||
|
echo "🎉 Experimental release published 📦️ on npm: https://npmjs.com/package/${{ github.event.inputs.name }}/v/${{ env.VERSION }}"
|
||||||
|
echo "Install via: pnpm add ${{ github.event.inputs.name }}@${{ env.VERSION }}"
|
||||||
|
env:
|
||||||
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
PACKAGE_PATH: ${{ github.event.inputs.path }}
|
||||||
|
VERSION: ${{ steps.determine-version.outputs.version }}
|
||||||
|
|||||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -26,10 +26,19 @@ dist
|
|||||||
# Generated files
|
# Generated files
|
||||||
.docusaurus
|
.docusaurus
|
||||||
.cache-loader
|
.cache-loader
|
||||||
|
packages/next-auth/providers
|
||||||
|
packages/next-auth/src/providers/oauth-types.ts
|
||||||
|
packages/next-auth/client
|
||||||
|
packages/next-auth/css
|
||||||
|
packages/next-auth/utils
|
||||||
|
packages/next-auth/core
|
||||||
|
packages/next-auth/jwt
|
||||||
|
packages/next-auth/react
|
||||||
|
packages/next-auth/next
|
||||||
packages/*/*.js
|
packages/*/*.js
|
||||||
packages/*/*.d.ts
|
packages/*/*.d.ts
|
||||||
packages/*/*.d.ts.map
|
packages/*/*.d.ts.map
|
||||||
|
packages/*/lib
|
||||||
|
|
||||||
# Development app
|
# Development app
|
||||||
apps/dev/src/css
|
apps/dev/src/css
|
||||||
@@ -77,10 +86,7 @@ packages/core/providers
|
|||||||
packages/core/src/lib/pages/styles.ts
|
packages/core/src/lib/pages/styles.ts
|
||||||
docs/docs/reference/core
|
docs/docs/reference/core
|
||||||
docs/docs/reference/sveltekit
|
docs/docs/reference/sveltekit
|
||||||
docs/docs/reference/next-auth
|
|
||||||
|
|
||||||
# Next.js
|
|
||||||
packages/next-auth/lib
|
|
||||||
|
|
||||||
# SvelteKit
|
# SvelteKit
|
||||||
packages/frameworks-sveltekit/index.*
|
packages/frameworks-sveltekit/index.*
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ packages/core/src/lib/pages/styles.ts
|
|||||||
packages/frameworks-sveltekit/package
|
packages/frameworks-sveltekit/package
|
||||||
packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*
|
packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*
|
||||||
|
|
||||||
|
# next-auth
|
||||||
|
packages/next-auth/src/providers/oauth-types.ts
|
||||||
|
packages/next-auth/css/index.css
|
||||||
|
|
||||||
|
|
||||||
# Adapters
|
# Adapters
|
||||||
.branches
|
.branches
|
||||||
|
|||||||
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"packages/core/{lib,providers,*.js,*.d.ts*}": true,
|
"packages/core/{lib,providers,*.js,*.d.ts,*.d.ts.map}": true,
|
||||||
"packages/next-auth/{lib,*.js,*.d.ts*}": true,
|
"packages/next-auth/{client,core,css,jwt,next,providers,react,utils,*.js,*.d.ts}": true
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"openInGitHub.remote.branch": "main"
|
"openInGitHub.remote.branch": "main"
|
||||||
|
|||||||
@@ -14,10 +14,10 @@
|
|||||||
},
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next-auth/fauna-adapter": "workspace:*",
|
"@auth/fauna-adapter": "workspace:*",
|
||||||
"@next-auth/prisma-adapter": "workspace:*",
|
"@auth/prisma-adapter": "workspace:*",
|
||||||
"@next-auth/supabase-adapter": "workspace:*",
|
"@auth/supabase-adapter": "workspace:*",
|
||||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
"@auth/typeorm-adapter": "workspace:*",
|
||||||
"@prisma/client": "^3",
|
"@prisma/client": "^3",
|
||||||
"@supabase/supabase-js": "^2.0.5",
|
"@supabase/supabase-js": "^2.0.5",
|
||||||
"faunadb": "^4",
|
"faunadb": "^4",
|
||||||
|
|||||||
@@ -37,22 +37,22 @@ import WorkOS from "next-auth/providers/workos"
|
|||||||
|
|
||||||
// // Prisma
|
// // Prisma
|
||||||
// import { PrismaClient } from "@prisma/client"
|
// import { PrismaClient } from "@prisma/client"
|
||||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
// import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||||
// const client = globalThis.prisma || new PrismaClient()
|
// const client = globalThis.prisma || new PrismaClient()
|
||||||
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||||
// const adapter = PrismaAdapter(client)
|
// const adapter = PrismaAdapter(client)
|
||||||
|
|
||||||
// // Fauna
|
// // Fauna
|
||||||
// import { Client as FaunaClient } from "faunadb"
|
// import { Client as FaunaClient } from "faunadb"
|
||||||
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
// import { FaunaAdapter } from "@auth/fauna-adapter"
|
||||||
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
||||||
// const client = globalThis.fauna || new FaunaClient(opts)
|
// const client = globalThis.fauna || new FaunaClient(opts)
|
||||||
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
||||||
// const adapter = FaunaAdapter(client)
|
// const adapter = FaunaAdapter(client)
|
||||||
|
|
||||||
// // TypeORM
|
// // TypeORM
|
||||||
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||||
// const adapter = TypeORMLegacyAdapter({
|
// const adapter = TypeORMAdapter({
|
||||||
// type: "sqlite",
|
// type: "sqlite",
|
||||||
// name: "next-auth-test-memory",
|
// name: "next-auth-test-memory",
|
||||||
// database: "./typeorm/dev.db",
|
// database: "./typeorm/dev.db",
|
||||||
@@ -60,7 +60,7 @@ import WorkOS from "next-auth/providers/workos"
|
|||||||
// })
|
// })
|
||||||
|
|
||||||
// // Supabase
|
// // Supabase
|
||||||
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
// import { SupabaseAdapter } from "@auth/supabase-adapter"
|
||||||
// const adapter = SupabaseAdapter({
|
// const adapter = SupabaseAdapter({
|
||||||
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||||
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||||
@@ -78,45 +78,130 @@ export const authOptions: NextAuthOptions = {
|
|||||||
credentials: { password: { label: "Password", type: "password" } },
|
credentials: { password: { label: "Password", type: "password" } },
|
||||||
async authorize(credentials) {
|
async authorize(credentials) {
|
||||||
if (credentials.password !== "pw") return null
|
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 }),
|
Apple({
|
||||||
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
|
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({
|
AzureAD({
|
||||||
clientId: process.env.AZURE_AD_CLIENT_ID,
|
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||||
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
||||||
tenantId: process.env.AZURE_AD_TENANT_ID,
|
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 }),
|
AzureB2C({
|
||||||
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
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 }),
|
// 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 }),
|
Discord({
|
||||||
DuendeIDS6({ clientId: "interactive.confidential", clientSecret: "secret", issuer: "https://demo.duendesoftware.com" }),
|
clientId: process.env.DISCORD_ID,
|
||||||
Facebook({ clientId: process.env.FACEBOOK_ID, clientSecret: process.env.FACEBOOK_SECRET }),
|
clientSecret: process.env.DISCORD_SECRET,
|
||||||
Foursquare({ clientId: process.env.FOURSQUARE_ID, clientSecret: process.env.FOURSQUARE_SECRET }),
|
}),
|
||||||
Freshbooks({ clientId: process.env.FRESHBOOKS_ID, clientSecret: process.env.FRESHBOOKS_SECRET }),
|
DuendeIDS6({
|
||||||
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
clientId: "interactive.confidential",
|
||||||
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
clientSecret: "secret",
|
||||||
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_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 }),
|
// 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 }),
|
// 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 }),
|
Line({
|
||||||
LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET }),
|
clientId: process.env.LINE_ID,
|
||||||
Mailchimp({ clientId: process.env.MAILCHIMP_ID, clientSecret: process.env.MAILCHIMP_SECRET }),
|
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 }),
|
// 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 }),
|
Osu({
|
||||||
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
|
clientId: process.env.OSU_CLIENT_ID,
|
||||||
Slack({ clientId: process.env.SLACK_ID, clientSecret: process.env.SLACK_SECRET }),
|
clientSecret: process.env.OSU_CLIENT_SECRET,
|
||||||
Spotify({ clientId: process.env.SPOTIFY_ID, clientSecret: process.env.SPOTIFY_SECRET }),
|
}),
|
||||||
Trakt({ clientId: process.env.TRAKT_ID, clientSecret: process.env.TRAKT_SECRET }),
|
Patreon({
|
||||||
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
clientId: process.env.PATREON_ID,
|
||||||
Twitter({ clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
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 }),
|
// TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
|
||||||
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||||
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
Wikimedia({
|
||||||
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
clientId: process.env.WIKIMEDIA_ID,
|
||||||
|
clientSecret: process.env.WIKIMEDIA_SECRET,
|
||||||
|
}),
|
||||||
|
WorkOS({
|
||||||
|
clientId: process.env.WORKOS_ID,
|
||||||
|
clientSecret: process.env.WORKOS_SECRET,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import { handlers } from "auth"
|
|
||||||
export const { GET, POST } = handlers
|
|
||||||
export const runtime = "edge"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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 })
|
|
||||||
})
|
|
||||||
@@ -1,37 +1,6 @@
|
|||||||
import { auth } from "auth"
|
import { unstable_getServerSession } from "next-auth/next"
|
||||||
import { cookies, headers } from "next/headers"
|
|
||||||
|
|
||||||
function SignIn({ id, children }: 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 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() {
|
export default async function Page() {
|
||||||
const session = await auth(headers())
|
const session = await unstable_getServerSession()
|
||||||
if (session) {
|
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<pre>{JSON.stringify(session, null, 2)}</pre>
|
|
||||||
<SignOut>Sign out</SignOut>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return <SignIn id="github">Sign in with github</SignIn>
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import { NextAuth } from "next-auth"
|
|
||||||
import GitHub from "@auth/core/providers/github"
|
|
||||||
|
|
||||||
export const { handlers, auth } = NextAuth({
|
|
||||||
providers: [GitHub],
|
|
||||||
callbacks: {
|
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import styles from "./footer.module.css"
|
import styles from "./footer.module.css"
|
||||||
import packageJSON from "next-auth/package.json"
|
import packageJSON from "package.json"
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ export default function Header() {
|
|||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/middleware-protected">Middleware protected</Link>
|
<Link href="/middleware-protected">Middleware protected</Link>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -1,10 +1,45 @@
|
|||||||
// export { auth as default } from "auth"
|
export { default } from "next-auth/middleware"
|
||||||
import { auth } from "auth"
|
|
||||||
import { NextResponse } from "next/server"
|
|
||||||
|
|
||||||
export default auth((req) => {
|
|
||||||
if (req.auth) return NextResponse.json(req.auth)
|
|
||||||
return NextResponse.json("Not authorized", { status: 401 })
|
|
||||||
})
|
|
||||||
|
|
||||||
export const config = { matcher: ["/middleware-protected"] }
|
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,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
|||||||
@@ -15,15 +15,14 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "workspace:*",
|
"@auth/core": "workspace:*",
|
||||||
"next-auth": "workspace:*",
|
"@auth/fauna-adapter": "workspace:*",
|
||||||
"@next-auth/fauna-adapter": "workspace:*",
|
"@auth/prisma-adapter": "workspace:*",
|
||||||
"@next-auth/prisma-adapter": "workspace:*",
|
"@auth/supabase-adapter": "workspace:*",
|
||||||
"@next-auth/supabase-adapter": "workspace:*",
|
"@auth/typeorm-adapter": "workspace:*",
|
||||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
|
||||||
"@prisma/client": "^3",
|
"@prisma/client": "^3",
|
||||||
"@supabase/supabase-js": "^2.0.5",
|
"@supabase/supabase-js": "^2.0.5",
|
||||||
"faunadb": "^4",
|
"faunadb": "^4",
|
||||||
"next": "13.3.2-canary.12",
|
"next": "13.3.0",
|
||||||
"next-auth": "workspace:*",
|
"next-auth": "workspace:*",
|
||||||
"nodemailer": "^6",
|
"nodemailer": "^6",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
|||||||
@@ -41,22 +41,22 @@ import WorkOS from "@auth/core/providers/workos"
|
|||||||
|
|
||||||
// // Prisma
|
// // Prisma
|
||||||
// import { PrismaClient } from "@prisma/client"
|
// import { PrismaClient } from "@prisma/client"
|
||||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
// import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||||
// const client = globalThis.prisma || new PrismaClient()
|
// const client = globalThis.prisma || new PrismaClient()
|
||||||
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||||
// const adapter = PrismaAdapter(client)
|
// const adapter = PrismaAdapter(client)
|
||||||
|
|
||||||
// // Fauna
|
// // Fauna
|
||||||
// import { Client as FaunaClient } from "faunadb"
|
// import { Client as FaunaClient } from "faunadb"
|
||||||
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
// import { FaunaAdapter } from "@auth/fauna-adapter"
|
||||||
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
||||||
// const client = globalThis.fauna || new FaunaClient(opts)
|
// const client = globalThis.fauna || new FaunaClient(opts)
|
||||||
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
||||||
// const adapter = FaunaAdapter(client)
|
// const adapter = FaunaAdapter(client)
|
||||||
|
|
||||||
// // TypeORM
|
// // TypeORM
|
||||||
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||||
// const adapter = TypeORMLegacyAdapter({
|
// const adapter = TypeORMAdapter({
|
||||||
// type: "sqlite",
|
// type: "sqlite",
|
||||||
// name: "next-auth-test-memory",
|
// name: "next-auth-test-memory",
|
||||||
// database: "./typeorm/dev.db",
|
// database: "./typeorm/dev.db",
|
||||||
@@ -64,7 +64,7 @@ import WorkOS from "@auth/core/providers/workos"
|
|||||||
// })
|
// })
|
||||||
|
|
||||||
// // Supabase
|
// // Supabase
|
||||||
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
// import { SupabaseAdapter } from "@auth/supabase-adapter"
|
||||||
// const adapter = SupabaseAdapter({
|
// const adapter = SupabaseAdapter({
|
||||||
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||||
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||||
@@ -160,4 +160,4 @@ function AuthHandler(...args: any[]) {
|
|||||||
|
|
||||||
export default AuthHandler(authConfig)
|
export default AuthHandler(authConfig)
|
||||||
|
|
||||||
export const config = { runtime: "edge" }
|
export const config = { runtime: "experimental-edge" }
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
// This is an example of to protect an API route
|
// This is an example of to protect an API route
|
||||||
import { authConfig } from "../auth-old/[...nextauth]"
|
import { unstable_getServerSession } from "next-auth/next"
|
||||||
import { getServerSession } from "next-auth/next"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const session = await getServerSession(req, res, authConfig as any)
|
const session = await unstable_getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
res.send({
|
res.send({
|
||||||
8
apps/dev/nextjs/pages/api/examples/session.js
Normal file
8
apps/dev/nextjs/pages/api/examples/session.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// 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)
|
||||||
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
30
apps/dev/nextjs/pages/api/examples/supabase-rls.js
Normal file
30
apps/dev/nextjs/pages/api/examples/supabase-rls.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// 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))
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// This is an example of how to protect content using server rendering
|
// This is an example of how to protect content using server rendering
|
||||||
import { getServerSession } from "next-auth/next"
|
import { unstable_getServerSession } from "next-auth/next"
|
||||||
import { authConfig } from "./api/auth-old/[...nextauth]"
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
import AccessDenied from "../components/access-denied"
|
import AccessDenied from "../components/access-denied"
|
||||||
|
|
||||||
@@ -26,7 +26,11 @@ export default function Page({ content, session }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps(context) {
|
||||||
const session = await getServerSession(context.req, context.res, authConfig)
|
const session = await unstable_getServerSession(
|
||||||
|
context.req,
|
||||||
|
context.res,
|
||||||
|
authOptions
|
||||||
|
)
|
||||||
let content = null
|
let content = null
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { getServerSession } from "next-auth/next"
|
import { unstable_getServerSession } from "next-auth/next"
|
||||||
import Layout from "../components/layout"
|
import Layout from "../components/layout"
|
||||||
import { authConfig } from "./api/auth-old/[...nextauth]"
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
// As this page uses Server Side Rendering, the `session` will be already
|
// As this page uses Server Side Rendering, the `session` will be already
|
||||||
@@ -12,11 +12,11 @@ export default function Page() {
|
|||||||
<Layout>
|
<Layout>
|
||||||
<h1>Server Side Rendering</h1>
|
<h1>Server Side Rendering</h1>
|
||||||
<p>
|
<p>
|
||||||
This page uses the <strong>getServerSession()</strong> method in{" "}
|
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||||
<strong>getServerSideProps()</strong>.
|
in <strong>getServerSideProps()</strong>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Using <strong>getServerSession()</strong> in{" "}
|
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||||
<strong>getServerSideProps()</strong> is currently the recommended
|
<strong>getServerSideProps()</strong> is currently the recommended
|
||||||
approach, although the API may still change, if you need to support
|
approach, although the API may still change, if you need to support
|
||||||
Server Side Rendering with authentication.
|
Server Side Rendering with authentication.
|
||||||
@@ -40,7 +40,11 @@ export default function Page() {
|
|||||||
export async function getServerSideProps(context) {
|
export async function getServerSideProps(context) {
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
session: await getServerSession(context.req, context.res, authConfig),
|
session: await unstable_getServerSession(
|
||||||
|
context.req,
|
||||||
|
context.res,
|
||||||
|
authOptions
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
48
apps/dev/nextjs/pages/supabase-client-rls.js
Normal file
48
apps/dev/nextjs/pages/supabase-client-rls.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
68
apps/dev/nextjs/pages/supabase-ssr.js
Normal file
68
apps/dev/nextjs/pages/supabase-ssr.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// 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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
@@ -18,12 +18,3 @@ declare module "next-auth" {
|
|||||||
foo: string
|
foo: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
namespace NodeJS {
|
|
||||||
interface ProcessEnv {
|
|
||||||
[key: string]: string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
/** @type {import("next").NextConfig} */
|
|
||||||
module.exports = {
|
|
||||||
reactStrictMode: true,
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
NEXTAUTH_URL=http://localhost:3000
|
NEXTAUTH_URL=http://localhost:3000
|
||||||
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32
|
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||||
|
|
||||||
|
|
||||||
AUTH0_ID=
|
AUTH0_ID=
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<a href="https://nextjs.org" target="_blank">
|
<a href="https://nextjs.org" target="_blank">
|
||||||
<img height="64" src="https://nextjs.org/static/favicon/android-chrome-192x192.png" />
|
<img height="64" src="https://nextjs.org/static/favicon/android-chrome-192x192.png" />
|
||||||
</a>
|
</a>
|
||||||
<h3 align="center"><b>next-auth</b> - Example App</h3>
|
<h3 align="center"><b>NextAuth.js</b> - Example App</h3>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Open Source. Full Stack. Own Your Data.
|
Open Source. Full Stack. Own Your Data.
|
||||||
</p>
|
</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)
|
The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app)
|
||||||
|
|
||||||
Go to [authjs.dev](https://authjs.dev) for more information and documentation.
|
Go to [next-auth.js.org](https://next-auth.js.org) for more information and documentation.
|
||||||
|
|
||||||
## Getting Started
|
## 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:
|
For more information about setting up a database, please check out the following links:
|
||||||
|
|
||||||
- Docs: [authjs.dev/reference/adapters](https://authjs.dev/reference/adapters)
|
- Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||||
|
|
||||||
### 3. Configure Authentication Providers
|
### 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`
|
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 [authjs.dev/getting-started/oauth-tutorial](https://authjs.dev/getting-started/oauth-tutorial)
|
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
|
||||||
|
|
||||||
3. You can also choose to specify an SMTP server for passwordless sign in via email.
|
3. You can also choose to specify an SMTP server for passwordless sign in via email.
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import { handlers } from "auth"
|
|
||||||
export const { GET, POST } = handlers
|
|
||||||
export const runtime = "edge"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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 })
|
|
||||||
})
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
export default function Page() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<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>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const runtime = "experimental-edge"
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import NextAuth from "next-auth"
|
|
||||||
import GitHub from "@auth/core/providers/github"
|
|
||||||
|
|
||||||
export const { handlers, auth } = NextAuth({
|
|
||||||
providers: [GitHub],
|
|
||||||
callbacks: {
|
|
||||||
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
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import styles from "./footer.module.css"
|
import styles from "./footer.module.css"
|
||||||
import packageJSON from "next-auth/package.json"
|
import packageJSON from "../package.json"
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
return (
|
return (
|
||||||
@@ -8,10 +8,10 @@ export default function Footer() {
|
|||||||
<hr />
|
<hr />
|
||||||
<ul className={styles.navItems}>
|
<ul className={styles.navItems}>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<a href="https://authjs.dev">Documentation</a>
|
<a href="https://next-auth.js.org">Documentation</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<a href="https://www.npmjs.com/package/@auth/core">NPM</a>
|
<a href="https://www.npmjs.com/package/next-auth">NPM</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||||
@@ -20,7 +20,7 @@ export default function Footer() {
|
|||||||
<Link href="/policy">Policy</Link>
|
<Link href="/policy">Policy</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<em>{packageJSON.version}</em>
|
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* Set min-height to avoid page reflow while session loading */
|
/* Set min-height to avoid page reflow while session loading */
|
||||||
.signedInStatus {
|
.signedInStatus {
|
||||||
position: relative;
|
|
||||||
display: block;
|
display: block;
|
||||||
min-height: 4rem;
|
min-height: 4rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,63 +1,65 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { auth } from "auth"
|
import { signIn, signOut, useSession } from "next-auth/react"
|
||||||
import { cookies, headers } from "next/headers"
|
|
||||||
import styles from "./header.module.css"
|
import styles from "./header.module.css"
|
||||||
|
|
||||||
function SignIn({ id, children, className }: any) {
|
// The approach used in this component shows how to build a sign in and sign out
|
||||||
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
|
// component that works on pages which support both client and server side
|
||||||
// rendering, and avoids any flash incorrect content on initial page load.
|
// rendering, and avoids any flash incorrect content on initial page load.
|
||||||
export default async function Header() {
|
export default function Header() {
|
||||||
const session = await auth(headers())
|
const { data: session, status } = useSession()
|
||||||
|
const loading = status === "loading"
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<noscript>
|
<noscript>
|
||||||
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
|
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div className={styles.signedInStatus}>
|
<div className={styles.signedInStatus}>
|
||||||
<p className={`nojs-show ${styles.loaded}`}>
|
<p
|
||||||
|
className={`nojs-show ${
|
||||||
|
!session && loading ? styles.loading : styles.loaded
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{!session && (
|
{!session && (
|
||||||
<>
|
<>
|
||||||
<span className={styles.notSignedInText}>
|
<span className={styles.notSignedInText}>
|
||||||
You are not signed in
|
You are not signed in
|
||||||
</span>
|
</span>
|
||||||
<SignIn className={styles.buttonPrimary}>Sign In</SignIn>
|
<a
|
||||||
|
href={`/api/auth/signin`}
|
||||||
|
className={styles.buttonPrimary}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signIn()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign in
|
||||||
|
</a>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{session && (
|
{session?.user && (
|
||||||
<>
|
<>
|
||||||
{session.user.image && (
|
{session.user.image && (
|
||||||
<img src={session.user.image} className={styles.avatar} />
|
<span
|
||||||
|
style={{ backgroundImage: `url('${session.user.image}')` }}
|
||||||
|
className={styles.avatar}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<span className={styles.signedInText}>
|
<span className={styles.signedInText}>
|
||||||
<small>Signed in as</small>
|
<small>Signed in as</small>
|
||||||
<br />
|
<br />
|
||||||
<strong>{session.user.email} </strong>
|
<strong>{session.user.email ?? session.user.name}</strong>
|
||||||
{session.user.name ? `(${session.user.name})` : null}
|
|
||||||
</span>
|
</span>
|
||||||
<SignOut className={styles.button}>Sign Out</SignOut>
|
<a
|
||||||
|
href={`/api/auth/signout`}
|
||||||
|
className={styles.button}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
signOut()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Sign out
|
||||||
|
</a>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
@@ -71,7 +73,7 @@ export default async function Header() {
|
|||||||
<Link href="/client">Client</Link>
|
<Link href="/client">Client</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/server-component">Server</Link>
|
<Link href="/server">Server</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/protected">Protected</Link>
|
<Link href="/protected">Protected</Link>
|
||||||
@@ -80,12 +82,13 @@ export default async function Header() {
|
|||||||
<Link href="/api-example">API</Link>
|
<Link href="/api-example">API</Link>
|
||||||
</li>
|
</li>
|
||||||
<li className={styles.navItem}>
|
<li className={styles.navItem}>
|
||||||
<Link href="/middleware-protected">Middleware protected</Link>
|
<Link href="/admin">Admin</Link>
|
||||||
|
</li>
|
||||||
|
<li className={styles.navItem}>
|
||||||
|
<Link href="/me">Me</Link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const runtime = "experimental-edge"
|
|
||||||
|
|||||||
13
apps/examples/nextjs/components/layout.tsx
Normal file
13
apps/examples/nextjs/components/layout.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
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 />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
// export { auth as default } from "auth"
|
import { withAuth } from "next-auth/middleware"
|
||||||
import { auth } from "auth"
|
|
||||||
import { NextResponse } from "next/server"
|
|
||||||
|
|
||||||
export default auth((req) => {
|
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
||||||
if (req.auth) return NextResponse.json(req.auth)
|
export default withAuth({
|
||||||
return NextResponse.json("Not authorized", { status: 401 })
|
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 const config = { matcher: ["/middleware-protected"] }
|
export const config = { matcher: ["/admin", "/me"] }
|
||||||
|
|||||||
10
apps/examples/nextjs/next-auth.d.ts
vendored
Normal file
10
apps/examples/nextjs/next-auth.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import "next-auth/jwt"
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
/** @type {import("next").NextConfig} */
|
/** @type {import("next").NextConfig} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
webpack(config) {
|
reactStrictMode: true,
|
||||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
|
||||||
return config
|
|
||||||
},
|
|
||||||
experimental: { appDir: true },
|
|
||||||
typescript: { ignoreBuildErrors: true },
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "nextjs-example-app",
|
|
||||||
"description": "An example project for NextAuth.js with Next.js",
|
"description": "An example project for NextAuth.js with Next.js",
|
||||||
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@@ -19,9 +18,8 @@
|
|||||||
"Lluis Agusti <hi@llu.lu>"
|
"Lluis Agusti <hi@llu.lu>"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "workspace:*",
|
|
||||||
"next": "latest",
|
"next": "latest",
|
||||||
"next-auth": "workspace:*",
|
"next-auth": "latest",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
18
apps/examples/nextjs/pages/_app.tsx
Normal file
18
apps/examples/nextjs/pages/_app.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
17
apps/examples/nextjs/pages/admin.tsx
Normal file
17
apps/examples/nextjs/pages/admin.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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
|
||||||
|
<a href="https://next-auth.js.org/configuration/nextjs#middleware">
|
||||||
|
the docs
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
19
apps/examples/nextjs/pages/api-example.tsx
Normal file
19
apps/examples/nextjs/pages/api-example.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
44
apps/examples/nextjs/pages/api/auth/[...nextauth].ts
Normal file
44
apps/examples/nextjs/pages/api/auth/[...nextauth].ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||||
|
import GoogleProvider from "next-auth/providers/google"
|
||||||
|
import FacebookProvider from "next-auth/providers/facebook"
|
||||||
|
import GithubProvider from "next-auth/providers/github"
|
||||||
|
import TwitterProvider from "next-auth/providers/twitter"
|
||||||
|
import Auth0Provider from "next-auth/providers/auth0"
|
||||||
|
|
||||||
|
// For more information on each option (and a full list of options) go to
|
||||||
|
// https://next-auth.js.org/configuration/options
|
||||||
|
export const authOptions: NextAuthOptions = {
|
||||||
|
// https://next-auth.js.org/configuration/providers/oauth
|
||||||
|
providers: [
|
||||||
|
Auth0Provider({
|
||||||
|
clientId: process.env.AUTH0_ID,
|
||||||
|
clientSecret: process.env.AUTH0_SECRET,
|
||||||
|
issuer: process.env.AUTH0_ISSUER,
|
||||||
|
}),
|
||||||
|
FacebookProvider({
|
||||||
|
clientId: process.env.FACEBOOK_ID,
|
||||||
|
clientSecret: process.env.FACEBOOK_SECRET,
|
||||||
|
}),
|
||||||
|
GithubProvider({
|
||||||
|
clientId: process.env.GITHUB_ID,
|
||||||
|
clientSecret: process.env.GITHUB_SECRET,
|
||||||
|
}),
|
||||||
|
GoogleProvider({
|
||||||
|
clientId: process.env.GOOGLE_ID,
|
||||||
|
clientSecret: process.env.GOOGLE_SECRET,
|
||||||
|
}),
|
||||||
|
TwitterProvider({
|
||||||
|
clientId: process.env.TWITTER_ID,
|
||||||
|
clientSecret: process.env.TWITTER_SECRET,
|
||||||
|
version: "2.0",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
callbacks: {
|
||||||
|
async jwt({ token }) {
|
||||||
|
token.userRole = "admin"
|
||||||
|
return token
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NextAuth(authOptions)
|
||||||
14
apps/examples/nextjs/pages/api/examples/jwt.ts
Normal file
14
apps/examples/nextjs/pages/api/examples/jwt.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// 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))
|
||||||
|
}
|
||||||
23
apps/examples/nextjs/pages/api/examples/protected.ts
Normal file
23
apps/examples/nextjs/pages/api/examples/protected.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// This is an example of to protect an API route
|
||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
) {
|
||||||
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
|
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.",
|
||||||
|
})
|
||||||
|
}
|
||||||
13
apps/examples/nextjs/pages/api/examples/session.ts
Normal file
13
apps/examples/nextjs/pages/api/examples/session.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// This is an example of how to access a session from an API route
|
||||||
|
import { getServerSession } from "next-auth"
|
||||||
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse
|
||||||
|
) {
|
||||||
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
res.send(JSON.stringify(session, null, 2))
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
export default function Page() {
|
import Layout from "../components/layout"
|
||||||
|
|
||||||
|
export default function ClientPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<Layout>
|
||||||
<h1>Client Side Rendering</h1>
|
<h1>Client Side Rendering</h1>
|
||||||
<p>
|
<p>
|
||||||
This page uses the <strong>useSession()</strong> React Hook in the{" "}
|
This page uses the <strong>useSession()</strong> React Hook in the{" "}
|
||||||
<strong></Header></strong> component.
|
<strong><Header/></strong> component.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The <strong>useSession()</strong> React Hook easy to use and allows
|
The <strong>useSession()</strong> React Hook is easy to use and allows
|
||||||
pages to render very quickly.
|
pages to render very quickly.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
@@ -20,6 +22,6 @@ export default function Page() {
|
|||||||
The disadvantage of <strong>useSession()</strong> is that it requires
|
The disadvantage of <strong>useSession()</strong> is that it requires
|
||||||
client side JavaScript.
|
client side JavaScript.
|
||||||
</p>
|
</p>
|
||||||
</>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
13
apps/examples/nextjs/pages/index.tsx
Normal file
13
apps/examples/nextjs/pages/index.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
12
apps/examples/nextjs/pages/me.tsx
Normal file
12
apps/examples/nextjs/pages/me.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
32
apps/examples/nextjs/pages/policy.tsx
Normal file
32
apps/examples/nextjs/pages/policy.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
40
apps/examples/nextjs/pages/protected.tsx
Normal file
40
apps/examples/nextjs/pages/protected.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
44
apps/examples/nextjs/pages/server.tsx
Normal file
44
apps/examples/nextjs/pages/server.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { getServerSession } from "next-auth/next"
|
||||||
|
import { authOptions } from "./api/auth/[...nextauth]"
|
||||||
|
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 getServerSession(context.req, context.res, authOptions),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
body {
|
body {
|
||||||
color: red;
|
|
||||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||||
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
@@ -7,7 +6,7 @@ body {
|
|||||||
max-width: 680px;
|
max-width: 680px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: var(--color-text);
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
li,
|
li,
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
@@ -16,24 +12,15 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"incremental": true,
|
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"baseUrl": ".",
|
"incremental": true
|
||||||
"plugins": [
|
|
||||||
{
|
|
||||||
"name": "next"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"strictNullChecks": true
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
|
"process.d.ts",
|
||||||
"next-env.d.ts",
|
"next-env.d.ts",
|
||||||
|
"next-auth.d.ts",
|
||||||
"**/*.ts",
|
"**/*.ts",
|
||||||
"**/*.tsx",
|
"**/*.tsx"
|
||||||
".next/types/**/*.ts"
|
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": ["node_modules"]
|
||||||
"node_modules",
|
|
||||||
"jest.config.js"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Session } from "@auth/core"
|
import { Session } from "@auth/core/types"
|
||||||
|
|
||||||
export default function useSession() {
|
export default function useSession() {
|
||||||
return useState<Session | null>("session", () => null)
|
return useState<Session | null>("session", () => null)
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export async function signIn<
|
|||||||
|
|
||||||
// TODO: Handle custom base path
|
// TODO: Handle custom base path
|
||||||
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
|
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
|
||||||
const { csrfToken } = await $fetch("/api/auth/csrf")
|
const { csrfToken } = await $fetch<{ csrfToken: string }>("/api/auth/csrf")
|
||||||
|
|
||||||
console.log(_signInUrl)
|
console.log(_signInUrl)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { AuthHandler, AuthOptions, Session } from "@auth/core"
|
import { AuthConfig, Session } from "@auth/core/types"
|
||||||
|
import { Auth } from "@auth/core"
|
||||||
import { fromNodeMiddleware, H3Event } from "h3"
|
import { fromNodeMiddleware, H3Event } from "h3"
|
||||||
import getURL from "requrl"
|
import getURL from "requrl"
|
||||||
import { createMiddleware } from "@hattip/adapter-node"
|
import { createMiddleware } from "@hattip/adapter-node"
|
||||||
|
|
||||||
export function NuxtAuthHandler(options: AuthOptions) {
|
export function NuxtAuthHandler(options: AuthConfig) {
|
||||||
async function handler(ctx: { request: Request }) {
|
async function handler(ctx: { request: Request }) {
|
||||||
options.trustHost ??= true
|
options.trustHost ??= true
|
||||||
|
|
||||||
return AuthHandler(ctx.request, options)
|
return Auth(ctx.request, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
const middleware = createMiddleware(handler)
|
const middleware = createMiddleware(handler)
|
||||||
@@ -17,7 +18,7 @@ export function NuxtAuthHandler(options: AuthOptions) {
|
|||||||
|
|
||||||
export async function getSession(
|
export async function getSession(
|
||||||
event: H3Event,
|
event: H3Event,
|
||||||
options: AuthOptions
|
options: AuthConfig
|
||||||
): Promise<Session | null> {
|
): Promise<Session | null> {
|
||||||
options.trustHost ??= true
|
options.trustHost ??= true
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ export async function getSession(
|
|||||||
nodeHeaders.append(key, headers[key] as any)
|
nodeHeaders.append(key, headers[key] as any)
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await AuthHandler(
|
const response = await Auth(
|
||||||
new Request(url, { headers: nodeHeaders }),
|
new Request(url, { headers: nodeHeaders }),
|
||||||
options
|
options
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "playground-nuxt",
|
"name": "next-auth-nuxt",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "nuxt prepare && nuxt build",
|
"build": "nuxt build",
|
||||||
"dev": "nuxt prepare && export NODE_OPTIONS='--no-experimental-fetch' && nuxt dev",
|
"dev": "nuxt prepare && nuxt dev",
|
||||||
"generate": "nuxt generate",
|
"generate": "nuxt generate",
|
||||||
"preview": "nuxt preview"
|
"preview": "nuxt preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/eslint-config": "^0.1.1",
|
"@nuxt/eslint-config": "^0.1.1",
|
||||||
"eslint": "^8.29.0",
|
"eslint": "^8.29.0",
|
||||||
"h3": "1.0.2",
|
"h3": "1.6.6",
|
||||||
"nuxt": "3.0.0"
|
"nuxt": "3.5.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth/core": "workspace:*",
|
"@auth/core": "workspace:*",
|
||||||
"@hattip/adapter-node": "^0.0.22",
|
"@hattip/adapter-node": "^0.0.34",
|
||||||
"requrl": "^3.0.2"
|
"requrl": "^3.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Session } from "@auth/core"
|
import { Session } from "@auth/core/types"
|
||||||
|
|
||||||
export default defineNuxtPlugin(async () => {
|
export default defineNuxtPlugin(async () => {
|
||||||
const session = useSession()
|
const session = useSession()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { NuxtAuthHandler } from "@/lib/auth/server"
|
import { NuxtAuthHandler } from "@/lib/auth/server"
|
||||||
import GithubProvider from "@auth/core/providers/github"
|
import GithubProvider from "@auth/core/providers/github"
|
||||||
import type { AuthOptions } from "@auth/core"
|
import type { AuthConfig } from "@auth/core"
|
||||||
|
|
||||||
const runtimeConfig = useRuntimeConfig()
|
const runtimeConfig = useRuntimeConfig()
|
||||||
|
|
||||||
export const authOptions: AuthOptions = {
|
export const authOptions = {
|
||||||
secret: runtimeConfig.secret,
|
secret: runtimeConfig.secret,
|
||||||
providers: [
|
providers: [
|
||||||
GithubProvider({
|
GithubProvider({
|
||||||
@@ -12,6 +12,6 @@ export const authOptions: AuthOptions = {
|
|||||||
clientSecret: runtimeConfig.github.clientSecret,
|
clientSecret: runtimeConfig.github.clientSecret,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
} as AuthConfig
|
||||||
|
|
||||||
export default NuxtAuthHandler(authOptions)
|
export default NuxtAuthHandler(authOptions)
|
||||||
|
|||||||
@@ -91,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...
|
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, other any of the other adapters will work just fine.
|
For this tutorial, we're going to use the **MongoDB** adapter, but any of the other adapters will work just fine.
|
||||||
|
|
||||||
First, let's start by installing the adapter package:
|
First, let's start by installing the adapter package:
|
||||||
|
|
||||||
```bash npm2yarn2pnpm
|
```bash npm2yarn2pnpm
|
||||||
npm install -D @next-auth/mongodb-adapter mongodb
|
npm install -D @auth/mongodb-adapter mongodb
|
||||||
```
|
```
|
||||||
|
|
||||||
and create a simple MongoDB client:
|
and create a simple MongoDB client:
|
||||||
@@ -142,7 +142,7 @@ And now let's reference this new adapter from our Auth.js configuration file:
|
|||||||
```diff title="pages/api/auth/[...nextauth].ts"
|
```diff title="pages/api/auth/[...nextauth].ts"
|
||||||
import NextAuth from "next-auth"
|
import NextAuth from "next-auth"
|
||||||
import EmailProvider from "next-auth/providers/email"
|
import EmailProvider from "next-auth/providers/email"
|
||||||
+ import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
|
+ import { MongoDBAdapter } from "@auth/mongodb-adapter"
|
||||||
+ import clientPromise from "../../../lib/mongodb/client"
|
+ import clientPromise from "../../../lib/mongodb/client"
|
||||||
|
|
||||||
export default NextAuth({
|
export default NextAuth({
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ This tutorial assumes you have a Next.js application set up. If you don't, you c
|
|||||||
npm install next-auth
|
npm install next-auth
|
||||||
```
|
```
|
||||||
|
|
||||||
|
:::info
|
||||||
|
We are working on a new `@auth/nextjs` package that will make it easier to set up Auth.js with Next.js. Stay tuned! For now, you can use the `next-auth` package.
|
||||||
|
:::
|
||||||
|
|
||||||
### Creating the server config
|
### 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:
|
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:
|
||||||
@@ -239,10 +243,13 @@ http://localhost:5173/auth/callback/github
|
|||||||
TODO Core
|
TODO Core
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
:::info
|
:::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 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.
|
The same id is used in the `signIn()` method we saw earlier.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
To register, tap on "Register application" button.
|
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**:
|
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**:
|
||||||
@@ -266,7 +273,7 @@ Note that, for each provider, the configuration process will be similar to what
|
|||||||
2. Create create your OAuth application within it
|
2. Create create your OAuth application within it
|
||||||
3. Set the callback URL
|
3. Set the callback URL
|
||||||
4. Get the Client ID and Generate a Client Secret
|
4. Get the Client ID and Generate a Client Secret
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## 3. Wiring all together
|
## 3. Wiring all together
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ Using the database strategy is very similar, but instead of preserving the `acce
|
|||||||
import { Auth } from "@auth/core"
|
import { Auth } from "@auth/core"
|
||||||
import { type TokenSet } from "@auth/core/types"
|
import { type TokenSet } from "@auth/core/types"
|
||||||
import Google from "@auth/core/providers/google"
|
import Google from "@auth/core/providers/google"
|
||||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||||
import { PrismaClient } from "@prisma/client"
|
import { PrismaClient } from "@prisma/client"
|
||||||
|
|
||||||
const prisma = new PrismaClient()
|
const prisma = new PrismaClient()
|
||||||
|
|||||||
@@ -22,11 +22,18 @@ Next you will have to create some configuration files for Cypress.
|
|||||||
|
|
||||||
First, the primary cypress config:
|
First, the primary cypress config:
|
||||||
|
|
||||||
```js title="cypress.json"
|
```ts title="cypress.config.ts"
|
||||||
{
|
import { defineConfig } from 'cypress'
|
||||||
"baseUrl": "http://localhost:3000",
|
|
||||||
"chromeWebSecurity": false
|
export default defineConfig({
|
||||||
}
|
e2e: {
|
||||||
|
baseUrl: 'http://localhost:3000',
|
||||||
|
chromeWebSecurity: false,
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
// implement node event listeners here
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
This initial Cypress config will tell Cypress where to find your site on initial launch as well as allow it to open up URLs at domains that aren't your page, for example to be able to login to a social provider.
|
This initial Cypress config will tell Cypress where to find your site on initial launch as well as allow it to open up URLs at domains that aren't your page, for example to be able to login to a social provider.
|
||||||
@@ -46,14 +53,24 @@ You must change the login credentials you want to use, but you can also redefine
|
|||||||
|
|
||||||
Third, if you're using the `cypress-social-login` plugin, you must add this to your `/cypress/plugins/index.js` file like so:
|
Third, if you're using the `cypress-social-login` plugin, you must add this to your `/cypress/plugins/index.js` file like so:
|
||||||
|
|
||||||
```js title="cypress/plugins/index.js"
|
```js title="cypress.config.ts" {3-4,10-14}
|
||||||
const { GoogleSocialLogin } = require("cypress-social-logins").plugins
|
import { defineConfig } from 'cypress'
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
|
const { GoogleSocialLogin } = require('cypress-social-logins').plugins
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
e2e: {
|
||||||
|
baseUrl: 'http://localhost:3000',
|
||||||
|
chromeWebSecurity: false,
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
on('task', {
|
||||||
|
GoogleSocialLogin,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = (on, config) => {
|
|
||||||
on("task", {
|
|
||||||
GoogleSocialLogin: GoogleSocialLogin,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, you can also add the following npm scripts to your `package.json`:
|
Finally, you can also add the following npm scripts to your `package.json`:
|
||||||
@@ -110,10 +127,6 @@ describe("Login page", () => {
|
|||||||
secure: cookie.secure,
|
secure: cookie.secure,
|
||||||
})
|
})
|
||||||
|
|
||||||
Cypress.Cookies.defaults({
|
|
||||||
preserve: cookieName,
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove the two lines below if you need to stay logged in
|
// remove the two lines below if you need to stay logged in
|
||||||
// for your remaining tests
|
// for your remaining tests
|
||||||
cy.visit("/api/auth/signout")
|
cy.visit("/api/auth/signout")
|
||||||
|
|||||||
@@ -96,8 +96,13 @@ erDiagram
|
|||||||
string type
|
string type
|
||||||
string provider
|
string provider
|
||||||
string providerAccountId
|
string providerAccountId
|
||||||
|
string refresh_token
|
||||||
string access_token
|
string access_token
|
||||||
|
int expires_at
|
||||||
|
string token_type
|
||||||
|
string scope
|
||||||
string id_token
|
string id_token
|
||||||
|
string session_state
|
||||||
}
|
}
|
||||||
VerificationToken {
|
VerificationToken {
|
||||||
string identifier
|
string identifier
|
||||||
@@ -137,7 +142,7 @@ The Account model is for information about OAuth accounts associated with a User
|
|||||||
|
|
||||||
A single User can have multiple Accounts, but each Account can only have one User.
|
A single User can have multiple Accounts, but each Account can only have one User.
|
||||||
|
|
||||||
Account creation in the database is automatic and happens when the user is logging in for the first time with a provider, or the [`Adapter.linkAccount`](/reference/core/adapters#linkaccount) method is invoked. The default data saved is `access_token`, `refresh_token`, `id_token` and `expires_at`. You can save other fields by returning them in the [OAuth provider](/guides/providers/custom-provider)'s [`account()`](/reference/core/providers#account) callback.
|
Account creation in the database is automatic and happens when the user is logging in for the first time with a provider, or the [`Adapter.linkAccount`](/reference/core/adapters#linkaccount) method is invoked. The default data saved is `access_token`, `expires_at`, `refresh_token`, `id_token`, `token_type`, `scope` and `session_state`. You can save other fields or remove the ones you don't need by returning them in the [OAuth provider](/guides/providers/custom-provider)'s [`account()`](/reference/core/providers#account) callback.
|
||||||
|
|
||||||
Linking Accounts to Users happen automatically, only when they have the same e-mail address, and the user is currently signed in. Check the [FAQ](/concepts/faq#security) for more information on why this is a requirement.
|
Linking Accounts to Users happen automatically, only when they have the same e-mail address, and the user is currently signed in. Check the [FAQ](/concepts/faq#security) for more information on why this is a requirement.
|
||||||
|
|
||||||
|
|||||||
7
docs/docs/reference/nextjs/client.md
Normal file
7
docs/docs/reference/nextjs/client.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Client
|
||||||
|
---
|
||||||
|
|
||||||
|
:::warning WIP
|
||||||
|
`@auth/nextjs/client` is work in progress. For now, please use [NextAuth.js Client API](https://next-auth.js.org/getting-started/client).
|
||||||
|
:::
|
||||||
7
docs/docs/reference/nextjs/index.md
Normal file
7
docs/docs/reference/nextjs/index.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
title: Next.js Auth
|
||||||
|
---
|
||||||
|
|
||||||
|
:::warning WIP
|
||||||
|
`@auth/nextjs` is work in progress. For now, please use [NextAuth.js](https://next-auth.js.org).
|
||||||
|
:::
|
||||||
@@ -38,22 +38,6 @@ function typedocAdapter(name) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function typedocFramework(id, entrypoints) {
|
|
||||||
return [
|
|
||||||
"docusaurus-plugin-typedoc",
|
|
||||||
{
|
|
||||||
...typedocConfig,
|
|
||||||
id: id.replace("frameworks-", ""),
|
|
||||||
plugin: [require.resolve("./typedoc-mdn-links")],
|
|
||||||
watch: process.env.TYPEDOC_WATCH,
|
|
||||||
entryPoints: entrypoints.map((e) => `../packages/${id}/src/${e}`),
|
|
||||||
tsconfig: `../packages/${id}/tsconfig.json`,
|
|
||||||
out: `reference/${id.replace("frameworks-", "")}`,
|
|
||||||
sidebar: { indexLabel: "index" },
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {import("@docusaurus/types").Config} */
|
/** @type {import("@docusaurus/types").Config} */
|
||||||
const docusaurusConfig = {
|
const docusaurusConfig = {
|
||||||
markdown: {
|
markdown: {
|
||||||
@@ -247,9 +231,36 @@ const docusaurusConfig = {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
typedocFramework("core", ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"]),
|
[
|
||||||
typedocFramework("frameworks-sveltekit", ["lib/index.ts", "lib/client.ts"]),
|
"docusaurus-plugin-typedoc",
|
||||||
typedocFramework("next-auth", ["index.ts", "react.tsx", "jwt.ts", "adapters.ts", "next.ts", "types.ts", "middleware.ts"]),
|
{
|
||||||
|
...typedocConfig,
|
||||||
|
id: "core",
|
||||||
|
plugin: [require.resolve("./typedoc-mdn-links")],
|
||||||
|
watch: process.env.TYPEDOC_WATCH,
|
||||||
|
entryPoints: ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"].map((e) => `${coreSrc}/${e}`).concat(providers),
|
||||||
|
tsconfig: "../packages/core/tsconfig.json",
|
||||||
|
out: "reference/core",
|
||||||
|
sidebar: {
|
||||||
|
indexLabel: "index",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"docusaurus-plugin-typedoc",
|
||||||
|
{
|
||||||
|
...typedocConfig,
|
||||||
|
id: "sveltekit",
|
||||||
|
plugin: [require.resolve("./typedoc-mdn-links")],
|
||||||
|
watch: process.env.TYPEDOC_WATCH,
|
||||||
|
entryPoints: ["index.ts", "client.ts"].map((e) => `../packages/frameworks-sveltekit/src/lib/${e}`),
|
||||||
|
tsconfig: "../packages/frameworks-sveltekit/tsconfig.json",
|
||||||
|
out: "reference/sveltekit",
|
||||||
|
sidebar: {
|
||||||
|
indexLabel: "index",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
||||||
? []
|
? []
|
||||||
: [
|
: [
|
||||||
@@ -262,19 +273,7 @@ const docusaurusConfig = {
|
|||||||
typedocAdapter("Neo4j"),
|
typedocAdapter("Neo4j"),
|
||||||
typedocAdapter("PouchDB"),
|
typedocAdapter("PouchDB"),
|
||||||
typedocAdapter("Prisma"),
|
typedocAdapter("Prisma"),
|
||||||
[
|
typedocAdapter("TypeORM"),
|
||||||
"docusaurus-plugin-typedoc",
|
|
||||||
{
|
|
||||||
...typedocConfig,
|
|
||||||
id: "typeorm",
|
|
||||||
plugin: [require.resolve("./typedoc-mdn-links")],
|
|
||||||
watch: process.env.TYPEDOC_WATCH,
|
|
||||||
entryPoints: [`../packages/adapter-typeorm-legacy/src/index.ts`],
|
|
||||||
tsconfig: `../packages/adapter-typeorm-legacy/tsconfig.json`,
|
|
||||||
out: `reference/adapter/typeorm`,
|
|
||||||
sidebar: { indexLabel: "TypeORM" },
|
|
||||||
},
|
|
||||||
],
|
|
||||||
typedocAdapter("Sequelize"),
|
typedocAdapter("Sequelize"),
|
||||||
typedocAdapter("Supabase"),
|
typedocAdapter("Supabase"),
|
||||||
typedocAdapter("Upstash Redis"),
|
typedocAdapter("Upstash Redis"),
|
||||||
|
|||||||
@@ -35,9 +35,16 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
label: "next-auth",
|
label: "@auth/nextjs",
|
||||||
link: { type: "doc", id: "reference/next-auth/index" },
|
link: { type: "doc", id: "reference/nextjs/index" },
|
||||||
items: [{ type: "autogenerated", dirName: "reference/next-auth" }],
|
items: [
|
||||||
|
"reference/nextjs/client",
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
label: "NextAuth.js (next-auth)",
|
||||||
|
href: "https://next-auth.js.org",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
||||||
? []
|
? []
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ html[data-theme="dark"] .adapter-card {
|
|||||||
color: #f5f5f5;
|
color: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html[data-theme="dark"] .adapter-card:hover,
|
||||||
.adapter-card:hover {
|
.adapter-card:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: black;
|
color: black;
|
||||||
|
|||||||
13
package.json
13
package.json
@@ -9,7 +9,6 @@
|
|||||||
"build": "turbo run build --filter=next-auth --filter=@next-auth/* --filter=@auth/* --no-deps",
|
"build": "turbo run build --filter=next-auth --filter=@next-auth/* --filter=@auth/* --no-deps",
|
||||||
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!@*upstash* --filter=!*dynamodb-*",
|
"test": "turbo run test --concurrency=1 --filter=[HEAD^1] --filter=./packages/* --filter=!@*upstash* --filter=!*dynamodb-*",
|
||||||
"clean": "turbo run clean --no-cache",
|
"clean": "turbo run clean --no-cache",
|
||||||
"dev:example": "turbo run dev --parallel --continue --filter=nextjs-example-app... --filter=!./packages/adapter-*",
|
|
||||||
"dev:db": "turbo run dev --parallel --continue --filter=next-auth-app...",
|
"dev:db": "turbo run dev --parallel --continue --filter=next-auth-app...",
|
||||||
"dev": "turbo run dev --parallel --continue --filter=next-auth-app... --filter=!./packages/adapter-*",
|
"dev": "turbo run dev --parallel --continue --filter=next-auth-app... --filter=!./packages/adapter-*",
|
||||||
"dev-v4:db": "turbo run dev --parallel --continue --filter=next-auth-app-v4...",
|
"dev-v4:db": "turbo run dev --parallel --continue --filter=next-auth-app-v4...",
|
||||||
@@ -29,7 +28,7 @@
|
|||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.0",
|
||||||
"@balazsorban/monorepo-release": "0.1.8",
|
"@balazsorban/monorepo-release": "0.1.8",
|
||||||
"@types/jest": "^28.1.3",
|
"@types/jest": "^28.1.3",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^17.0.25",
|
||||||
"@typescript-eslint/eslint-plugin": "5.47.0",
|
"@typescript-eslint/eslint-plugin": "5.47.0",
|
||||||
"@typescript-eslint/parser": "5.47.0",
|
"@typescript-eslint/parser": "5.47.0",
|
||||||
"eslint": "8.30.0",
|
"eslint": "8.30.0",
|
||||||
@@ -44,7 +43,7 @@
|
|||||||
"eslint-plugin-svelte3": "^4.0.0",
|
"eslint-plugin-svelte3": "^4.0.0",
|
||||||
"prettier": "2.8.1",
|
"prettier": "2.8.1",
|
||||||
"prettier-plugin-svelte": "^2.8.1",
|
"prettier-plugin-svelte": "^2.8.1",
|
||||||
"turbo": "1.8.8",
|
"turbo": "1.10.1",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -97,6 +96,8 @@
|
|||||||
"packages/core/src/lib/pages/styles.ts",
|
"packages/core/src/lib/pages/styles.ts",
|
||||||
"packages/frameworks-sveltekit/package",
|
"packages/frameworks-sveltekit/package",
|
||||||
"packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*",
|
"packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*",
|
||||||
|
"packages/next-auth/src/providers/oauth-types.ts",
|
||||||
|
"packages/next-auth/css/index.css",
|
||||||
".branches",
|
".branches",
|
||||||
"db.sqlite",
|
"db.sqlite",
|
||||||
"dev.db",
|
"dev.db",
|
||||||
@@ -247,10 +248,8 @@
|
|||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": [
|
"files": [
|
||||||
"apps/dev/nextjs/pages/api/auth-old/[...nextauth].ts",
|
"apps/dev/nextjs/pages/api/auth/[...nextauth].ts",
|
||||||
"apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts",
|
"docs/{sidebars,docusaurus.config}.js"
|
||||||
"docs/{sidebars,docusaurus.config}.js",
|
|
||||||
"packages/next-auth/src/lib/env.ts"
|
|
||||||
],
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"printWidth": 150
|
"printWidth": 150
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<h3 align="center"><b>Dgraph Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
<h3 align="center"><b>Dgraph Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||||
<p align="center" style="align: center;">
|
<p align="center" style="align: center;">
|
||||||
<a href="https://npm.im/@next-auth/dgraph-adapter">
|
<a href="https://npm.im/@auth/dgraph-adapter">
|
||||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://npm.im/@next-auth/dgraph-adapter">
|
<a href="https://npm.im/@auth/dgraph-adapter">
|
||||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/dgraph-adapter?color=green&label=@next-auth/dgraph-adapter&style=flat-square">
|
<img alt="npm" src="https://img.shields.io/npm/v/@auth/dgraph-adapter?color=green&label=@auth/dgraph-adapter&style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.npmtrends.com/@next-auth/dgraph-adapter">
|
<a href="https://www.npmtrends.com/@auth/dgraph-adapter">
|
||||||
<img src="https://img.shields.io/npm/dm/@next-auth/dgraph-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
<img src="https://img.shields.io/npm/dm/@auth/dgraph-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
<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" />
|
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||||
|
|||||||
@@ -1,19 +1,30 @@
|
|||||||
{
|
{
|
||||||
"name": "@next-auth/dgraph-adapter",
|
"name": "@auth/dgraph-adapter",
|
||||||
"version": "1.0.6",
|
"version": "1.0.0",
|
||||||
"description": "Dgraph adapter for next-auth.",
|
"description": "Dgraph adapter for Auth.js",
|
||||||
"homepage": "https://authjs.dev",
|
"homepage": "https://authjs.dev",
|
||||||
"repository": "https://github.com/nextauthjs/next-auth",
|
"repository": "https://github.com/nextauthjs/next-auth",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||||
},
|
},
|
||||||
"author": "Arnaud Derbey <arnaud@derbey.dev>",
|
"author": "Arnaud Derbey <arnaud@derbey.dev>",
|
||||||
"contributors": [],
|
"contributors": [
|
||||||
"main": "dist/index.js",
|
"Balázs Orbán <info@balazsorban.com>"
|
||||||
"files": [
|
|
||||||
"dist",
|
|
||||||
"index.d.ts"
|
|
||||||
],
|
],
|
||||||
|
"type": "module",
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"*.js",
|
||||||
|
"*.d.ts*",
|
||||||
|
"lib",
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"import": "./index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"next-auth",
|
"next-auth",
|
||||||
@@ -29,10 +40,6 @@
|
|||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "./tests/test.sh"
|
"test": "./tests/test.sh"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
|
||||||
"jsonwebtoken": "^8.5.1",
|
|
||||||
"next-auth": "^4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next-auth/adapter-test": "workspace:*",
|
"@next-auth/adapter-test": "workspace:*",
|
||||||
"@next-auth/tsconfig": "workspace:*",
|
"@next-auth/tsconfig": "workspace:*",
|
||||||
@@ -40,12 +47,12 @@
|
|||||||
"@types/jsonwebtoken": "^8.5.5",
|
"@types/jsonwebtoken": "^8.5.5",
|
||||||
"@types/node-fetch": "^2.5.11",
|
"@types/node-fetch": "^2.5.11",
|
||||||
"jest": "^27.4.3",
|
"jest": "^27.4.3",
|
||||||
"next-auth": "workspace:*",
|
"ts-jest": "^27.0.3",
|
||||||
"ts-jest": "^27.0.3"
|
"undici": "5.22.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsonwebtoken": "^8.5.1",
|
"@auth/core": "workspace:*",
|
||||||
"node-fetch": "^2.6.1"
|
"jsonwebtoken": "^8.5.1"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"preset": "@next-auth/adapter-test/jest"
|
"preset": "@next-auth/adapter-test/jest"
|
||||||
|
|||||||
@@ -9,18 +9,18 @@
|
|||||||
* ## Installation
|
* ## Installation
|
||||||
*
|
*
|
||||||
* ```bash npm2yarn2pnpm
|
* ```bash npm2yarn2pnpm
|
||||||
* npm install next-auth @next-auth/dgraph-adapter
|
* npm install next-auth @auth/dgraph-adapter
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @module @next-auth/dgraph-adapter
|
* @module @auth/dgraph-adapter
|
||||||
*/
|
*/
|
||||||
import { client as dgraphClient } from "./client"
|
import { client as dgraphClient } from "./lib/client"
|
||||||
import { format } from "./utils"
|
import { format } from "./lib/utils"
|
||||||
import type { Adapter } from "next-auth/adapters"
|
import type { Adapter } from "@auth/core/adapters"
|
||||||
import type { DgraphClientParams } from "./client"
|
import type { DgraphClientParams } from "./lib/client"
|
||||||
import * as defaultFragments from "./graphql/fragments"
|
import * as defaultFragments from "./lib/graphql/fragments"
|
||||||
|
|
||||||
export type { DgraphClientParams, DgraphClientError } from "./client"
|
export type { DgraphClientParams, DgraphClientError } from "./lib/client"
|
||||||
|
|
||||||
/** This is the interface of the Dgraph adapter options. */
|
/** This is the interface of the Dgraph adapter options. */
|
||||||
export interface DgraphAdapterOptions {
|
export interface DgraphAdapterOptions {
|
||||||
@@ -28,7 +28,7 @@ export interface DgraphAdapterOptions {
|
|||||||
* The GraphQL {@link https://dgraph.io/docs/query-language/fragments/ Fragments} you can supply to the adapter
|
* The GraphQL {@link https://dgraph.io/docs/query-language/fragments/ Fragments} you can supply to the adapter
|
||||||
* to define how the shapes of the `user`, `account`, `session`, `verificationToken` entities look.
|
* to define how the shapes of the `user`, `account`, `session`, `verificationToken` entities look.
|
||||||
*
|
*
|
||||||
* By default the adapter will uses the [default defined fragments](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-dgraph/src/graphql/fragments.ts)
|
* By default the adapter will uses the [default defined fragments](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-dgraph/src/lib/graphql/fragments.ts)
|
||||||
* , this config option allows to extend them.
|
* , this config option allows to extend them.
|
||||||
*/
|
*/
|
||||||
fragments?: {
|
fragments?: {
|
||||||
@@ -48,7 +48,7 @@ export { format }
|
|||||||
*
|
*
|
||||||
* ```ts title="pages/api/auth/[...nextauth].js"
|
* ```ts title="pages/api/auth/[...nextauth].js"
|
||||||
* import NextAuth from "next-auth"
|
* import NextAuth from "next-auth"
|
||||||
* import { DgraphAdapter } from "@next-auth/dgraph-adapter"
|
* import { DgraphAdapter } from "@auth/dgraph-adapter"
|
||||||
*
|
*
|
||||||
* export default NextAuth({
|
* export default NextAuth({
|
||||||
* providers: [],
|
* providers: [],
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import * as jwt from "jsonwebtoken"
|
import * as jwt from "jsonwebtoken"
|
||||||
import fetch from "node-fetch"
|
|
||||||
|
|
||||||
import type { HeadersInit } from "node-fetch"
|
|
||||||
|
|
||||||
export interface DgraphClientParams {
|
export interface DgraphClientParams {
|
||||||
endpoint: string
|
endpoint: string
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
import { DgraphAdapter, format } from "../src"
|
import { DgraphAdapter, format } from "../src"
|
||||||
import { client as dgraphClient } from "../src/client"
|
import { client as dgraphClient } from "../src/lib/client"
|
||||||
import * as fragments from "../src/graphql/fragments"
|
import * as fragments from "../src/lib/graphql/fragments"
|
||||||
import { runBasicTests } from "@next-auth/adapter-test"
|
import { runBasicTests } from "@next-auth/adapter-test"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|
||||||
import type { DgraphClientParams } from "../src"
|
import type { DgraphClientParams } from "../src"
|
||||||
|
|
||||||
|
globalThis.fetch ??= require("undici").fetch
|
||||||
|
|
||||||
const params: DgraphClientParams = {
|
const params: DgraphClientParams = {
|
||||||
endpoint: "http://localhost:8080/graphql",
|
endpoint: "http://localhost:8080/graphql",
|
||||||
authToken: "test",
|
authToken: "test",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ dgraph/standalone
|
|||||||
|
|
||||||
echo "Waiting 15 sec for db to start..." && sleep 15
|
echo "Waiting 15 sec for db to start..." && sleep 15
|
||||||
|
|
||||||
head -n -1 src/graphql/schema.gql > tests/test.schema.gql
|
head -n -1 src/lib/graphql/schema.gql > tests/test.schema.gql
|
||||||
PUBLIC_KEY=$(sed 's/$/\\n/' tests/public.key | tr -d '\n')
|
PUBLIC_KEY=$(sed 's/$/\\n/' tests/public.key | tr -d '\n')
|
||||||
echo "# Dgraph.Authorization {\"VerificationKey\":\"$PUBLIC_KEY\",\"Namespace\":\"https://dgraph.io/jwt/claims\",\"Header\":\"Authorization\",\"Algo\":\"RS256\"}" >> tests/test.schema.gql
|
echo "# Dgraph.Authorization {\"VerificationKey\":\"$PUBLIC_KEY\",\"Namespace\":\"https://dgraph.io/jwt/claims\",\"Header\":\"Authorization\",\"Algo\":\"RS256\"}" >> tests/test.schema.gql
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"isolatedModules": true,
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"outDir": ".",
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "dist"
|
"skipDefaultLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"stripInternal": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"declaration": true
|
||||||
},
|
},
|
||||||
"exclude": ["tests", "dist", "jest.config.js"]
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"*.js",
|
||||||
|
"*.d.ts",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<h3 align="center"><b>DynamoDB Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
<h3 align="center"><b>DynamoDB Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||||
<p align="center" style="align: center;">
|
<p align="center" style="align: center;">
|
||||||
<a href="https://npm.im/@next-auth/dynamodb-adapter">
|
<a href="https://npm.im/@auth/dynamodb-adapter">
|
||||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://npm.im/@next-auth/dynamodb-adapter">
|
<a href="https://npm.im/@auth/dynamodb-adapter">
|
||||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/dynamodb-adapter?color=green&label=@next-auth/dynamodb-adapter&style=flat-square">
|
<img alt="npm" src="https://img.shields.io/npm/v/@auth/dynamodb-adapter?color=green&label=@auth/dynamodb-adapter&style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.npmtrends.com/@next-auth/dynamodb-adapter">
|
<a href="https://www.npmtrends.com/@auth/dynamodb-adapter">
|
||||||
<img src="https://img.shields.io/npm/dm/@next-auth/dynamodb-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
<img src="https://img.shields.io/npm/dm/@auth/dynamodb-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
<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" />
|
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@next-auth/dynamodb-adapter",
|
"name": "@auth/dynamodb-adapter",
|
||||||
"repository": "https://github.com/nextauthjs/next-auth",
|
"repository": "https://github.com/nextauthjs/next-auth",
|
||||||
"version": "3.0.2",
|
"version": "1.0.0",
|
||||||
"description": "AWS DynamoDB adapter for next-auth.",
|
"description": "AWS DynamoDB adapter for next-auth.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"next-auth",
|
"next-auth",
|
||||||
@@ -9,18 +9,10 @@
|
|||||||
"oauth",
|
"oauth",
|
||||||
"dynamodb"
|
"dynamodb"
|
||||||
],
|
],
|
||||||
"type": "module",
|
|
||||||
"types": "./index.d.ts",
|
|
||||||
"homepage": "https://authjs.dev",
|
"homepage": "https://authjs.dev",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||||
},
|
},
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"types": "./index.d.ts",
|
|
||||||
"import": "./index.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"private": false,
|
"private": false,
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
@@ -32,19 +24,27 @@
|
|||||||
"clean": "rm -rf index.*",
|
"clean": "rm -rf index.*",
|
||||||
"build": "pnpm clean && tsc"
|
"build": "pnpm clean && tsc"
|
||||||
},
|
},
|
||||||
|
"author": "Pol Marnette",
|
||||||
|
"contributors": [
|
||||||
|
"Balázs Orbán <info@balazsorban.com>"
|
||||||
|
],
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "module",
|
||||||
|
"types": "./index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
"README.md",
|
"*.js",
|
||||||
"index.js",
|
"*.d.ts*",
|
||||||
"index.d.ts",
|
|
||||||
"index.d.ts.map",
|
|
||||||
"src"
|
"src"
|
||||||
],
|
],
|
||||||
"author": "Pol Marnette",
|
"exports": {
|
||||||
"license": "ISC",
|
".": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"import": "./index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@aws-sdk/client-dynamodb": "^3.36.1",
|
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||||
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
"@aws-sdk/lib-dynamodb": "^3.36.1"
|
||||||
"next-auth": "^4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aws-sdk/client-dynamodb": "^3.36.1",
|
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||||
@@ -52,11 +52,9 @@
|
|||||||
"@next-auth/adapter-test": "workspace:*",
|
"@next-auth/adapter-test": "workspace:*",
|
||||||
"@next-auth/tsconfig": "workspace:*",
|
"@next-auth/tsconfig": "workspace:*",
|
||||||
"@shelf/jest-dynamodb": "^2.1.0",
|
"@shelf/jest-dynamodb": "^2.1.0",
|
||||||
"@types/uuid": "^9.0.0",
|
"jest": "^27.4.3"
|
||||||
"jest": "^27.4.3",
|
|
||||||
"next-auth": "workspace:*"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"uuid": "^9.0.0"
|
"@auth/core": "workspace:*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,12 +9,11 @@
|
|||||||
* ## Installation
|
* ## Installation
|
||||||
*
|
*
|
||||||
* ```bash npm2yarn2pnpm
|
* ```bash npm2yarn2pnpm
|
||||||
* npm install next-auth @next-auth/dynamodb-adapter
|
* npm install next-auth @auth/dynamodb-adapter
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @module @next-auth/dynamodb-adapter
|
* @module @auth/dynamodb-adapter
|
||||||
*/
|
*/
|
||||||
import { v4 as uuid } from "uuid"
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
BatchWriteCommandInput,
|
BatchWriteCommandInput,
|
||||||
@@ -26,7 +25,7 @@ import type {
|
|||||||
AdapterAccount,
|
AdapterAccount,
|
||||||
AdapterUser,
|
AdapterUser,
|
||||||
VerificationToken,
|
VerificationToken,
|
||||||
} from "next-auth/adapters"
|
} from "@auth/core/adapters"
|
||||||
|
|
||||||
export interface DynamoDBAdapterOptions {
|
export interface DynamoDBAdapterOptions {
|
||||||
tableName?: string
|
tableName?: string
|
||||||
@@ -53,7 +52,7 @@ export interface DynamoDBAdapterOptions {
|
|||||||
* import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
* import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
||||||
* import NextAuth from "next-auth";
|
* import NextAuth from "next-auth";
|
||||||
* import Providers from "next-auth/providers";
|
* import Providers from "next-auth/providers";
|
||||||
* import { DynamoDBAdapter } from "@next-auth/dynamodb-adapter"
|
* import { DynamoDBAdapter } from "@auth/dynamodb-adapter"
|
||||||
*
|
*
|
||||||
* const config: DynamoDBClientConfig = {
|
* const config: DynamoDBClientConfig = {
|
||||||
* credentials: {
|
* credentials: {
|
||||||
@@ -187,7 +186,7 @@ export function DynamoDBAdapter(
|
|||||||
async createUser(data) {
|
async createUser(data) {
|
||||||
const user: AdapterUser = {
|
const user: AdapterUser = {
|
||||||
...(data as any),
|
...(data as any),
|
||||||
id: uuid(),
|
id: crypto.randomUUID(),
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.put({
|
await client.put({
|
||||||
@@ -312,7 +311,7 @@ export function DynamoDBAdapter(
|
|||||||
async linkAccount(data) {
|
async linkAccount(data) {
|
||||||
const item = {
|
const item = {
|
||||||
...data,
|
...data,
|
||||||
id: uuid(),
|
id: crypto.randomUUID(),
|
||||||
[pk]: `USER#${data.userId}`,
|
[pk]: `USER#${data.userId}`,
|
||||||
[sk]: `ACCOUNT#${data.provider}#${data.providerAccountId}`,
|
[sk]: `ACCOUNT#${data.provider}#${data.providerAccountId}`,
|
||||||
[GSI1PK]: `ACCOUNT#${data.provider}`,
|
[GSI1PK]: `ACCOUNT#${data.provider}`,
|
||||||
@@ -376,7 +375,7 @@ export function DynamoDBAdapter(
|
|||||||
},
|
},
|
||||||
async createSession(data) {
|
async createSession(data) {
|
||||||
const session = {
|
const session = {
|
||||||
id: uuid(),
|
id: crypto.randomUUID(),
|
||||||
...data,
|
...data,
|
||||||
}
|
}
|
||||||
await client.put({
|
await client.put({
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"rootDir": "src",
|
"allowJs": true,
|
||||||
"outDir": ".",
|
"baseUrl": ".",
|
||||||
|
"isolatedModules": true,
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
"outDir": ".",
|
||||||
|
"rootDir": "src",
|
||||||
"skipDefaultLibCheck": true,
|
"skipDefaultLibCheck": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"stripInternal": true,
|
"stripInternal": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
"declaration": true
|
"declaration": true
|
||||||
},
|
},
|
||||||
"exclude": ["tests", "dist", "jest.config.js", "jest-dynamodb-config.js"]
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"*.js",
|
||||||
|
"*.d.ts",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<h3 align="center"><b>Fauna Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
<h3 align="center"><b>Fauna Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||||
<p align="center" style="align: center;">
|
<p align="center" style="align: center;">
|
||||||
<a href="https://npm.im/@next-auth/fauna-adapter">
|
<a href="https://npm.im/@auth/fauna-adapter">
|
||||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://npm.im/@next-auth/fauna-adapter">
|
<a href="https://npm.im/@auth/fauna-adapter">
|
||||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/fauna-adapter?color=green&label=@next-auth/fauna-adapter&style=flat-square">
|
<img alt="npm" src="https://img.shields.io/npm/v/@auth/fauna-adapter?color=green&label=@auth/fauna-adapter&style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.npmtrends.com/@next-auth/fauna-adapter">
|
<a href="https://www.npmtrends.com/@auth/fauna-adapter">
|
||||||
<img src="https://img.shields.io/npm/dm/@next-auth/fauna-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
<img src="https://img.shields.io/npm/dm/@auth/fauna-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
<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" />
|
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
{
|
{
|
||||||
"name": "@next-auth/fauna-adapter",
|
"name": "@auth/fauna-adapter",
|
||||||
"version": "1.0.4",
|
"version": "1.0.0",
|
||||||
"description": "Fauna Adapter for NextAuth",
|
"description": "Fauna Adapter for Auth.js",
|
||||||
"homepage": "https://authjs.dev",
|
"homepage": "https://authjs.dev",
|
||||||
"repository": "https://github.com/nextauthjs/next-auth",
|
"repository": "https://github.com/nextauthjs/next-auth",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||||
},
|
},
|
||||||
"files": [
|
|
||||||
"dist",
|
|
||||||
"README.md"
|
|
||||||
],
|
|
||||||
"author": "Bhanu Teja P",
|
"author": "Bhanu Teja P",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
"Nico Domino <yo@ndo.dev>",
|
||||||
"name": "Nico Domino",
|
"Balázs Orbán <info@balazsorban.com>"
|
||||||
"email": "yo@ndo.dev"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Balázs Orbán",
|
|
||||||
"email": "info@balazsorban.com"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"main": "dist/index.js",
|
"type": "module",
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"*.js",
|
||||||
|
"*.d.ts*",
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"import": "./index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"next-auth",
|
"next-auth",
|
||||||
@@ -41,17 +43,18 @@
|
|||||||
"migrate": "fauna-schema-migrate generate",
|
"migrate": "fauna-schema-migrate generate",
|
||||||
"test": "./tests/test.sh"
|
"test": "./tests/test.sh"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@auth/core": "workspace:*"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"faunadb": "^4.3.0",
|
"faunadb": "^4.3.0"
|
||||||
"next-auth": "^4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fauna-labs/fauna-schema-migrate": "^2.1.3",
|
"@fauna-labs/fauna-schema-migrate": "^2.1.3",
|
||||||
"@next-auth/adapter-test": "workspace:*",
|
"@next-auth/adapter-test": "workspace:*",
|
||||||
"@next-auth/tsconfig": "workspace:*",
|
"@next-auth/tsconfig": "workspace:*",
|
||||||
"faunadb": "^4.3.0",
|
"faunadb": "^4.3.0",
|
||||||
"jest": "^27.4.3",
|
"jest": "^27.4.3"
|
||||||
"next-auth": "workspace:*"
|
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"preset": "@next-auth/adapter-test/jest"
|
"preset": "@next-auth/adapter-test/jest"
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
* ## Installation
|
* ## Installation
|
||||||
*
|
*
|
||||||
* ```bash npm2yarn2pnpm
|
* ```bash npm2yarn2pnpm
|
||||||
* npm install next-auth @next-auth/fauna-adapter faunadb
|
* npm install @auth/fauna-adapter faunadb
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
* @module @next-auth/fauna-adapter
|
* @module @auth/fauna-adapter
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
Client as FaunaClient,
|
Client as FaunaClient,
|
||||||
@@ -44,7 +44,7 @@ import {
|
|||||||
AdapterSession,
|
AdapterSession,
|
||||||
AdapterUser,
|
AdapterUser,
|
||||||
VerificationToken,
|
VerificationToken,
|
||||||
} from "next-auth/adapters"
|
} from "@auth/core/adapters"
|
||||||
|
|
||||||
export const collections = {
|
export const collections = {
|
||||||
Users: Collection("users"),
|
Users: Collection("users"),
|
||||||
@@ -137,7 +137,7 @@ export function query(f: FaunaClient, format: (...args: any) => any) {
|
|||||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||||
* import NextAuth from "next-auth"
|
* import NextAuth from "next-auth"
|
||||||
* import { Client as FaunaClient } from "faunadb"
|
* import { Client as FaunaClient } from "faunadb"
|
||||||
* import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
* import { FaunaAdapter } from "@auth/fauna-adapter"
|
||||||
*
|
*
|
||||||
* const client = new FaunaClient({
|
* const client = new FaunaClient({
|
||||||
* secret: "secret",
|
* secret: "secret",
|
||||||
|
|||||||
@@ -1,8 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"isolatedModules": true,
|
||||||
|
"target": "ES2020",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"outDir": ".",
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "dist"
|
"skipDefaultLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"stripInternal": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"declaration": true
|
||||||
},
|
},
|
||||||
"exclude": ["tests", "dist", "jest.config.js"]
|
"include": [
|
||||||
|
"src/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"*.js",
|
||||||
|
"*.d.ts",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
1
packages/adapter-firebase/.npmrc
Normal file
1
packages/adapter-firebase/.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
||||||
@@ -8,14 +8,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<h3 align="center"><b>Firebase Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
<h3 align="center"><b>Firebase Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||||
<p align="center" style="align: center;">
|
<p align="center" style="align: center;">
|
||||||
<a href="https://npm.im/@next-auth/firebase-adapter">
|
<a href="https://npm.im/@auth/firebase-adapter">
|
||||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://npm.im/@next-auth/firebase-adapter">
|
<a href="https://npm.im/@auth/firebase-adapter">
|
||||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/firebase-adapter?color=green&label=@next-auth/firebase-adapter&style=flat-square">
|
<img alt="npm" src="https://img.shields.io/npm/v/@auth/firebase-adapter?color=green&label=@auth/firebase-adapter&style=flat-square">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.npmtrends.com/@next-auth/firebase-adapter">
|
<a href="https://www.npmtrends.com/@auth/firebase-adapter">
|
||||||
<img src="https://img.shields.io/npm/dm/@next-auth/firebase-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
<img src="https://img.shields.io/npm/dm/@auth/firebase-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
<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" />
|
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@next-auth/firebase-adapter",
|
"name": "@auth/firebase-adapter",
|
||||||
"version": "2.0.1",
|
"version": "1.0.0",
|
||||||
"description": "Firebase adapter for next-auth.",
|
"description": "Firebase adapter for Auth.js",
|
||||||
"homepage": "https://authjs.dev",
|
"homepage": "https://authjs.dev",
|
||||||
"repository": "https://github.com/nextauthjs/next-auth",
|
"repository": "https://github.com/nextauthjs/next-auth",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@@ -13,17 +13,18 @@
|
|||||||
"Alex Meuer <github@alexmeuer.com>"
|
"Alex Meuer <github@alexmeuer.com>"
|
||||||
],
|
],
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"types": "./index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"*.js",
|
||||||
|
"*.d.ts*",
|
||||||
|
"src"
|
||||||
|
],
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./index.d.ts",
|
"types": "./index.d.ts",
|
||||||
"import": "./index.js"
|
"import": "./index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": [
|
|
||||||
"src",
|
|
||||||
"*.js",
|
|
||||||
"*.d.ts*"
|
|
||||||
],
|
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"next-auth",
|
"next-auth",
|
||||||
@@ -40,16 +41,17 @@
|
|||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"test": "firebase emulators:exec --only firestore --project next-auth-test 'jest -c tests/jest.config.js'"
|
"test": "firebase emulators:exec --only firestore --project next-auth-test 'jest -c tests/jest.config.js'"
|
||||||
},
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@auth/core": "workspace:*"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"firebase-admin": "^11.4.1",
|
"firebase-admin": "^11.4.1"
|
||||||
"next-auth": "^4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@next-auth/adapter-test": "workspace:*",
|
"@next-auth/adapter-test": "workspace:*",
|
||||||
"@next-auth/tsconfig": "workspace:*",
|
"@next-auth/tsconfig": "workspace:*",
|
||||||
"firebase-admin": "^11.4.1",
|
"firebase-admin": "^11.4.1",
|
||||||
"firebase-tools": "^11.16.1",
|
"firebase-tools": "^11.16.1",
|
||||||
"jest": "^29.3.1",
|
"jest": "^29.3.1"
|
||||||
"next-auth": "workspace:*"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user