mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
61 Commits
@auth/core
...
feat/nextj
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54876744fe | ||
|
|
28cbb3aac5 | ||
|
|
ac0ca51278 | ||
|
|
5400645221 | ||
|
|
d739e8e04e | ||
|
|
c2eb9b3ad4 | ||
|
|
4f54840014 | ||
|
|
d938333750 | ||
|
|
d837dfaea1 | ||
|
|
a99f4bd8c6 | ||
|
|
a96b8597b1 | ||
|
|
29ce4cb4d4 | ||
|
|
da40242e48 | ||
|
|
3f211e7ad0 | ||
|
|
5f369b0981 | ||
|
|
4a056c774f | ||
|
|
038b9bccad | ||
|
|
dfb20849c5 | ||
|
|
4a7a7ab757 | ||
|
|
f94b604397 | ||
|
|
535f9276f6 | ||
|
|
cd2872de89 | ||
|
|
2de2dc9bb3 | ||
|
|
6f96004d75 | ||
|
|
f834bc2a99 | ||
|
|
551dcbd2d5 | ||
|
|
316b344930 | ||
|
|
97ff6406cb | ||
|
|
1b9559fbb1 | ||
|
|
27864eea2f | ||
|
|
e5f18e3266 | ||
|
|
47eec2c498 | ||
|
|
77bba4ada7 | ||
|
|
f081fcd31d | ||
|
|
5f079930cc | ||
|
|
4cc4b45e52 | ||
|
|
c0cfb13c88 | ||
|
|
537112a306 | ||
|
|
6663003c7c | ||
|
|
68559941a5 | ||
|
|
cec1fd753e | ||
|
|
c97c40c9cb | ||
|
|
defc2233be | ||
|
|
e0450c9d52 | ||
|
|
04021c6d47 | ||
|
|
210d28b6b0 | ||
|
|
fcd9bfc6f8 | ||
|
|
0a027cf35d | ||
|
|
47ac2e94ce | ||
|
|
30e3672708 | ||
|
|
635a9b0c50 | ||
|
|
510b9764f5 | ||
|
|
7329725702 | ||
|
|
23ea9428e0 | ||
|
|
319f7af866 | ||
|
|
58be169b10 | ||
|
|
c87fdd9060 | ||
|
|
28263f52bd | ||
|
|
27869b70b8 | ||
|
|
7af7ca4d1c | ||
|
|
30948fbada |
4
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
4
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -29,10 +29,10 @@ body:
|
||||
- "@next-auth/mongodb-adapter"
|
||||
- "@next-auth/neo4j-adapter"
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
- "@auth/prisma-adapter"
|
||||
- "@next-auth/prisma-adapter"
|
||||
- "@next-auth/sequelize-adapter"
|
||||
- "@next-auth/supabase-adapter"
|
||||
- "@auth/typeorm-adapter"
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
- "@next-auth/xata-adapter"
|
||||
validations:
|
||||
|
||||
6
.github/issue-labeler.yml
vendored
6
.github/issue-labeler.yml
vendored
@@ -25,7 +25,7 @@ pouchdb:
|
||||
- "@next-auth/pouchdb-adapter"
|
||||
|
||||
prisma:
|
||||
- "@auth/prisma-adapter"
|
||||
- "@next-auth/prisma-adapter"
|
||||
|
||||
sequelize:
|
||||
- "@next-auth/sequelize-adapter"
|
||||
@@ -33,8 +33,8 @@ sequelize:
|
||||
supabase:
|
||||
- "@next-auth/supabase-adapter"
|
||||
|
||||
typeorm:
|
||||
- "@auth/typeorm-adapter"
|
||||
typeorm-legacy:
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
|
||||
upstash-redis:
|
||||
- "@next-auth/upstash-redis-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/**/*"]
|
||||
svelte: ["packages/frameworks-sveltekit/**/*"]
|
||||
test: ["**test**/*"]
|
||||
typeorm: ["packages/adapter-typeorm/**/*"]
|
||||
typeorm-legacy: ["packages/adapter-typeorm-legacy/**/*"]
|
||||
upstash-redis: ["packages/adapter-upstash-redis/**/*"]
|
||||
xata: ["packages/adapter-xata/**/*"]
|
||||
|
||||
9
.github/version-pr/index.js
vendored
9
.github/version-pr/index.js
vendored
@@ -5,15 +5,14 @@ const core = require("@actions/core")
|
||||
try {
|
||||
const packageJSONPath = path.join(
|
||||
process.cwd(),
|
||||
`packages/${process.env.PACKAGE_PATH || "next-auth"}/package.json`
|
||||
"packages/next-auth/package.json"
|
||||
)
|
||||
const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath, "utf8"))
|
||||
|
||||
const sha8 = process.env.GITHUB_SHA.substring(0, 8)
|
||||
const prefix = "0.0.0-"
|
||||
const pr = process.env.PR_NUMBER
|
||||
const source = pr ? `pr.${pr}` : "manual"
|
||||
const packageVersion = `${prefix}${source}.${sha8}`
|
||||
const prNumber = process.env.PR_NUMBER
|
||||
|
||||
const packageVersion = `0.0.0-pr.${prNumber}.${sha8}`
|
||||
packageJSON.version = packageVersion
|
||||
core.setOutput("version", packageVersion)
|
||||
fs.writeFileSync(packageJSONPath, JSON.stringify(packageJSON))
|
||||
|
||||
84
.github/workflows/release.yml
vendored
84
.github/workflows/release.yml
vendored
@@ -8,54 +8,6 @@ on:
|
||||
- next
|
||||
- 3.x
|
||||
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:
|
||||
test:
|
||||
@@ -72,7 +24,6 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Run tests
|
||||
@@ -122,7 +73,6 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Publish to npm and GitHub
|
||||
@@ -147,7 +97,6 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Determine version
|
||||
@@ -173,36 +122,3 @@ jobs:
|
||||
env:
|
||||
VERSION: ${{ steps.determine-version.outputs.version }}
|
||||
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 }}
|
||||
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -26,15 +26,7 @@ dist
|
||||
# Generated files
|
||||
.docusaurus
|
||||
.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/*/*.d.ts
|
||||
packages/*/*.d.ts.map
|
||||
@@ -85,7 +77,10 @@ packages/core/providers
|
||||
packages/core/src/lib/pages/styles.ts
|
||||
docs/docs/reference/core
|
||||
docs/docs/reference/sveltekit
|
||||
docs/docs/reference/next-auth
|
||||
|
||||
# Next.js
|
||||
packages/next-auth/lib
|
||||
|
||||
# SvelteKit
|
||||
packages/frameworks-sveltekit/index.*
|
||||
|
||||
@@ -40,10 +40,6 @@ packages/core/src/lib/pages/styles.ts
|
||||
packages/frameworks-sveltekit/package
|
||||
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
|
||||
.branches
|
||||
|
||||
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"packages/core/{lib,providers,*.js,*.d.ts,*.d.ts.map}": true,
|
||||
"packages/next-auth/{client,core,css,jwt,next,providers,react,utils,*.js,*.d.ts}": true
|
||||
"packages/core/{lib,providers,*.js,*.d.ts*}": true,
|
||||
"packages/next-auth/{lib,*.js,*.d.ts*}": true,
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"openInGitHub.remote.branch": "main"
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,9 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@auth/typeorm-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"@supabase/supabase-js": "^2.0.5",
|
||||
"faunadb": "^4",
|
||||
|
||||
@@ -37,7 +37,7 @@ import WorkOS from "next-auth/providers/workos"
|
||||
|
||||
// // Prisma
|
||||
// import { PrismaClient } from "@prisma/client"
|
||||
// import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
// const client = globalThis.prisma || new PrismaClient()
|
||||
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||
// const adapter = PrismaAdapter(client)
|
||||
@@ -51,8 +51,8 @@ import WorkOS from "next-auth/providers/workos"
|
||||
// const adapter = FaunaAdapter(client)
|
||||
|
||||
// // TypeORM
|
||||
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
// const adapter = TypeORMAdapter({
|
||||
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
// const adapter = TypeORMLegacyAdapter({
|
||||
// type: "sqlite",
|
||||
// name: "next-auth-test-memory",
|
||||
// database: "./typeorm/dev.db",
|
||||
|
||||
3
apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
3
apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { handlers } from "auth"
|
||||
export const { GET, POST } = handlers
|
||||
export const runtime = "edge"
|
||||
10
apps/dev/nextjs/app/api/protected/route.ts
Normal file
10
apps/dev/nextjs/app/api/protected/route.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
export const GET = auth(function GET(req) {
|
||||
if (req.auth) {
|
||||
return NextResponse.json(req.auth)
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||
})
|
||||
@@ -1,6 +1,37 @@
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { auth } from "auth"
|
||||
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() {
|
||||
const session = await unstable_getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
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>
|
||||
}
|
||||
|
||||
21
apps/dev/nextjs/auth.ts
Normal file
21
apps/dev/nextjs/auth.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
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 styles from "./footer.module.css"
|
||||
import packageJSON from "package.json"
|
||||
import packageJSON from "next-auth/package.json"
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
|
||||
@@ -76,12 +76,6 @@ export default function Header() {
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/middleware-protected">Middleware protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/supabase-client-rls">Supabase RLS</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/supabase-ssr">Supabase RLS(SSR)</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -1,45 +1,10 @@
|
||||
export { default } from "next-auth/middleware"
|
||||
// export { auth as default } from "auth"
|
||||
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"] }
|
||||
|
||||
// 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,14 +15,15 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"next-auth": "workspace:*",
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@auth/typeorm-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"@supabase/supabase-js": "^2.0.5",
|
||||
"faunadb": "^4",
|
||||
"next": "13.3.0",
|
||||
"next": "13.3.2-canary.12",
|
||||
"next-auth": "workspace:*",
|
||||
"nodemailer": "^6",
|
||||
"react": "^18",
|
||||
|
||||
@@ -41,7 +41,7 @@ import WorkOS from "@auth/core/providers/workos"
|
||||
|
||||
// // Prisma
|
||||
// import { PrismaClient } from "@prisma/client"
|
||||
// import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
// const client = globalThis.prisma || new PrismaClient()
|
||||
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||
// const adapter = PrismaAdapter(client)
|
||||
@@ -55,8 +55,8 @@ import WorkOS from "@auth/core/providers/workos"
|
||||
// const adapter = FaunaAdapter(client)
|
||||
|
||||
// // TypeORM
|
||||
// import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
// const adapter = TypeORMAdapter({
|
||||
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
// const adapter = TypeORMLegacyAdapter({
|
||||
// type: "sqlite",
|
||||
// name: "next-auth-test-memory",
|
||||
// database: "./typeorm/dev.db",
|
||||
@@ -94,7 +94,11 @@ export const authConfig: AuthConfig = {
|
||||
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||
}),
|
||||
AzureB2C({ clientId: process.env.AZURE_B2C_ID, clientSecret: process.env.AZURE_B2C_SECRET, issuer: process.env.AZURE_B2C_ISSUER }),
|
||||
BeyondIdentity({ clientId: process.env.BEYOND_IDENTITY_CLIENT_ID, clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET, issuer: process.env.BEYOND_IDENTITY_ISSUER }),
|
||||
BeyondIdentity({
|
||||
clientId: process.env.BEYOND_IDENTITY_CLIENT_ID,
|
||||
clientSecret: process.env.BEYOND_IDENTITY_CLIENT_SECRET,
|
||||
issuer: process.env.BEYOND_IDENTITY_ISSUER,
|
||||
}),
|
||||
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
||||
// Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
|
||||
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
||||
@@ -156,4 +160,4 @@ function AuthHandler(...args: any[]) {
|
||||
|
||||
export default AuthHandler(authConfig)
|
||||
|
||||
export const config = { runtime: "experimental-edge" }
|
||||
export const config = { runtime: "edge" }
|
||||
@@ -1,9 +1,9 @@
|
||||
// This is an example of to protect an API route
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
import { authConfig } from "../auth-old/[...nextauth]"
|
||||
import { getServerSession } from "next-auth/next"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
const session = await getServerSession(req, res, authConfig as any)
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
@@ -1,8 +0,0 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
res.json(session)
|
||||
}
|
||||
8
apps/dev/nextjs/pages/api/examples/session.ts
Normal file
8
apps/dev/nextjs/pages/api/examples/session.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { authConfig } from "../auth-old/[...nextauth]"
|
||||
// This is an example of how to access a session from an API route
|
||||
import { getServerSession } from "next-auth/next"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getServerSession(req, res, authConfig as any)
|
||||
res.json(session)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// This is an example of how to query data from Supabase with RLS.
|
||||
// Learn more about Row Levele Security (RLS): https://supabase.com/docs/guides/auth/row-level-security
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (!session)
|
||||
return res.send(JSON.stringify({ error: "No session!" }, null, 2))
|
||||
|
||||
const { supabaseAccessToken } = session
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
// Now you can query with RLS enabled.
|
||||
const { data, error } = await supabase.from("users").select("*")
|
||||
|
||||
res.send(JSON.stringify({ supabaseAccessToken, data, error }, null, 2))
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authConfig } from "./api/auth-old/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
@@ -26,11 +26,7 @@ export default function Page({ content, session }) {
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
)
|
||||
const session = await getServerSession(context.req, context.res, authConfig)
|
||||
let content = null
|
||||
|
||||
if (session) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import Layout from "../components/layout"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import { authConfig } from "./api/auth-old/[...nextauth]"
|
||||
|
||||
export default function Page() {
|
||||
// As this page uses Server Side Rendering, the `session` will be already
|
||||
@@ -12,11 +12,11 @@ export default function Page() {
|
||||
<Layout>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||
in <strong>getServerSideProps()</strong>.
|
||||
This page uses the <strong>getServerSession()</strong> method in{" "}
|
||||
<strong>getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||
Using <strong>getServerSession()</strong> in{" "}
|
||||
<strong>getServerSideProps()</strong> is currently the recommended
|
||||
approach, although the API may still change, if you need to support
|
||||
Server Side Rendering with authentication.
|
||||
@@ -40,11 +40,7 @@ export default function Page() {
|
||||
export async function getServerSideProps(context) {
|
||||
return {
|
||||
props: {
|
||||
session: await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
),
|
||||
session: await getServerSession(context.req, context.res, authConfig),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import Layout from "../components/layout"
|
||||
import { useState, useEffect } from "react"
|
||||
import { useSession } from "next-auth/react"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
|
||||
export default function Page() {
|
||||
const { data: session } = useSession()
|
||||
const [data, setData] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
// User is logged in, let's fetch their data.
|
||||
const { supabaseAccessToken } = session
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: { Authorization: `Bearer ${supabaseAccessToken}` },
|
||||
},
|
||||
}
|
||||
)
|
||||
// Fetch data with RLS enabled.
|
||||
supabase
|
||||
.from("users")
|
||||
.select("*")
|
||||
.then(({ data }) => setData(data))
|
||||
}
|
||||
}, [session])
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Fetch Data from Supabase with RLS</h1>
|
||||
<h2>Client-side data fetching with RLS:</h2>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
<h2>API Example</h2>
|
||||
<p>
|
||||
You can also use Supabase in API routes. See the code in the
|
||||
`/pages/api/examples/supabase-rls.js` file.
|
||||
</p>
|
||||
<p>
|
||||
<em>You must be signed in to see responses.</em>
|
||||
</p>
|
||||
<p>/api/examples/supabase-rls</p>
|
||||
<iframe src="/api/examples/supabase-rls" />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
// and fetching data from Supabase with RLS enabled.
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
export default function Page({ data, session }) {
|
||||
// If no session exists, display access denied message
|
||||
if (!session) {
|
||||
return (
|
||||
<Layout>
|
||||
<AccessDenied />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// If session exists, display content
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Protected Page</h1>
|
||||
<p>Data fetched during SSR from Supabase with RSL enabled:</p>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
)
|
||||
|
||||
if (!session)
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
data: null,
|
||||
error: "No session",
|
||||
},
|
||||
}
|
||||
|
||||
const { supabaseAccessToken } = session
|
||||
|
||||
const supabase = createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
global: {
|
||||
headers: {
|
||||
Authorization: `Bearer ${supabaseAccessToken}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
// Now you can query with RLS enabled.
|
||||
const { data, error } = await supabase.from("users").select("*")
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
data,
|
||||
error,
|
||||
},
|
||||
}
|
||||
}
|
||||
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
9
apps/dev/nextjs/types/nextauth.d.ts
vendored
@@ -18,3 +18,12 @@ declare module "next-auth" {
|
||||
foo: string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
[key: string]: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
4
apps/examples/next.config.js
Normal file
4
apps/examples/next.config.js
Normal file
@@ -0,0 +1,4 @@
|
||||
/** @type {import("next").NextConfig} */
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.now.sh/32
|
||||
NEXTAUTH_SECRET= # Linux: `openssl rand -hex 32` or go to https://generate-secret.vercel.app/32
|
||||
|
||||
|
||||
AUTH0_ID=
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<a href="https://nextjs.org" target="_blank">
|
||||
<img height="64" src="https://nextjs.org/static/favicon/android-chrome-192x192.png" />
|
||||
</a>
|
||||
<h3 align="center"><b>NextAuth.js</b> - Example App</h3>
|
||||
<h3 align="center"><b>next-auth</b> - Example App</h3>
|
||||
<p align="center">
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
@@ -36,7 +36,7 @@ This is an example application that shows how `next-auth` is applied to a basic
|
||||
|
||||
The deployed version can be found at [`next-auth-example.vercel.app`](https://next-auth-example.vercel.app)
|
||||
|
||||
Go to [next-auth.js.org](https://next-auth.js.org) for more information and documentation.
|
||||
Go to [authjs.dev](https://authjs.dev) for more information and documentation.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -66,7 +66,7 @@ You **can** skip configuring a database and come back to it later if you want.
|
||||
|
||||
For more information about setting up a database, please check out the following links:
|
||||
|
||||
- Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||
- Docs: [authjs.dev/reference/adapters](https://authjs.dev/reference/adapters)
|
||||
|
||||
### 3. Configure Authentication Providers
|
||||
|
||||
@@ -76,7 +76,7 @@ For more information about setting up a database, please check out the following
|
||||
|
||||
e.g. For Google OAuth you would use: `http://localhost:3000/api/auth/callback/google`
|
||||
|
||||
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at https://next-auth.js.org/configuration/providers/oauth
|
||||
A list of configured providers and their callback URLs is available from the endpoint `/api/auth/providers`. You can find more information at [authjs.dev/getting-started/oauth-tutorial](https://authjs.dev/getting-started/oauth-tutorial)
|
||||
|
||||
3. You can also choose to specify an SMTP server for passwordless sign in via email.
|
||||
|
||||
@@ -106,4 +106,4 @@ Follow the [Deployment documentation](https://authjs.dev/guides/basics/deploymen
|
||||
<a href="https://vercel.com?utm_source=nextauthjs&utm_campaign=oss">
|
||||
<img width="170px" src="https://raw.githubusercontent.com/nextauthjs/next-auth/main/docs/static/img/powered-by-vercel.svg" alt="Powered By Vercel" />
|
||||
</a>
|
||||
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire Auth.js Team</p>
|
||||
<p align="left">Thanks to Vercel sponsoring this project by allowing it to be deployed for free for the entire Auth.js Team</p>
|
||||
|
||||
3
apps/examples/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
3
apps/examples/nextjs/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { handlers } from "auth"
|
||||
export const { GET, POST } = handlers
|
||||
export const runtime = "edge"
|
||||
10
apps/examples/nextjs/app/api/protected/route.ts
Normal file
10
apps/examples/nextjs/app/api/protected/route.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
export const GET = auth(function GET(req) {
|
||||
if (req.auth) {
|
||||
return NextResponse.json(req.auth)
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
|
||||
})
|
||||
@@ -1,15 +1,13 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function ClientPage() {
|
||||
export default function Page() {
|
||||
return (
|
||||
<Layout>
|
||||
<>
|
||||
<h1>Client Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>useSession()</strong> React Hook in the{" "}
|
||||
<strong><Header/></strong> component.
|
||||
<strong></Header></strong> component.
|
||||
</p>
|
||||
<p>
|
||||
The <strong>useSession()</strong> React Hook is easy to use and allows
|
||||
The <strong>useSession()</strong> React Hook easy to use and allows
|
||||
pages to render very quickly.
|
||||
</p>
|
||||
<p>
|
||||
@@ -22,6 +20,6 @@ export default function ClientPage() {
|
||||
The disadvantage of <strong>useSession()</strong> is that it requires
|
||||
client side JavaScript.
|
||||
</p>
|
||||
</Layout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
24
apps/examples/nextjs/app/layout.tsx
Normal file
24
apps/examples/nextjs/app/layout.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import Header from "components/header"
|
||||
import Footer from "components/footer"
|
||||
import './styles.css'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<Header />
|
||||
<main>
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
13
apps/examples/nextjs/app/page.tsx
Normal file
13
apps/examples/nextjs/app/page.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
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"
|
||||
39
apps/examples/nextjs/app/server-component/page.tsx
Normal file
39
apps/examples/nextjs/app/server-component/page.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { auth } from "auth"
|
||||
import { cookies, headers } from "next/headers"
|
||||
|
||||
function SignIn({ id, children, className }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action={`/api/auth/signin/${id}`} method="post">
|
||||
<button className={className} type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function SignOut({ children }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action="/api/auth/signout" method="post">
|
||||
<button type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default async function Page() {
|
||||
const session = await auth(headers())
|
||||
if (session) {
|
||||
return (
|
||||
<>
|
||||
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
<SignOut>Sign out</SignOut>
|
||||
</>
|
||||
)
|
||||
}
|
||||
return <SignIn id="github">Sign in with github</SignIn>
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
@@ -1,4 +1,5 @@
|
||||
body {
|
||||
color: red;
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
@@ -6,7 +7,7 @@ body {
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
li,
|
||||
21
apps/examples/nextjs/auth.ts
Normal file
21
apps/examples/nextjs/auth.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
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 styles from "./footer.module.css"
|
||||
import packageJSON from "../package.json"
|
||||
import packageJSON from "next-auth/package.json"
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
@@ -8,10 +8,10 @@ export default function Footer() {
|
||||
<hr />
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://next-auth.js.org">Documentation</a>
|
||||
<a href="https://authjs.dev">Documentation</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://www.npmjs.com/package/next-auth">NPM</a>
|
||||
<a href="https://www.npmjs.com/package/@auth/core">NPM</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||
@@ -20,7 +20,7 @@ export default function Footer() {
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
|
||||
<em>{packageJSON.version}</em>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* Set min-height to avoid page reflow while session loading */
|
||||
.signedInStatus {
|
||||
position: relative;
|
||||
display: block;
|
||||
min-height: 4rem;
|
||||
width: 100%;
|
||||
|
||||
@@ -1,65 +1,63 @@
|
||||
import Link from "next/link"
|
||||
import { signIn, signOut, useSession } from "next-auth/react"
|
||||
import { auth } from "auth"
|
||||
import { cookies, headers } from "next/headers"
|
||||
import styles from "./header.module.css"
|
||||
|
||||
// The approach used in this component shows how to build a sign in and sign out
|
||||
function SignIn({ id, children, className }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action={`/api/auth/signin/${id}`} method="post">
|
||||
<button className={className} type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
function SignOut({ children, className }: any) {
|
||||
const $cookies = cookies()
|
||||
const csrfToken = $cookies.get("next-auth.csrf-token")?.value.split("|")[0]
|
||||
return (
|
||||
<form action="/api/auth/signout" method="post">
|
||||
<button className={className} type="submit">{children}</button>
|
||||
<input type="hidden" name="csrfToken" value={csrfToken} />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
// The approach used in this component shows how to built a sign in and sign out
|
||||
// component that works on pages which support both client and server side
|
||||
// rendering, and avoids any flash incorrect content on initial page load.
|
||||
export default function Header() {
|
||||
const { data: session, status } = useSession()
|
||||
const loading = status === "loading"
|
||||
export default async function Header() {
|
||||
const session = await auth(headers())
|
||||
|
||||
return (
|
||||
<header>
|
||||
<noscript>
|
||||
<style>{`.nojs-show { opacity: 1; top: 0; }`}</style>
|
||||
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
|
||||
</noscript>
|
||||
<div className={styles.signedInStatus}>
|
||||
<p
|
||||
className={`nojs-show ${
|
||||
!session && loading ? styles.loading : styles.loaded
|
||||
}`}
|
||||
>
|
||||
<p className={`nojs-show ${styles.loaded}`}>
|
||||
{!session && (
|
||||
<>
|
||||
<span className={styles.notSignedInText}>
|
||||
You are not signed in
|
||||
</span>
|
||||
<a
|
||||
href={`/api/auth/signin`}
|
||||
className={styles.buttonPrimary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signIn()
|
||||
}}
|
||||
>
|
||||
Sign in
|
||||
</a>
|
||||
<SignIn className={styles.buttonPrimary}>Sign In</SignIn>
|
||||
</>
|
||||
)}
|
||||
{session?.user && (
|
||||
{session && (
|
||||
<>
|
||||
{session.user.image && (
|
||||
<span
|
||||
style={{ backgroundImage: `url('${session.user.image}')` }}
|
||||
className={styles.avatar}
|
||||
/>
|
||||
<img src={session.user.image} className={styles.avatar} />
|
||||
)}
|
||||
<span className={styles.signedInText}>
|
||||
<small>Signed in as</small>
|
||||
<br />
|
||||
<strong>{session.user.email ?? session.user.name}</strong>
|
||||
<strong>{session.user.email} </strong>
|
||||
{session.user.name ? `(${session.user.name})` : null}
|
||||
</span>
|
||||
<a
|
||||
href={`/api/auth/signout`}
|
||||
className={styles.button}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signOut()
|
||||
}}
|
||||
>
|
||||
Sign out
|
||||
</a>
|
||||
<SignOut className={styles.button}>Sign Out</SignOut>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
@@ -73,7 +71,7 @@ export default function Header() {
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server">Server</Link>
|
||||
<Link href="/server-component">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">Protected</Link>
|
||||
@@ -82,13 +80,12 @@ export default function Header() {
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/admin">Admin</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/me">Me</Link>
|
||||
<Link href="/middleware-protected">Middleware protected</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
export const runtime = "experimental-edge"
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import Header from "./header"
|
||||
import Footer from "./footer"
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,17 +1,10 @@
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
// export { auth as default } from "auth"
|
||||
import { auth } from "auth"
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
||||
export default withAuth({
|
||||
callbacks: {
|
||||
authorized({ req, token }) {
|
||||
// `/admin` requires admin role
|
||||
if (req.nextUrl.pathname === "/admin") {
|
||||
return token?.userRole === "admin"
|
||||
}
|
||||
// `/me` only requires the user to be logged in
|
||||
return !!token
|
||||
},
|
||||
},
|
||||
export default auth((req) => {
|
||||
if (req.auth) return NextResponse.json(req.auth)
|
||||
return NextResponse.json("Not authorized", { status: 401 })
|
||||
})
|
||||
|
||||
export const config = { matcher: ["/admin", "/me"] }
|
||||
export const config = { matcher: ["/middleware-protected"] }
|
||||
|
||||
10
apps/examples/nextjs/next-auth.d.ts
vendored
10
apps/examples/nextjs/next-auth.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
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,4 +1,9 @@
|
||||
/** @type {import("next").NextConfig} */
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
webpack(config) {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
experimental: { appDir: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "nextjs-example-app",
|
||||
"description": "An example project for NextAuth.js with Next.js",
|
||||
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
||||
"bugs": {
|
||||
@@ -18,8 +19,9 @@
|
||||
"Lluis Agusti <hi@llu.lu>"
|
||||
],
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"next": "latest",
|
||||
"next-auth": "latest",
|
||||
"next-auth": "workspace:*",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
import "./styles.css"
|
||||
|
||||
import type { AppProps } from "next/app"
|
||||
import type { Session } from "next-auth"
|
||||
|
||||
// Use of the <SessionProvider> is mandatory to allow components that call
|
||||
// `useSession()` anywhere in your application to access the `session` object.
|
||||
export default function App({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}: AppProps<{ session: Session }>) {
|
||||
return (
|
||||
<SessionProvider session={session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
)
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>This page is protected by Middleware</h1>
|
||||
<p>Only admin users can see this page.</p>
|
||||
<p>
|
||||
To learn more about the NextAuth middleware see
|
||||
<a href="https://next-auth.js.org/configuration/nextjs#middleware">
|
||||
the docs
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function ApiExamplePage() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>API Example</h1>
|
||||
<p>The examples below show responses from the example API endpoints.</p>
|
||||
<p>
|
||||
<em>You must be signed in to see responses.</em>
|
||||
</p>
|
||||
<h2>Session</h2>
|
||||
<p>/api/examples/session</p>
|
||||
<iframe src="/api/examples/session" />
|
||||
<h2>JSON Web Token</h2>
|
||||
<p>/api/examples/jwt</p>
|
||||
<iframe src="/api/examples/jwt" />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
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)
|
||||
@@ -1,14 +0,0 @@
|
||||
// This is an example of how to read a JSON Web Token from an API route
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
// If you don't have the NEXTAUTH_SECRET environment variable set,
|
||||
// you will have to pass your secret as `secret` to `getToken`
|
||||
const token = await getToken({ req })
|
||||
res.send(JSON.stringify(token, null, 2))
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// 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.",
|
||||
})
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// 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 +0,0 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function IndexPage() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>NextAuth.js Example</h1>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use{" "}
|
||||
<a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { useSession } from "next-auth/react"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function MePage() {
|
||||
const { data } = useSession()
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function PolicyPage() {
|
||||
return (
|
||||
<Layout>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use{" "}
|
||||
<a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
|
||||
</p>
|
||||
<h2>Terms of Service</h2>
|
||||
<p>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</p>
|
||||
<h2>Privacy Policy</h2>
|
||||
<p>
|
||||
This site uses JSON Web Tokens and an in-memory database which resets
|
||||
every ~2 hours.
|
||||
</p>
|
||||
<p>
|
||||
Data provided to this site is exclusively used to support signing in and
|
||||
is not passed to any third party services, other than via SMTP or OAuth
|
||||
for the purposes of authentication.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { useState, useEffect } from "react"
|
||||
import { useSession } from "next-auth/react"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
export default function ProtectedPage() {
|
||||
const { data: session } = useSession()
|
||||
const [content, setContent] = useState()
|
||||
|
||||
// Fetch content from protected route
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const res = await fetch("/api/examples/protected")
|
||||
const json = await res.json()
|
||||
if (json.content) {
|
||||
setContent(json.content)
|
||||
}
|
||||
}
|
||||
fetchData()
|
||||
}, [session])
|
||||
|
||||
// If no session exists, display access denied message
|
||||
if (!session) {
|
||||
return (
|
||||
<Layout>
|
||||
<AccessDenied />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// If session exists, display content
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Protected Page</h1>
|
||||
<p>
|
||||
<strong>{content ?? "\u00a0"}</strong>
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
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,10 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
@@ -12,15 +16,24 @@
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
"process.d.ts",
|
||||
"next-env.d.ts",
|
||||
"next-auth.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.js"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Session } from "@auth/core/types"
|
||||
import { Session } from "@auth/core"
|
||||
|
||||
export default function useSession() {
|
||||
return useState<Session | null>("session", () => null)
|
||||
|
||||
@@ -43,7 +43,7 @@ export async function signIn<
|
||||
|
||||
// TODO: Handle custom base path
|
||||
// TODO: Remove this since Sveltekit offers the CSRF protection via origin check
|
||||
const { csrfToken } = await $fetch<{ csrfToken: string }>("/api/auth/csrf")
|
||||
const { csrfToken } = await $fetch("/api/auth/csrf")
|
||||
|
||||
console.log(_signInUrl)
|
||||
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { AuthConfig, Session } from "@auth/core/types"
|
||||
import { Auth } from "@auth/core"
|
||||
import { AuthHandler, AuthOptions, Session } from "@auth/core"
|
||||
import { fromNodeMiddleware, H3Event } from "h3"
|
||||
import getURL from "requrl"
|
||||
import { createMiddleware } from "@hattip/adapter-node"
|
||||
|
||||
export function NuxtAuthHandler(options: AuthConfig) {
|
||||
export function NuxtAuthHandler(options: AuthOptions) {
|
||||
async function handler(ctx: { request: Request }) {
|
||||
options.trustHost ??= true
|
||||
|
||||
return Auth(ctx.request, options)
|
||||
return AuthHandler(ctx.request, options)
|
||||
}
|
||||
|
||||
const middleware = createMiddleware(handler)
|
||||
@@ -18,7 +17,7 @@ export function NuxtAuthHandler(options: AuthConfig) {
|
||||
|
||||
export async function getSession(
|
||||
event: H3Event,
|
||||
options: AuthConfig
|
||||
options: AuthOptions
|
||||
): Promise<Session | null> {
|
||||
options.trustHost ??= true
|
||||
|
||||
@@ -31,7 +30,7 @@ export async function getSession(
|
||||
nodeHeaders.append(key, headers[key] as any)
|
||||
})
|
||||
|
||||
const response = await Auth(
|
||||
const response = await AuthHandler(
|
||||
new Request(url, { headers: nodeHeaders }),
|
||||
options
|
||||
)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"name": "next-auth-nuxt",
|
||||
"name": "playground-nuxt",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt prepare && nuxt dev",
|
||||
"build": "nuxt prepare && nuxt build",
|
||||
"dev": "nuxt prepare && export NODE_OPTIONS='--no-experimental-fetch' && nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint-config": "^0.1.1",
|
||||
"eslint": "^8.29.0",
|
||||
"h3": "1.6.6",
|
||||
"nuxt": "3.5.1"
|
||||
"h3": "1.0.2",
|
||||
"nuxt": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"@hattip/adapter-node": "^0.0.34",
|
||||
"@hattip/adapter-node": "^0.0.22",
|
||||
"requrl": "^3.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Session } from "@auth/core/types"
|
||||
import { Session } from "@auth/core"
|
||||
|
||||
export default defineNuxtPlugin(async () => {
|
||||
const session = useSession()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { NuxtAuthHandler } from "@/lib/auth/server"
|
||||
import GithubProvider from "@auth/core/providers/github"
|
||||
import type { AuthConfig } from "@auth/core"
|
||||
import type { AuthOptions } from "@auth/core"
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
export const authOptions = {
|
||||
export const authOptions: AuthOptions = {
|
||||
secret: runtimeConfig.secret,
|
||||
providers: [
|
||||
GithubProvider({
|
||||
@@ -12,6 +12,6 @@ export const authOptions = {
|
||||
clientSecret: runtimeConfig.github.clientSecret,
|
||||
}),
|
||||
],
|
||||
} as AuthConfig
|
||||
}
|
||||
|
||||
export default NuxtAuthHandler(authOptions)
|
||||
|
||||
@@ -36,10 +36,6 @@ This tutorial assumes you have a Next.js application set up. If you don't, you c
|
||||
npm install next-auth
|
||||
```
|
||||
|
||||
:::info
|
||||
We are working on a new `@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
|
||||
|
||||
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:
|
||||
@@ -243,13 +239,10 @@ http://localhost:5173/auth/callback/github
|
||||
TODO Core
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info
|
||||
The last part of the URL, `[provider]`, is the ID of the provider you're using. In this case, we're using GitHub, so it's `github`. If you're using Google, it'll be `google`, etc... We keep track of the provider IDs internally.
|
||||
|
||||
The same id is used in the `signIn()` method we saw earlier.
|
||||
:::
|
||||
|
||||
To register, tap on "Register application" button.
|
||||
|
||||
The next screen shows all the configurations for your newly created OAuth app. For now, we need two things from it - the **Client ID** and **Client Secret**:
|
||||
@@ -273,7 +266,7 @@ Note that, for each provider, the configuration process will be similar to what
|
||||
2. Create create your OAuth application within it
|
||||
3. Set the callback URL
|
||||
4. Get the Client ID and Generate a Client Secret
|
||||
:::
|
||||
:::
|
||||
|
||||
## 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 { type TokenSet } from "@auth/core/types"
|
||||
import Google from "@auth/core/providers/google"
|
||||
import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
@@ -22,18 +22,11 @@ Next you will have to create some configuration files for Cypress.
|
||||
|
||||
First, the primary cypress config:
|
||||
|
||||
```ts title="cypress.config.ts"
|
||||
import { defineConfig } from 'cypress'
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:3000',
|
||||
chromeWebSecurity: false,
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
})
|
||||
```js title="cypress.json"
|
||||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"chromeWebSecurity": false
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -53,24 +46,14 @@ 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:
|
||||
|
||||
```js title="cypress.config.ts" {3-4,10-14}
|
||||
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,
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
```js title="cypress/plugins/index.js"
|
||||
const { GoogleSocialLogin } = require("cypress-social-logins").plugins
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on("task", {
|
||||
GoogleSocialLogin: GoogleSocialLogin,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
Finally, you can also add the following npm scripts to your `package.json`:
|
||||
@@ -127,6 +110,10 @@ describe("Login page", () => {
|
||||
secure: cookie.secure,
|
||||
})
|
||||
|
||||
Cypress.Cookies.defaults({
|
||||
preserve: cookieName,
|
||||
})
|
||||
|
||||
// remove the two lines below if you need to stay logged in
|
||||
// for your remaining tests
|
||||
cy.visit("/api/auth/signout")
|
||||
|
||||
@@ -96,13 +96,8 @@ erDiagram
|
||||
string type
|
||||
string provider
|
||||
string providerAccountId
|
||||
string refresh_token
|
||||
string access_token
|
||||
int expires_at
|
||||
string token_type
|
||||
string scope
|
||||
string id_token
|
||||
string session_state
|
||||
}
|
||||
VerificationToken {
|
||||
string identifier
|
||||
@@ -142,7 +137,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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
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).
|
||||
:::
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Next.js Auth
|
||||
---
|
||||
|
||||
:::warning WIP
|
||||
`@auth/nextjs` is work in progress. For now, please use [NextAuth.js](https://next-auth.js.org).
|
||||
:::
|
||||
@@ -38,6 +38,22 @@ 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} */
|
||||
const docusaurusConfig = {
|
||||
markdown: {
|
||||
@@ -231,36 +247,9 @@ const docusaurusConfig = {
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
"docusaurus-plugin-typedoc",
|
||||
{
|
||||
...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",
|
||||
},
|
||||
},
|
||||
],
|
||||
typedocFramework("core", ["index.ts", "adapters.ts", "errors.ts", "jwt.ts", "types.ts"]),
|
||||
typedocFramework("frameworks-sveltekit", ["lib/index.ts", "lib/client.ts"]),
|
||||
typedocFramework("next-auth", ["index.ts", "react.tsx", "jwt.ts", "adapters.ts", "next.ts", "types.ts", "middleware.ts"]),
|
||||
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
||||
? []
|
||||
: [
|
||||
@@ -273,7 +262,19 @@ const docusaurusConfig = {
|
||||
typedocAdapter("Neo4j"),
|
||||
typedocAdapter("PouchDB"),
|
||||
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("Supabase"),
|
||||
typedocAdapter("Upstash Redis"),
|
||||
|
||||
@@ -35,16 +35,9 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
label: "@auth/nextjs",
|
||||
link: { type: "doc", id: "reference/nextjs/index" },
|
||||
items: [
|
||||
"reference/nextjs/client",
|
||||
{
|
||||
type: "link",
|
||||
label: "NextAuth.js (next-auth)",
|
||||
href: "https://next-auth.js.org",
|
||||
},
|
||||
],
|
||||
label: "next-auth",
|
||||
link: { type: "doc", id: "reference/next-auth/index" },
|
||||
items: [{ type: "autogenerated", dirName: "reference/next-auth" }],
|
||||
},
|
||||
...(process.env.TYPEDOC_SKIP_ADAPTERS
|
||||
? []
|
||||
|
||||
@@ -29,7 +29,6 @@ html[data-theme="dark"] .adapter-card {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
html[data-theme="dark"] .adapter-card:hover,
|
||||
.adapter-card:hover {
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
|
||||
13
package.json
13
package.json
@@ -9,6 +9,7 @@
|
||||
"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-*",
|
||||
"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": "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...",
|
||||
@@ -28,7 +29,7 @@
|
||||
"@actions/core": "^1.10.0",
|
||||
"@balazsorban/monorepo-release": "0.1.8",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/node": "^17.0.25",
|
||||
"@types/node": "^18.15.11",
|
||||
"@typescript-eslint/eslint-plugin": "5.47.0",
|
||||
"@typescript-eslint/parser": "5.47.0",
|
||||
"eslint": "8.30.0",
|
||||
@@ -43,7 +44,7 @@
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"prettier": "2.8.1",
|
||||
"prettier-plugin-svelte": "^2.8.1",
|
||||
"turbo": "1.10.1",
|
||||
"turbo": "1.8.8",
|
||||
"typescript": "4.9.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -96,8 +97,6 @@
|
||||
"packages/core/src/lib/pages/styles.ts",
|
||||
"packages/frameworks-sveltekit/package",
|
||||
"packages/frameworks-sveltekit/vite.config.{js,ts}.timestamp-*",
|
||||
"packages/next-auth/src/providers/oauth-types.ts",
|
||||
"packages/next-auth/css/index.css",
|
||||
".branches",
|
||||
"db.sqlite",
|
||||
"dev.db",
|
||||
@@ -248,8 +247,10 @@
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"apps/dev/nextjs/pages/api/auth/[...nextauth].ts",
|
||||
"docs/{sidebars,docusaurus.config}.js"
|
||||
"apps/dev/nextjs/pages/api/auth-old/[...nextauth].ts",
|
||||
"apps/dev/nextjs/app/api/auth/[...nextauth]/route.ts",
|
||||
"docs/{sidebars,docusaurus.config}.js",
|
||||
"packages/next-auth/src/lib/env.ts"
|
||||
],
|
||||
"options": {
|
||||
"printWidth": 150
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>Prisma Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@auth/prisma-adapter">
|
||||
<a href="https://npm.im/@next-auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@auth/prisma-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/prisma-adapter?color=green&label=@auth/prisma-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@next-auth/prisma-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/prisma-adapter?color=green&label=@next-auth/prisma-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/prisma-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@next-auth/prisma-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/prisma-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||
|
||||
@@ -1,29 +1,14 @@
|
||||
{
|
||||
"name": "@auth/prisma-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "Prisma adapter for Auth.js",
|
||||
"homepage": "https://authjs.dev/reference/adapter/prisma",
|
||||
"name": "@next-auth/prisma-adapter",
|
||||
"version": "1.0.6",
|
||||
"description": "Prisma adapter for next-auth.",
|
||||
"homepage": "https://authjs.dev",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "William Luke",
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -47,19 +32,22 @@
|
||||
"dev": "prisma generate && tsc -w",
|
||||
"studio": "prisma studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@prisma/client": ">=2.26.0 || >=3 || >=4"
|
||||
"@prisma/client": ">=2.26.0 || >=3",
|
||||
"next-auth": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"@prisma/client": "^4.15.0",
|
||||
"@prisma/client": "^3.10.0",
|
||||
"jest": "^27.4.3",
|
||||
"mongodb": "^4.4.0",
|
||||
"prisma": "^4.15.0"
|
||||
"next-auth": "workspace:*",
|
||||
"prisma": "^3.10.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install @prisma/client @auth/prisma-adapter
|
||||
* npm install next-auth @prisma/client @next-auth/prisma-adapter
|
||||
* npm install prisma --save-dev
|
||||
* ```
|
||||
*
|
||||
* @module @auth/prisma-adapter
|
||||
* @module @next-auth/prisma-adapter
|
||||
*/
|
||||
import type { PrismaClient, Prisma } from "@prisma/client"
|
||||
import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
import type { Adapter, AdapterAccount } from "next-auth/adapters"
|
||||
|
||||
/**
|
||||
* ## Setup
|
||||
@@ -26,7 +26,7 @@ import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
* ```js title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import GoogleProvider from "next-auth/providers/google"
|
||||
* import { PrismaAdapter } from "@auth/prisma-adapter"
|
||||
* import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
* import { PrismaClient } from "@prisma/client"
|
||||
*
|
||||
* const prisma = new PrismaClient()
|
||||
@@ -42,6 +42,8 @@ import type { Adapter, AdapterAccount } from "@auth/core/adapters"
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* ## Advanced usage
|
||||
*
|
||||
* ### Create the Prisma schema from scratch
|
||||
*
|
||||
* You need to use at least Prisma 2.26.0. Create a schema file in `prisma/schema.prisma` similar to this one:
|
||||
|
||||
@@ -1,25 +1,9 @@
|
||||
{
|
||||
"extends": "@next-auth/tsconfig/tsconfig.base.json",
|
||||
"extends": "@next-auth/tsconfig/tsconfig.adapters.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": ".",
|
||||
"isolatedModules": true,
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"outDir": ".",
|
||||
"rootDir": "src",
|
||||
"skipDefaultLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"stripInternal": true,
|
||||
"declarationMap": true,
|
||||
"declaration": true
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"*.js",
|
||||
"*.d.ts",
|
||||
]
|
||||
}
|
||||
"include": ["."],
|
||||
"exclude": ["tests", "dist", "jest.config.js"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Adapter } from "@auth/core/adapters"
|
||||
import type { Adapter } from "next-auth/adapters"
|
||||
import { createHash, randomUUID } from "crypto"
|
||||
|
||||
const requiredMethods = [
|
||||
@@ -58,8 +58,7 @@ export async function runBasicTests(options: TestOptions) {
|
||||
await options.db.connect?.()
|
||||
})
|
||||
|
||||
const { adapter: _adapter, db, skipTests } = options
|
||||
const adapter = _adapter as Required<Adapter>
|
||||
const { adapter, db, skipTests } = options
|
||||
|
||||
afterAll(async () => {
|
||||
// @ts-expect-error This is only used for the TypeORM adapter
|
||||
@@ -89,7 +88,7 @@ export async function runBasicTests(options: TestOptions) {
|
||||
providerAccountId: randomUUID(),
|
||||
type: "oauth",
|
||||
access_token: randomUUID(),
|
||||
expires_at: ONE_MONTH / 1000,
|
||||
expires_at: ONE_MONTH,
|
||||
id_token: randomUUID(),
|
||||
refresh_token: randomUUID(),
|
||||
token_type: "bearer",
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
"license": "ISC",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@auth/core": "workspace:*",
|
||||
"@babel/cli": "^7.14.3",
|
||||
"@babel/plugin-transform-runtime": "^7.14.3",
|
||||
"@babel/preset-env": "^7.14.2",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"jest": "^27.0.3",
|
||||
"next-auth": "workspace:*",
|
||||
"ts-jest": "^27.0.3",
|
||||
"typescript": "^4.2.4"
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
</a>
|
||||
<h3 align="center"><b>TypeORM Adapter</b> - NextAuth.js / Auth.js</a></h3>
|
||||
<p align="center" style="align: center;">
|
||||
<a href="https://npm.im/@auth/typeorm-adapter">
|
||||
<a href="https://npm.im/@next-auth/typeorm-legacy-adapter">
|
||||
<img src="https://img.shields.io/badge/TypeScript-blue?style=flat-square" alt="TypeScript" />
|
||||
</a>
|
||||
<a href="https://npm.im/@auth/typeorm-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@auth/typeorm-adapter?color=green&label=@auth/typeorm-adapter&style=flat-square">
|
||||
<a href="https://npm.im/@next-auth/typeorm-legacy-adapter">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/@next-auth/typeorm-legacy-adapter?color=green&label=@next-auth/typeorm-legacy-adapter&style=flat-square">
|
||||
</a>
|
||||
<a href="https://www.npmtrends.com/@auth/typeorm-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@auth/typeorm-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
<a href="https://www.npmtrends.com/@next-auth/typeorm-legacy-adapter">
|
||||
<img src="https://img.shields.io/npm/dm/@next-auth/typeorm-legacy-adapter?label=%20downloads&style=flat-square" alt="Downloads" />
|
||||
</a>
|
||||
<a href="https://github.com/nextauthjs/next-auth/stargazers">
|
||||
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth?style=flat-square" alt="Github Stars" />
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "@auth/typeorm-adapter",
|
||||
"version": "1.0.0",
|
||||
"description": "TypeORM adapter for Auth.js.",
|
||||
"homepage": "https://authjs.dev/reference/adapter/typeorm",
|
||||
"name": "@next-auth/typeorm-legacy-adapter",
|
||||
"version": "2.0.2",
|
||||
"description": "TypeORM (legacy) adapter for next-auth.",
|
||||
"homepage": "https://authjs.dev",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
@@ -11,19 +11,11 @@
|
||||
"contributors": [
|
||||
"Balázs Orbán <info@balazsorban.com>"
|
||||
],
|
||||
"type": "module",
|
||||
"types": "./index.d.ts",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.d.ts*",
|
||||
"src"
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./index.d.ts",
|
||||
"import": "./index.js"
|
||||
}
|
||||
},
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
@@ -46,27 +38,26 @@
|
||||
"test:containers": "tests/test.sh",
|
||||
"test": "tests/test.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth/core": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:*",
|
||||
"@next-auth/tsconfig": "workspace:*",
|
||||
"jest": "^27.4.3",
|
||||
"mssql": "^7.2.1",
|
||||
"mysql": "^2.18.1",
|
||||
"next-auth": "workspace:*",
|
||||
"pg": "^8.7.3",
|
||||
"sqlite3": "^5.0.8",
|
||||
"typeorm": "0.3.15",
|
||||
"typeorm": "0.3.7",
|
||||
"typeorm-naming-strategies": "^4.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mssql": "^6.2.1 || 7",
|
||||
"mysql": "^2.18.1",
|
||||
"next-auth": "^4",
|
||||
"pg": "^8.2.1",
|
||||
"sqlite3": "^5.0.2",
|
||||
"typeorm": "^0.3.7"
|
||||
"typeorm": "0.3.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"mysql": {
|
||||
@@ -9,17 +9,17 @@
|
||||
* ## Installation
|
||||
*
|
||||
* ```bash npm2yarn2pnpm
|
||||
* npm install @auth/typeorm-adapter typeorm
|
||||
* npm install next-auth @next-auth/typeorm-legacy-adapter typeorm
|
||||
* ```
|
||||
*
|
||||
* @module @auth/typeorm-adapter
|
||||
* @module @next-auth/typeorm-legacy-adapter
|
||||
*/
|
||||
import type {
|
||||
Adapter,
|
||||
AdapterUser,
|
||||
AdapterAccount,
|
||||
AdapterSession,
|
||||
} from "@auth/core/adapters"
|
||||
} from "next-auth/adapters"
|
||||
import { DataSourceOptions, DataSource, EntityManager } from "typeorm"
|
||||
import * as defaultEntities from "./entities"
|
||||
import { parseDataSourceConfig, updateConnectionEntities } from "./utils"
|
||||
@@ -29,7 +29,7 @@ export const entities = defaultEntities
|
||||
export type Entities = typeof entities
|
||||
|
||||
/** This is the interface for the TypeORM adapter options. */
|
||||
export interface TypeORMAdapterOptions {
|
||||
export interface TypeORMLegacyAdapterOptions {
|
||||
/**
|
||||
* The {@link https://orkhan.gitbook.io/typeorm/docs/entities TypeORM entities} to create the database tables from.
|
||||
*/
|
||||
@@ -70,16 +70,16 @@ export async function getManager(options: {
|
||||
*
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
* import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
*
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: TypeORMAdapter("yourconnectionstring"),
|
||||
* adapter: TypeORMLegacyAdapter("yourconnectionstring"),
|
||||
* ...
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* `TypeORMAdapter` takes either a connection string, or a [`ConnectionOptions`](https://github.com/typeorm/typeorm/blob/master/docs/connection-options.md) object as its first parameter.
|
||||
* `TypeORMLegacyAdapter` takes either a connection string, or a [`ConnectionOptions`](https://github.com/typeorm/typeorm/blob/master/docs/connection-options.md) object as its first parameter.
|
||||
*
|
||||
* ## Advanced usage
|
||||
*
|
||||
@@ -93,7 +93,7 @@ export async function getManager(options: {
|
||||
*
|
||||
* 1. Create a file containing your modified entities:
|
||||
*
|
||||
* (The file below is based on the [default entities](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-typeorm/src/entities.ts))
|
||||
* (The file below is based on the [default entities](https://github.com/nextauthjs/next-auth/blob/main/packages/adapter-typeorm-legacy/src/entities.ts))
|
||||
*
|
||||
* ```diff title="lib/entities.ts"
|
||||
* import {
|
||||
@@ -231,15 +231,15 @@ export async function getManager(options: {
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* 2. Pass them to `TypeORMAdapter`
|
||||
* 2. Pass them to `TypeORMLegacyAdapter`
|
||||
*
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
* import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
* import * as entities from "lib/entities"
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: TypeORMAdapter("yourconnectionstring", { entities }),
|
||||
* adapter: TypeORMLegacyAdapter("yourconnectionstring", { entities }),
|
||||
* ...
|
||||
* })
|
||||
* ```
|
||||
@@ -260,7 +260,7 @@ export async function getManager(options: {
|
||||
*
|
||||
* ```javascript title="pages/api/auth/[...nextauth].js"
|
||||
* import NextAuth from "next-auth"
|
||||
* import { TypeORMAdapter } from "@auth/typeorm-adapter"
|
||||
* import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
* import { SnakeNamingStrategy } from 'typeorm-naming-strategies'
|
||||
* import { ConnectionOptions } from "typeorm"
|
||||
*
|
||||
@@ -275,14 +275,14 @@ export async function getManager(options: {
|
||||
* }
|
||||
*
|
||||
* export default NextAuth({
|
||||
* adapter: TypeORMAdapter(connection),
|
||||
* adapter: TypeORMLegacyAdapter(connection),
|
||||
* ...
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function TypeORMAdapter(
|
||||
export function TypeORMLegacyAdapter(
|
||||
dataSource: string | DataSourceOptions,
|
||||
options?: TypeORMAdapterOptions
|
||||
options?: TypeORMLegacyAdapterOptions
|
||||
): Adapter {
|
||||
const entities = options?.entities
|
||||
const c = {
|
||||
@@ -328,10 +328,8 @@ export function TypeORMAdapter(
|
||||
},
|
||||
async getUserByAccount(provider_providerAccountId) {
|
||||
const m = await getManager(c)
|
||||
// @ts-expect-error
|
||||
const account = await m.findOne<AdapterAccount & { user: AdapterUser }>(
|
||||
"AccountEntity",
|
||||
// @ts-expect-error
|
||||
{ where: provider_providerAccountId, relations: ["user"] }
|
||||
)
|
||||
if (!account) return null
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import * as entities from "../custom-entities"
|
||||
import { db } from "../helpers"
|
||||
import { SnakeNamingStrategy } from "typeorm-naming-strategies"
|
||||
@@ -18,7 +18,7 @@ const mysqlConfig: ConnectionOptions = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMAdapter(mysqlConfig, {
|
||||
adapter: TypeORMLegacyAdapter(mysqlConfig, {
|
||||
entities,
|
||||
}),
|
||||
db: db(mysqlConfig, entities),
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { db } from "../helpers"
|
||||
|
||||
const mysqlConfig = {
|
||||
@@ -13,6 +13,6 @@ const mysqlConfig = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMAdapter(mysqlConfig),
|
||||
adapter: TypeORMLegacyAdapter(mysqlConfig),
|
||||
db: db(mysqlConfig),
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import * as entities from "../custom-entities"
|
||||
import { db } from "../helpers"
|
||||
|
||||
@@ -7,7 +7,7 @@ const postgresConfig =
|
||||
"postgres://nextauth:password@localhost:5432/nextauth?synchronize=true"
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMAdapter(postgresConfig, {
|
||||
adapter: TypeORMLegacyAdapter(postgresConfig, {
|
||||
entities,
|
||||
}),
|
||||
db: db(postgresConfig, entities),
|
||||
@@ -1,11 +1,11 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import { db } from "../helpers"
|
||||
|
||||
const postgresConfig =
|
||||
"postgres://nextauth:password@localhost:5432/nextauth?synchronize=true"
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMAdapter(postgresConfig),
|
||||
adapter: TypeORMLegacyAdapter(postgresConfig),
|
||||
db: db(postgresConfig),
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { runBasicTests } from "../../../adapter-test"
|
||||
import { TypeORMAdapter } from "../../src"
|
||||
import { TypeORMLegacyAdapter } from "../../src"
|
||||
import * as entities from "../custom-entities"
|
||||
import { db } from "../helpers"
|
||||
|
||||
@@ -11,7 +11,7 @@ const sqliteConfig = {
|
||||
}
|
||||
|
||||
runBasicTests({
|
||||
adapter: TypeORMAdapter(sqliteConfig, {
|
||||
adapter: TypeORMLegacyAdapter(sqliteConfig, {
|
||||
entities,
|
||||
}),
|
||||
db: db(sqliteConfig, entities),
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user