mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
101 Commits
@next-auth
...
@auth/svel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25388de027 | ||
|
|
ad77e1c2b7 | ||
|
|
cd654c3001 | ||
|
|
6f9ca4143d | ||
|
|
e97b27414a | ||
|
|
9018939ee7 | ||
|
|
c2fc41b44d | ||
|
|
01d7eb4feb | ||
|
|
2388c20cc6 | ||
|
|
9a1bef9e72 | ||
|
|
35a72d2273 | ||
|
|
5f1b75a7a2 | ||
|
|
fa58065951 | ||
|
|
b31f2af66c | ||
|
|
71bb6f2590 | ||
|
|
6c07331cc5 | ||
|
|
c8ef94b2be | ||
|
|
75a59fbd92 | ||
|
|
3dd47b0735 | ||
|
|
4dc1d421f8 | ||
|
|
99ca67f1cf | ||
|
|
a087df8494 | ||
|
|
1aa4994de6 | ||
|
|
88023f69b9 | ||
|
|
b02057a72d | ||
|
|
400da8c766 | ||
|
|
b48104801b | ||
|
|
ccbbc800d2 | ||
|
|
d7888263ca | ||
|
|
47d3151410 | ||
|
|
7d264860ab | ||
|
|
6184b936f5 | ||
|
|
1954258a0a | ||
|
|
c580f0db22 | ||
|
|
d1cf701ed9 | ||
|
|
69398e2d3a | ||
|
|
856b5c50fc | ||
|
|
2830b7de5b | ||
|
|
40a0faa586 | ||
|
|
a6b4d958ac | ||
|
|
cc13df9d51 | ||
|
|
06b8d4772c | ||
|
|
d644d1fcbf | ||
|
|
380f2de961 | ||
|
|
dc5f3e1873 | ||
|
|
93f3fcd1b7 | ||
|
|
1d9b9ba47c | ||
|
|
8f6108f230 | ||
|
|
15943d6696 | ||
|
|
81589bf738 | ||
|
|
09402bf2fc | ||
|
|
e39a968a7b | ||
|
|
b03378be7f | ||
|
|
af415e9438 | ||
|
|
90eeeeab2f | ||
|
|
f0b475fc72 | ||
|
|
f4f8c4a0b3 | ||
|
|
6f2cb460c9 | ||
|
|
46f285f6f0 | ||
|
|
6bdb8af78d | ||
|
|
04e0637fd8 | ||
|
|
b5712448a1 | ||
|
|
605d15c3cc | ||
|
|
d1479125cb | ||
|
|
2e09bc0d19 | ||
|
|
843fc6ff8f | ||
|
|
6695ff8503 | ||
|
|
80c1f375b8 | ||
|
|
5a13288d47 | ||
|
|
26201e6271 | ||
|
|
d0d7b90ba1 | ||
|
|
874624dfbe | ||
|
|
4b5cd08800 | ||
|
|
1c104afef9 | ||
|
|
ff5b8ba8e2 | ||
|
|
42d5899efd | ||
|
|
b278975c3f | ||
|
|
997e595b5b | ||
|
|
527c25b128 | ||
|
|
0e2bbda537 | ||
|
|
7f3b35593f | ||
|
|
bce6b00c43 | ||
|
|
1bbd5d51d1 | ||
|
|
b24b02fe71 | ||
|
|
2c5c4d18c4 | ||
|
|
e3f9b398f0 | ||
|
|
ab13930020 | ||
|
|
f6bb16b264 | ||
|
|
a220245d03 | ||
|
|
7462e797de | ||
|
|
36286b1fae | ||
|
|
2e8e90a9be | ||
|
|
d06a552bf6 | ||
|
|
5cb8dd5f37 | ||
|
|
7c1a3b547e | ||
|
|
2534ae8801 | ||
|
|
14a120277b | ||
|
|
c49f484743 | ||
|
|
676b39d5b1 | ||
|
|
e27dbcab2f | ||
|
|
63805c7d75 |
@@ -1,70 +0,0 @@
|
||||
.eslintrc.js
|
||||
.cache-loader
|
||||
.DS_Store
|
||||
.pnpm-debug.log
|
||||
.turbo
|
||||
.vscode/generated*
|
||||
/_work
|
||||
/actions-runner
|
||||
node_modules
|
||||
patches
|
||||
pnpm-lock.yaml
|
||||
.github/actions/issue-validator/index.mjs
|
||||
*.cjs
|
||||
*.js
|
||||
*.d.ts
|
||||
*.d.ts.map
|
||||
|
||||
.svelte-kit
|
||||
.next
|
||||
.nuxt
|
||||
|
||||
# --------------- Docs ---------------
|
||||
|
||||
.docusaurus
|
||||
build
|
||||
docs/docs/reference/core
|
||||
docs/docs/reference/sveltekit
|
||||
static
|
||||
|
||||
# --------------- Packages ---------------
|
||||
|
||||
coverage
|
||||
dist
|
||||
|
||||
# @auth/core
|
||||
packages/core/src/providers/oauth-types.ts
|
||||
packages/core/src/lib/pages/styles.ts
|
||||
|
||||
# @auth/sveltekit
|
||||
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
|
||||
db.sqlite
|
||||
dev.db
|
||||
dynamodblocal-bin
|
||||
firebase-debug.log
|
||||
firestore-debug.log
|
||||
migrations
|
||||
test.schema.gql
|
||||
|
||||
# --------------- Apps ---------------
|
||||
|
||||
|
||||
# Examples should have their own Prettier config since they are templates too
|
||||
apps/example-sveltekit
|
||||
|
||||
# Development app
|
||||
apps
|
||||
|
||||
|
||||
# --------------- Tests ---------------
|
||||
# TODO: these should be linted
|
||||
packages/**/*test*
|
||||
75
.eslintrc.js
75
.eslintrc.js
@@ -1,75 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
/** @type {import("eslint").ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
env: { browser: true, es2022: true, node: true },
|
||||
extends: ["eslint:recommended", "prettier"],
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.ts", "*.tsx"],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: ["./packages/**/tsconfig.json", "./apps/**/tsconfig.json"],
|
||||
},
|
||||
settings: { react: { version: "18" } },
|
||||
extends: [
|
||||
"plugin:react/recommended",
|
||||
"plugin:react/jsx-runtime",
|
||||
"standard-with-typescript",
|
||||
"prettier",
|
||||
],
|
||||
rules: {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/method-signature-style": "off",
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"react/prop-types": "off",
|
||||
"react/no-unescaped-entities": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["*.test.ts", "*.test.js"],
|
||||
extends: ["plugin:jest/recommended"],
|
||||
env: { jest: true },
|
||||
},
|
||||
{
|
||||
files: ["docs/**"],
|
||||
plugins: ["@docusaurus"],
|
||||
extends: ["plugin:@docusaurus/recommended"],
|
||||
},
|
||||
{
|
||||
// TODO: Expand to all packages
|
||||
files: ["packages/{core,sveltekit}/*.ts"],
|
||||
plugins: ["jsdoc"],
|
||||
extends: ["plugin:jsdoc/recommended"],
|
||||
rules: {
|
||||
"jsdoc/require-param": "off",
|
||||
"jsdoc/require-returns": "off",
|
||||
"jsdoc/require-jsdoc": [
|
||||
"warn",
|
||||
{ publicOnly: true, enableFixer: false },
|
||||
],
|
||||
"jsdoc/no-multi-asterisks": ["warn", { allowWhitespace: true }],
|
||||
"jsdoc/tag-lines": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["packages/frameworks-sveltekit"],
|
||||
plugins: ["svelte3"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
settings: {
|
||||
"svelte3/typescript": () => require("typescript"),
|
||||
},
|
||||
parserOptions: { sourceType: "module", ecmaVersion: 2020 },
|
||||
env: { browser: true, es2017: true, node: true },
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: "latest",
|
||||
ecmaFeatures: { jsx: true },
|
||||
},
|
||||
root: true,
|
||||
}
|
||||
4
.github/actions/issue-validator/repro.md
vendored
4
.github/actions/issue-validator/repro.md
vendored
@@ -14,9 +14,9 @@ Ensure the link is pointing to a codebase that is accessible (e.g. not a private
|
||||
|
||||
### **What happens if I don't provide a sufficient minimal reproduction?**
|
||||
|
||||
Issues with the `incomplete` label that receives no meaningful activity (e.g. new comments with a reproduction link) are automatically closed and locked after 30 days.
|
||||
Issues with the `incomplete` label that receives no meaningful activity (e.g. new comments with a reproduction link) are closed after 7 days.
|
||||
|
||||
If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction.
|
||||
If your issue has _not_ been resolved in that time and it has been closed/locked, please open a new issue with the required reproduction. (It's less likely that we check back on already closed issues.)
|
||||
|
||||
### **I did not open this issue, but it is relevant to me, what can I do to help?**
|
||||
|
||||
|
||||
2
.github/workflows/issue-validator.yml
vendored
2
.github/workflows/issue-validator.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: "Run issue validator"
|
||||
- name: Run issue validator
|
||||
run: node /home/runner/work/next-auth/next-auth/.github/actions/issue-validator/index.mjs
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
11
.github/workflows/release.yml
vendored
11
.github/workflows/release.yml
vendored
@@ -3,10 +3,10 @@ name: Release
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "beta"
|
||||
- "next"
|
||||
- "3.x"
|
||||
- main
|
||||
- beta
|
||||
- next
|
||||
- 3.x
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
@@ -24,7 +24,6 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Run tests
|
||||
@@ -74,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
|
||||
@@ -99,7 +97,6 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Determine version
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,5 @@
|
||||
# Misc
|
||||
.DS_Store
|
||||
.npmrc
|
||||
.eslintcache
|
||||
.env
|
||||
.env.local
|
||||
@@ -14,7 +13,7 @@ yarn-error.log*
|
||||
firebase-debug.log
|
||||
ui-debug.log
|
||||
.pnpm-debug.log
|
||||
|
||||
.husky
|
||||
|
||||
# Dependencies
|
||||
node_modules
|
||||
@@ -44,6 +43,7 @@ packages/*/*.d.ts.map
|
||||
apps/dev/src/css
|
||||
apps/dev/prisma/migrations
|
||||
apps/dev/typeorm
|
||||
apps/dev/nextjs-2
|
||||
|
||||
# VS
|
||||
/.vs/slnx.sqlite-journal
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
/** @type {import("prettier").Config} */
|
||||
module.exports = {
|
||||
semi: false,
|
||||
singleQuote: false,
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
"apps/dev/nextjs/pages/api/auth/[...nextauth].ts",
|
||||
"docs/{sidebars,docusaurus.config}.js",
|
||||
],
|
||||
options: { printWidth: 150 },
|
||||
},
|
||||
{
|
||||
files: ["**/*package.json"],
|
||||
options: {
|
||||
trailingComma: "none",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
58
apps/dev/nextjs-v4/.env.local.example
Normal file
58
apps/dev/nextjs-v4/.env.local.example
Normal file
@@ -0,0 +1,58 @@
|
||||
# Rename file to .env.local (or .env) and populate values
|
||||
# to be able to run the dev app
|
||||
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
|
||||
# You can use `openssl rand -hex 32` or
|
||||
# https://generate-secret.vercel.app/32 to generate a secret.
|
||||
# Note: Changing a secret may invalidate existing sessions
|
||||
# and/or verification tokens.
|
||||
NEXTAUTH_SECRET=secret
|
||||
|
||||
AUTH0_ID=
|
||||
AUTH0_SECRET=
|
||||
AUTH0_ISSUER=
|
||||
|
||||
KEYCLOAK_ID=
|
||||
KEYCLOAK_SECRET=
|
||||
KEYCLOAK_ISSUER=
|
||||
|
||||
IDS4_ID=
|
||||
IDS4_SECRET=
|
||||
IDS4_ISSUER=
|
||||
|
||||
GITHUB_ID=
|
||||
GITHUB_SECRET=
|
||||
|
||||
TWITCH_ID=
|
||||
TWITCH_SECRET=
|
||||
|
||||
TWITTER_ID=
|
||||
TWITTER_SECRET=
|
||||
|
||||
LINE_ID=
|
||||
LINE_SECRET=
|
||||
|
||||
TRAKT_ID=
|
||||
TRAKT_SECRET=
|
||||
|
||||
# Example configuration for a Gmail account (will need SMTP enabled)
|
||||
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
|
||||
EMAIL_FROM=user@gmail.com
|
||||
|
||||
# Note: If using with Prisma adapter, you need to use a `.env`
|
||||
# file rather than a `.env.local` file to configure env vars.
|
||||
# Postgres: DATABASE_URL=postgres://nextauth:password@127.0.0.1:5432/nextauth?synchronize=true
|
||||
# MySQL: DATABASE_URL=mysql://nextauth:password@127.0.0.1:3306/nextauth?synchronize=true
|
||||
# MongoDB: DATABASE_URL=mongodb://nextauth:password@127.0.0.1:27017/nextauth?synchronize=true
|
||||
DATABASE_URL=
|
||||
|
||||
WIKIMEDIA_ID=
|
||||
WIKIMEDIA_SECRET=
|
||||
|
||||
# Supabase Example Configuration
|
||||
# Supabase Example Configuration
|
||||
# NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
||||
# SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSJ9.vI9obAHOGyVVKa3pD--kJlyxp-Z2zV9UUMAhKpNLAcU
|
||||
# SUPABASE_JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long
|
||||
# NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs
|
||||
4
apps/dev/nextjs-v4/.vscode/settings.json
vendored
Normal file
4
apps/dev/nextjs-v4/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"typescript.tsdk": "../../node_modules/.pnpm/typescript@4.8.4/node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true
|
||||
}
|
||||
6
apps/dev/nextjs-v4/README.md
Normal file
6
apps/dev/nextjs-v4/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# NextAuth.js Development App
|
||||
|
||||
This folder contains a Next.js app using NextAuth.js for local development. See the following section on how to start:
|
||||
|
||||
[Setting up local environment
|
||||
](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md#setting-up-local-environment)
|
||||
14
apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts
Normal file
14
apps/dev/nextjs-v4/app/api/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import NextAuth, { type NextAuthOptions } from "next-auth"
|
||||
import GitHub from "next-auth/providers/github"
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
GitHub({
|
||||
clientId: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
const handler = NextAuth(authOptions)
|
||||
export { handler as GET, handler as POST }
|
||||
12
apps/dev/nextjs-v4/app/layout.tsx
Normal file
12
apps/dev/nextjs-v4/app/layout.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html>
|
||||
<head></head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
6
apps/dev/nextjs-v4/app/server-component/page.tsx
Normal file
6
apps/dev/nextjs-v4/app/server-component/page.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { getServerSession } from "next-auth/next"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
}
|
||||
20
apps/dev/nextjs-v4/components/access-denied.js
Normal file
20
apps/dev/nextjs-v4/components/access-denied.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { signIn } from "next-auth/react"
|
||||
|
||||
export default function AccessDenied() {
|
||||
return (
|
||||
<>
|
||||
<h1>Access Denied</h1>
|
||||
<p>
|
||||
<a
|
||||
href="/api/auth/signin"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signIn()
|
||||
}}
|
||||
>
|
||||
You must be signed in to view this page
|
||||
</a>
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
28
apps/dev/nextjs-v4/components/footer.js
Normal file
28
apps/dev/nextjs-v4/components/footer.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import Link from "next/link"
|
||||
import styles from "./footer.module.css"
|
||||
import packageJSON from "package.json"
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className={styles.footer}>
|
||||
<hr />
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://next-auth.js.org">Documentation</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://www.npmjs.com/package/next-auth">NPM</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>{packageJSON.version}</em>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
14
apps/dev/nextjs-v4/components/footer.module.css
Normal file
14
apps/dev/nextjs-v4/components/footer.module.css
Normal file
@@ -0,0 +1,14 @@
|
||||
.footer {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.navItems {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.navItem {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
103
apps/dev/nextjs-v4/components/header.js
Normal file
103
apps/dev/nextjs-v4/components/header.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import Link from "next/link"
|
||||
import { signIn, signOut, useSession } from "next-auth/react"
|
||||
import styles from "./header.module.css"
|
||||
|
||||
// The approach used in this component shows how to built a sign in and sign out
|
||||
// component that works on pages which support both client and server side
|
||||
// rendering, and avoids any flash incorrect content on initial page load.
|
||||
export default function Header() {
|
||||
const { data: session, status } = useSession()
|
||||
|
||||
return (
|
||||
<header>
|
||||
<noscript>
|
||||
<style>{".nojs-show { opacity: 1; top: 0; }"}</style>
|
||||
</noscript>
|
||||
<div className={styles.signedInStatus}>
|
||||
<p
|
||||
className={`nojs-show ${
|
||||
!session && status === "loading" ? styles.loading : styles.loaded
|
||||
}`}
|
||||
>
|
||||
{!session && (
|
||||
<>
|
||||
<span className={styles.notSignedInText}>
|
||||
You are not signed in
|
||||
</span>
|
||||
<a
|
||||
href="/api/auth/signin"
|
||||
className={styles.buttonPrimary}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signIn()
|
||||
}}
|
||||
>
|
||||
Sign in
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
{session && (
|
||||
<>
|
||||
{session.user.image && (
|
||||
<img src={session.user.image} className={styles.avatar} />
|
||||
)}
|
||||
<span className={styles.signedInText}>
|
||||
<small>Signed in as</small>
|
||||
<br />
|
||||
<strong>{session.user.email} </strong>
|
||||
{session.user.name ? `(${session.user.name})` : null}
|
||||
</span>
|
||||
<a
|
||||
href="/api/auth/signout"
|
||||
className={styles.button}
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
signOut()
|
||||
}}
|
||||
>
|
||||
Sign out
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<nav>
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/">Home</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">Protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected-ssr">Protected(SSR)</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/credentials">Credentials</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/email">Email</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/middleware-protected">Middleware protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/supabase-client-rls">Supabase RLS</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/supabase-ssr">Supabase RLS(SSR)</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
92
apps/dev/nextjs-v4/components/header.module.css
Normal file
92
apps/dev/nextjs-v4/components/header.module.css
Normal file
@@ -0,0 +1,92 @@
|
||||
/* Set min-height to avoid page reflow while session loading */
|
||||
.signedInStatus {
|
||||
display: block;
|
||||
min-height: 4rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.loaded {
|
||||
position: relative;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
overflow: hidden;
|
||||
border-radius: 0 0 .6rem .6rem;
|
||||
padding: .6rem 1rem;
|
||||
margin: 0;
|
||||
background-color: rgba(0,0,0,.05);
|
||||
transition: all 0.2s ease-in;
|
||||
}
|
||||
|
||||
.loading {
|
||||
top: -2rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.signedInText,
|
||||
.notSignedInText {
|
||||
position: absolute;
|
||||
padding-top: .8rem;
|
||||
left: 1rem;
|
||||
right: 6.5rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
display: inherit;
|
||||
z-index: 1;
|
||||
line-height: 1.3rem;
|
||||
}
|
||||
|
||||
.signedInText {
|
||||
padding-top: 0rem;
|
||||
left: 4.6rem;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 2rem;
|
||||
float: left;
|
||||
height: 2.8rem;
|
||||
width: 2.8rem;
|
||||
background-color: white;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.button,
|
||||
.buttonPrimary {
|
||||
float: right;
|
||||
margin-right: -.4rem;
|
||||
font-weight: 500;
|
||||
border-radius: .3rem;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
line-height: 1.4rem;
|
||||
padding: .7rem .8rem;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
background-color: transparent;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.buttonPrimary {
|
||||
background-color: #346df1;
|
||||
border-color: #346df1;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
padding: .7rem 1.4rem;
|
||||
}
|
||||
|
||||
.buttonPrimary:hover {
|
||||
box-shadow: inset 0 0 5rem rgba(0,0,0,0.2)
|
||||
}
|
||||
|
||||
.navItems {
|
||||
margin-bottom: 2rem;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.navItem {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
14
apps/dev/nextjs-v4/components/layout.js
Normal file
14
apps/dev/nextjs-v4/components/layout.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import Header from 'components/header'
|
||||
import Footer from 'components/footer'
|
||||
|
||||
export default function Layout ({ children }) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<main>
|
||||
{children}
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
)
|
||||
}
|
||||
45
apps/dev/nextjs-v4/middleware.ts
Normal file
45
apps/dev/nextjs-v4/middleware.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
export { default } from "next-auth/middleware"
|
||||
|
||||
export const config = { matcher: ["/middleware-protected"] }
|
||||
|
||||
// Other ways to use this middleware
|
||||
|
||||
// import withAuth from "next-auth/middleware"
|
||||
// import { withAuth } from "next-auth/middleware"
|
||||
|
||||
// export function middleware(req, ev) {
|
||||
// return withAuth(req)
|
||||
// }
|
||||
|
||||
// export function middleware(req, ev) {
|
||||
// return withAuth(req, ev)
|
||||
// }
|
||||
|
||||
// export function middleware(req, ev) {
|
||||
// return withAuth(req, {
|
||||
// callbacks: {
|
||||
// authorized: ({ token }) => !!token,
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
|
||||
// export default withAuth(function middleware(req, ev) {
|
||||
// console.log(req.nextauth.token)
|
||||
// })
|
||||
|
||||
// export default withAuth(
|
||||
// function middleware(req, ev) {
|
||||
// console.log(req, ev)
|
||||
// },
|
||||
// {
|
||||
// callbacks: {
|
||||
// authorized: ({ token }) => token.name === "Balázs Orbán",
|
||||
// },
|
||||
// }
|
||||
// )
|
||||
|
||||
// export default withAuth({
|
||||
// callbacks: {
|
||||
// authorized: ({ token }) => !!token,
|
||||
// },
|
||||
// })
|
||||
6
apps/dev/nextjs-v4/next-env.d.ts
vendored
Normal file
6
apps/dev/nextjs-v4/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
9
apps/dev/nextjs-v4/next.config.js
Normal file
9
apps/dev/nextjs-v4/next.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/** @type {import("next").NextConfig} */
|
||||
module.exports = {
|
||||
webpack(config) {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
experimental: { appDir: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
}
|
||||
40
apps/dev/nextjs-v4/package.json
Normal file
40
apps/dev/nextjs-v4/package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "next-auth-app-v4",
|
||||
"version": "1.0.0",
|
||||
"description": "NextAuth.js Developer app",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rm -rf .next",
|
||||
"dev": "next dev",
|
||||
"lint": "next lint",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"email": "fake-smtp-server",
|
||||
"start:email": "pnpm email"
|
||||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/supabase-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"@supabase/supabase-js": "^2.0.5",
|
||||
"faunadb": "^4",
|
||||
"next": "13.3.0",
|
||||
"next-auth": "workspace:*",
|
||||
"nodemailer": "^6",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jsonwebtoken": "^8.5.5",
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"fake-smtp-server": "^0.8.0",
|
||||
"pg": "^8.7.3",
|
||||
"prisma": "^3",
|
||||
"sqlite3": "^5.0.8",
|
||||
"typeorm": "0.3.7"
|
||||
}
|
||||
}
|
||||
10
apps/dev/nextjs-v4/pages/_app.js
Normal file
10
apps/dev/nextjs-v4/pages/_app.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
import "./styles.css"
|
||||
|
||||
export default function App({ Component, pageProps }) {
|
||||
return (
|
||||
<SessionProvider session={pageProps.session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
)
|
||||
}
|
||||
17
apps/dev/nextjs-v4/pages/api-example.js
Normal file
17
apps/dev/nextjs-v4/pages/api-example.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import Layout from '../components/layout'
|
||||
|
||||
export default function Page () {
|
||||
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>
|
||||
)
|
||||
}
|
||||
132
apps/dev/nextjs-v4/pages/api/auth-old/[...nextauth].ts
Normal file
132
apps/dev/nextjs-v4/pages/api/auth-old/[...nextauth].ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||
|
||||
// Providers
|
||||
import Apple from "next-auth/providers/apple"
|
||||
import Auth0 from "next-auth/providers/auth0"
|
||||
import AzureAD from "next-auth/providers/azure-ad"
|
||||
import AzureB2C from "next-auth/providers/azure-ad-b2c"
|
||||
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
|
||||
// import Cognito from "next-auth/providers/cognito"
|
||||
import Credentials from "next-auth/providers/credentials"
|
||||
import Discord from "next-auth/providers/discord"
|
||||
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
|
||||
// import Email from "next-auth/providers/email"
|
||||
import Facebook from "next-auth/providers/facebook"
|
||||
import Foursquare from "next-auth/providers/foursquare"
|
||||
import Freshbooks from "next-auth/providers/freshbooks"
|
||||
import GitHub from "next-auth/providers/github"
|
||||
import Gitlab from "next-auth/providers/gitlab"
|
||||
import Google from "next-auth/providers/google"
|
||||
// import IDS4 from "next-auth/providers/identity-server4"
|
||||
import Instagram from "next-auth/providers/instagram"
|
||||
// import Keycloak from "next-auth/providers/keycloak"
|
||||
import Line from "next-auth/providers/line"
|
||||
import LinkedIn from "next-auth/providers/linkedin"
|
||||
import Mailchimp from "next-auth/providers/mailchimp"
|
||||
// import Okta from "next-auth/providers/okta"
|
||||
import Osu from "next-auth/providers/osu"
|
||||
import Patreon from "next-auth/providers/patreon"
|
||||
import Slack from "next-auth/providers/slack"
|
||||
import Spotify from "next-auth/providers/spotify"
|
||||
import Trakt from "next-auth/providers/trakt"
|
||||
import Twitch from "next-auth/providers/twitch"
|
||||
import Twitter from "next-auth/providers/twitter"
|
||||
import Vk from "next-auth/providers/vk"
|
||||
import Wikimedia from "next-auth/providers/wikimedia"
|
||||
import WorkOS from "next-auth/providers/workos"
|
||||
|
||||
// // Prisma
|
||||
// import { PrismaClient } from "@prisma/client"
|
||||
// import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
// const client = globalThis.prisma || new PrismaClient()
|
||||
// if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||
// const adapter = PrismaAdapter(client)
|
||||
|
||||
// // Fauna
|
||||
// import { Client as FaunaClient } from "faunadb"
|
||||
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
||||
// const opts = { secret: process.env.FAUNA_SECRET, domain: process.env.FAUNA_DOMAIN }
|
||||
// const client = globalThis.fauna || new FaunaClient(opts)
|
||||
// if (process.env.NODE_ENV !== "production") globalThis.fauna = client
|
||||
// const adapter = FaunaAdapter(client)
|
||||
|
||||
// // TypeORM
|
||||
// import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
// const adapter = TypeORMLegacyAdapter({
|
||||
// type: "sqlite",
|
||||
// name: "next-auth-test-memory",
|
||||
// database: "./typeorm/dev.db",
|
||||
// synchronize: true,
|
||||
// })
|
||||
|
||||
// // Supabase
|
||||
// import { SupabaseAdapter } from "@next-auth/supabase-adapter"
|
||||
// const adapter = SupabaseAdapter({
|
||||
// url: process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
// secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
|
||||
// })
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// adapter,
|
||||
// debug: process.env.NODE_ENV !== "production",
|
||||
theme: {
|
||||
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||
brandColor: "#1786fb",
|
||||
},
|
||||
providers: [
|
||||
Credentials({
|
||||
credentials: { password: { label: "Password", type: "password" } },
|
||||
async authorize(credentials) {
|
||||
if (credentials.password !== "pw") return null
|
||||
return { name: "Fill Murray", email: "bill@fillmurray.com", image: "https://www.fillmurray.com/64/64", id: "1", foo: "" }
|
||||
},
|
||||
}),
|
||||
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET }),
|
||||
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
|
||||
AzureAD({
|
||||
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
||||
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||
}),
|
||||
AzureB2C({ clientId: process.env.AZURE_B2C_ID, clientSecret: process.env.AZURE_B2C_SECRET, issuer: process.env.AZURE_B2C_ISSUER }),
|
||||
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
||||
// Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
|
||||
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
||||
DuendeIDS6({ clientId: "interactive.confidential", clientSecret: "secret", issuer: "https://demo.duendesoftware.com" }),
|
||||
Facebook({ clientId: process.env.FACEBOOK_ID, clientSecret: process.env.FACEBOOK_SECRET }),
|
||||
Foursquare({ clientId: process.env.FOURSQUARE_ID, clientSecret: process.env.FOURSQUARE_SECRET }),
|
||||
Freshbooks({ clientId: process.env.FRESHBOOKS_ID, clientSecret: process.env.FRESHBOOKS_SECRET }),
|
||||
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
||||
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
||||
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
|
||||
// IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
|
||||
Instagram({ clientId: process.env.INSTAGRAM_ID, clientSecret: process.env.INSTAGRAM_SECRET }),
|
||||
// Keycloak({ clientId: process.env.KEYCLOAK_ID, clientSecret: process.env.KEYCLOAK_SECRET, issuer: process.env.KEYCLOAK_ISSUER }),
|
||||
Line({ clientId: process.env.LINE_ID, clientSecret: process.env.LINE_SECRET }),
|
||||
LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET }),
|
||||
Mailchimp({ clientId: process.env.MAILCHIMP_ID, clientSecret: process.env.MAILCHIMP_SECRET }),
|
||||
// Okta({ clientId: process.env.OKTA_ID, clientSecret: process.env.OKTA_SECRET, issuer: process.env.OKTA_ISSUER }),
|
||||
Osu({ clientId: process.env.OSU_CLIENT_ID, clientSecret: process.env.OSU_CLIENT_SECRET }),
|
||||
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
|
||||
Slack({ clientId: process.env.SLACK_ID, clientSecret: process.env.SLACK_SECRET }),
|
||||
Spotify({ clientId: process.env.SPOTIFY_ID, clientSecret: process.env.SPOTIFY_SECRET }),
|
||||
Trakt({ clientId: process.env.TRAKT_ID, clientSecret: process.env.TRAKT_SECRET }),
|
||||
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
||||
Twitter({ clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
||||
// TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
|
||||
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
||||
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
||||
],
|
||||
}
|
||||
|
||||
if (authOptions.adapter) {
|
||||
// TODO:
|
||||
// authOptions.providers.unshift(
|
||||
// // NOTE: You can start a fake e-mail server with `pnpm email`
|
||||
// // and then go to `http://localhost:1080` in the browser
|
||||
// Email({ server: "smtp://127.0.0.1:1025?tls.rejectUnauthorized=false" })
|
||||
// )
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
7
apps/dev/nextjs-v4/pages/api/examples/jwt.js
Normal file
7
apps/dev/nextjs-v4/pages/api/examples/jwt.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// This is an example of how to read a JSON Web Token from an API route
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
export default async (req, res) => {
|
||||
const token = await getToken({ req })
|
||||
res.send(JSON.stringify(token, null, 2))
|
||||
}
|
||||
19
apps/dev/nextjs-v4/pages/api/examples/protected.js
Normal file
19
apps/dev/nextjs-v4/pages/api/examples/protected.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// This is an example of to protect an API route
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getServerSession(req, res, authOptions)
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
content:
|
||||
"This is protected content. You can access this content because you are signed in.",
|
||||
session,
|
||||
})
|
||||
} else {
|
||||
res.send({
|
||||
error: "You must be sign in to view the protected content on this page.",
|
||||
})
|
||||
}
|
||||
}
|
||||
8
apps/dev/nextjs-v4/pages/api/examples/session.js
Normal file
8
apps/dev/nextjs-v4/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 { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getServerSession(req, res, authOptions)
|
||||
res.json(session)
|
||||
}
|
||||
30
apps/dev/nextjs-v4/pages/api/examples/supabase-rls.js
Normal file
30
apps/dev/nextjs-v4/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 { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
import { createClient } from "@supabase/supabase-js"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await 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))
|
||||
}
|
||||
22
apps/dev/nextjs-v4/pages/client.js
Normal file
22
apps/dev/nextjs-v4/pages/client.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import Layout from '../components/layout'
|
||||
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
The <strong>useSession()</strong> React Hook easy to use and allows pages to render very quickly.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of this approach is that session state is shared between pages by using the <strong>Provider</strong> in <strong>_app.js</strong> so
|
||||
that navigation between pages using <strong>useSession()</strong> is very fast.
|
||||
</p>
|
||||
<p>
|
||||
The disadvantage of <strong>useSession()</strong> is that it requires client side JavaScript.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
67
apps/dev/nextjs-v4/pages/credentials.js
Normal file
67
apps/dev/nextjs-v4/pages/credentials.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
import * as React from "react"
|
||||
import { signIn, signOut, useSession } from "next-auth/react"
|
||||
import Layout from "components/layout"
|
||||
|
||||
export default function Page() {
|
||||
const [response, setResponse] = React.useState(null)
|
||||
const handleLogin = (options) => async () => {
|
||||
if (options.redirect) {
|
||||
return signIn("credentials", options)
|
||||
}
|
||||
const response = await signIn("credentials", options)
|
||||
setResponse(response)
|
||||
}
|
||||
|
||||
const handleLogout = (options) => async () => {
|
||||
if (options.redirect) {
|
||||
return signOut(options)
|
||||
}
|
||||
const response = await signOut(options)
|
||||
setResponse(response)
|
||||
}
|
||||
|
||||
const { data: session } = useSession()
|
||||
|
||||
if (session) {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Test different flows for Credentials logout</h1>
|
||||
<span className="spacing">Default:</span>
|
||||
<button onClick={handleLogout({ redirect: true })}>Logout</button>
|
||||
<br />
|
||||
<span className="spacing">No redirect:</span>
|
||||
<button onClick={handleLogout({ redirect: false })}>Logout</button>
|
||||
<br />
|
||||
<p>Response:</p>
|
||||
<pre style={{ background: "#eee", padding: 16 }}>
|
||||
{JSON.stringify(response, null, 2)}
|
||||
</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Test different flows for Credentials login</h1>
|
||||
<span className="spacing">Default:</span>
|
||||
<button onClick={handleLogin({ redirect: true, password: "password" })}>
|
||||
Login
|
||||
</button>
|
||||
<br />
|
||||
<span className="spacing">No redirect:</span>
|
||||
<button onClick={handleLogin({ redirect: false, password: "password" })}>
|
||||
Login
|
||||
</button>
|
||||
<br />
|
||||
<span className="spacing">No redirect, wrong password:</span>
|
||||
<button onClick={handleLogin({ redirect: false, password: "" })}>
|
||||
Login
|
||||
</button>
|
||||
<p>Response:</p>
|
||||
<pre style={{ background: "#eee", padding: 16 }}>
|
||||
{JSON.stringify(response, null, 2)}
|
||||
</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
80
apps/dev/nextjs-v4/pages/email.js
Normal file
80
apps/dev/nextjs-v4/pages/email.js
Normal file
@@ -0,0 +1,80 @@
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
import * as React from "react"
|
||||
import { signIn, signOut, useSession } from "next-auth/react"
|
||||
import Layout from "components/layout"
|
||||
|
||||
export default function Page() {
|
||||
const [response, setResponse] = React.useState(null)
|
||||
const [email, setEmail] = React.useState("")
|
||||
|
||||
const handleChange = (event) => {
|
||||
setEmail(event.target.value)
|
||||
}
|
||||
|
||||
const handleLogin = (options) => async (event) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (options.redirect) {
|
||||
return signIn("email", options)
|
||||
}
|
||||
const response = await signIn("email", options)
|
||||
setResponse(response)
|
||||
}
|
||||
|
||||
const handleLogout = (options) => async (event) => {
|
||||
if (options.redirect) {
|
||||
return signOut(options)
|
||||
}
|
||||
const response = await signOut(options)
|
||||
setResponse(response)
|
||||
}
|
||||
|
||||
const { data: session } = useSession()
|
||||
|
||||
if (session) {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Test different flows for Email logout</h1>
|
||||
<span className="spacing">Default:</span>
|
||||
<button onClick={handleLogout({ redirect: true })}>Logout</button>
|
||||
<br />
|
||||
<span className="spacing">No redirect:</span>
|
||||
<button onClick={handleLogout({ redirect: false })}>Logout</button>
|
||||
<br />
|
||||
<p>Response:</p>
|
||||
<pre style={{ background: "#eee", padding: 16 }}>
|
||||
{JSON.stringify(response, null, 2)}
|
||||
</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Test different flows for Email login</h1>
|
||||
<label className="spacing">
|
||||
Email address:{" "}
|
||||
<input
|
||||
type="text"
|
||||
id="email"
|
||||
name="email"
|
||||
value={email}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</label>
|
||||
<br />
|
||||
<form onSubmit={handleLogin({ redirect: true, email })}>
|
||||
<span className="spacing">Default:</span>
|
||||
<button type="submit">Sign in with Email</button>
|
||||
</form>
|
||||
<form onSubmit={handleLogin({ redirect: false, email })}>
|
||||
<span className="spacing">No redirect:</span>
|
||||
<button type="submit">Sign in with Email</button>
|
||||
</form>
|
||||
<p>Response:</p>
|
||||
<pre style={{ background: "#eee", padding: 16 }}>
|
||||
{JSON.stringify(response, null, 2)}
|
||||
</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
12
apps/dev/nextjs-v4/pages/index.js
Normal file
12
apps/dev/nextjs-v4/pages/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import Layout from 'components/layout'
|
||||
|
||||
export default function Page () {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>NextAuth.js Example</h1>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use <a href='https://next-auth.js.org'>NextAuth.js</a> for authentication.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
9
apps/dev/nextjs-v4/pages/middleware-protected/index.js
Normal file
9
apps/dev/nextjs-v4/pages/middleware-protected/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import Layout from "components/layout"
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Page protected by Middleware</h1>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
30
apps/dev/nextjs-v4/pages/policy.js
Normal file
30
apps/dev/nextjs-v4/pages/policy.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import Layout from '../components/layout'
|
||||
|
||||
export default function Page () {
|
||||
return (
|
||||
<Layout>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use <a href='https://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>
|
||||
)
|
||||
}
|
||||
48
apps/dev/nextjs-v4/pages/protected-ssr.js
Normal file
48
apps/dev/nextjs-v4/pages/protected-ssr.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
export default function Page({ content, session }) {
|
||||
// If no session exists, display access denied message
|
||||
if (!session) {
|
||||
return (
|
||||
<Layout>
|
||||
<AccessDenied />
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// If session exists, display content
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Protected Page</h1>
|
||||
<p>
|
||||
<strong>{content}</strong>
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await getServerSession(context.req, context.res, authOptions)
|
||||
let content = null
|
||||
|
||||
if (session) {
|
||||
const hostname = process.env.NEXTAUTH_URL || "http://localhost:3000"
|
||||
const options = { headers: { cookie: context.req.headers.cookie } }
|
||||
const res = await fetch(`${hostname}/api/examples/protected`, options)
|
||||
const json = await res.json()
|
||||
if (json.content) {
|
||||
content = json.content
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
content,
|
||||
},
|
||||
}
|
||||
}
|
||||
35
apps/dev/nextjs-v4/pages/protected.js
Normal file
35
apps/dev/nextjs-v4/pages/protected.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useState, useEffect } from "react"
|
||||
import { useSession } from "next-auth/react"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function Page() {
|
||||
const { status } = useSession({
|
||||
required: true,
|
||||
})
|
||||
const [content, setContent] = useState()
|
||||
|
||||
// Fetch content from protected route
|
||||
useEffect(() => {
|
||||
if (status === "loading") return
|
||||
const fetchData = async () => {
|
||||
const res = await fetch("/api/examples/protected")
|
||||
const json = await res.json()
|
||||
if (json.content) {
|
||||
setContent(json.content)
|
||||
}
|
||||
}
|
||||
fetchData()
|
||||
}, [status])
|
||||
|
||||
if (status === "loading") return <Layout>Loading...</Layout>
|
||||
|
||||
// If session exists, display content
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Protected Page</h1>
|
||||
<p>
|
||||
<strong>{content}</strong>
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
46
apps/dev/nextjs-v4/pages/server.js
Normal file
46
apps/dev/nextjs-v4/pages/server.js
Normal file
@@ -0,0 +1,46 @@
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import Layout from "../components/layout"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
|
||||
export default function Page() {
|
||||
// As this page uses Server Side Rendering, the `session` will be already
|
||||
// populated on render without needing to go through a loading stage.
|
||||
// This is possible because of the shared context configured in `_app.js` that
|
||||
// is used by `useSession()`.
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>getServerSession()</strong> method in{" "}
|
||||
<strong>getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getSession()</strong> is still recommended on the client.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of Server Side Rendering is this page does not require
|
||||
client side JavaScript.
|
||||
</p>
|
||||
<p>
|
||||
The disadvantage of Server Side Rendering is that this page is slower to
|
||||
render.
|
||||
</p>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// Export the `session` prop to use sessions with Server Side Rendering
|
||||
export async function getServerSideProps(context) {
|
||||
return {
|
||||
props: {
|
||||
session: await getServerSession(context.req, context.res, authOptions),
|
||||
},
|
||||
}
|
||||
}
|
||||
32
apps/dev/nextjs-v4/pages/styles.css
Normal file
32
apps/dev/nextjs-v4/pages/styles.css
Normal file
@@ -0,0 +1,32 @@
|
||||
body {
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
li,
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
iframe {
|
||||
background: #ccc;
|
||||
border: 1px solid #ccc;
|
||||
height: 10rem;
|
||||
width: 100%;
|
||||
border-radius: .5rem;
|
||||
filter: invert(1);
|
||||
}
|
||||
49
apps/dev/nextjs-v4/pages/supabase-client-rls.js
Normal file
49
apps/dev/nextjs-v4/pages/supabase-client-rls.js
Normal file
@@ -0,0 +1,49 @@
|
||||
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) {
|
||||
console.log(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>
|
||||
)
|
||||
}
|
||||
64
apps/dev/nextjs-v4/pages/supabase-ssr.js
Normal file
64
apps/dev/nextjs-v4/pages/supabase-ssr.js
Normal file
@@ -0,0 +1,64 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
// and fetching data from Supabase with RLS enabled.
|
||||
import { 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 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,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Account" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"userId" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"provider" TEXT NOT NULL,
|
||||
"providerAccountId" TEXT NOT NULL,
|
||||
"refresh_token" TEXT,
|
||||
"access_token" TEXT,
|
||||
"expires_at" INTEGER,
|
||||
"token_type" TEXT,
|
||||
"scope" TEXT,
|
||||
"id_token" TEXT,
|
||||
"session_state" TEXT,
|
||||
"oauth_token_secret" TEXT,
|
||||
"oauth_token" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "Account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"sessionToken" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"expires" DATETIME NOT NULL,
|
||||
CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT,
|
||||
"email" TEXT,
|
||||
"emailVerified" DATETIME,
|
||||
"image" TEXT
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VerificationToken" (
|
||||
"identifier" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"expires" DATETIME NOT NULL
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Account_provider_providerAccountId_key" ON "Account"("provider", "providerAccountId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Session_sessionToken_key" ON "Session"("sessionToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "VerificationToken_token_key" ON "VerificationToken"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "VerificationToken_identifier_token_key" ON "VerificationToken"("identifier", "token");
|
||||
3
apps/dev/nextjs-v4/prisma/migrations/migration_lock.toml
Normal file
3
apps/dev/nextjs-v4/prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "sqlite"
|
||||
57
apps/dev/nextjs-v4/prisma/schema.prisma
Normal file
57
apps/dev/nextjs-v4/prisma/schema.prisma
Normal file
@@ -0,0 +1,57 @@
|
||||
datasource db {
|
||||
provider = "sqlite"
|
||||
url = "file:./dev.db"
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
model Account {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String
|
||||
provider String
|
||||
providerAccountId String
|
||||
refresh_token String?
|
||||
access_token String?
|
||||
expires_at Int?
|
||||
token_type String?
|
||||
scope String?
|
||||
id_token String?
|
||||
session_state String?
|
||||
oauth_token_secret String?
|
||||
oauth_token String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@unique([provider, providerAccountId])
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(cuid())
|
||||
sessionToken String @unique
|
||||
userId String
|
||||
expires DateTime
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
}
|
||||
|
||||
model VerificationToken {
|
||||
identifier String
|
||||
token String @unique
|
||||
expires DateTime
|
||||
|
||||
@@unique([identifier, token])
|
||||
}
|
||||
39
apps/dev/nextjs-v4/tsconfig.json
Normal file
39
apps/dev/nextjs-v4/tsconfig.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"strictNullChecks": true
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.js"
|
||||
]
|
||||
}
|
||||
20
apps/dev/nextjs-v4/types/nextauth.d.ts
vendored
Normal file
20
apps/dev/nextjs-v4/types/nextauth.d.ts
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
declare module "next-auth" {
|
||||
/**
|
||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||
*/
|
||||
interface Session {
|
||||
// A JWT which can be used as Authorization header with supabase-js for RLS.
|
||||
supabaseAccessToken?: string
|
||||
user: {
|
||||
/** The user's postal address. */
|
||||
address: string
|
||||
} & User
|
||||
}
|
||||
|
||||
interface User {
|
||||
foo: string
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,10 @@ TWITTER_SECRET=
|
||||
WIKIMEDIA_ID=
|
||||
WIKIMEDIA_SECRET=
|
||||
|
||||
# Yandex OAuth. new app -> https://oauth.yandex.com/client/new/id
|
||||
YANDEX_ID=
|
||||
YANDEX_SECRET=
|
||||
|
||||
# Example configuration for a Gmail account (will need SMTP enabled)
|
||||
EMAIL_SERVER=smtps://user@gmail.com:password@smtp.gmail.com:465
|
||||
EMAIL_FROM=user@gmail.com
|
||||
|
||||
@@ -34,6 +34,7 @@ import Spotify from "@auth/core/providers/spotify"
|
||||
import Trakt from "@auth/core/providers/trakt"
|
||||
import Twitch from "@auth/core/providers/twitch"
|
||||
import Twitter from "@auth/core/providers/twitter"
|
||||
import Yandex from "@auth/core/providers/yandex"
|
||||
import Vk from "@auth/core/providers/vk"
|
||||
import Wikimedia from "@auth/core/providers/wikimedia"
|
||||
import WorkOS from "@auth/core/providers/workos"
|
||||
@@ -120,6 +121,7 @@ export const authConfig: AuthConfig = {
|
||||
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 }),
|
||||
Yandex({ clientId: process.env.YANDEX_ID, clientSecret: process.env.YANDEX_SECRET }),
|
||||
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
||||
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function ServerSidePage() {
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
return {
|
||||
props: {
|
||||
session: await unstable_getServerSession(
|
||||
session: await getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
"clean": "gatsby clean"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"gatsby": "next",
|
||||
"dotenv": "16.0.0",
|
||||
"gatsby": "5.8.0-next.3",
|
||||
"next-auth": "workspace:*",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vercel": "^23.1.2"
|
||||
"vercel": "23.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ If you are deploying directly to a particular cloud platform you may also want t
|
||||
|
||||
## Security
|
||||
|
||||
Parts of this section has been moved to its [own page](/getting-started/security).
|
||||
Parts of this section has been moved to its [own page](/security).
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
---
|
||||
title: Databases
|
||||
---
|
||||
|
||||
Auth.js offers multiple database adapters. Check our guides on:
|
||||
|
||||
- [using a database adapter](/guides/adapters/using-a-database-adapter)
|
||||
- [creating your own](/guides/adapters/creating-a-database-adapter)
|
||||
|
||||
> As of **v4** Auth.js no longer ships with an adapter included by default. If you would like to persist any information, you need to install one of the many available adapters yourself. See the individual adapter documentation pages for more details.
|
||||
|
||||
To learn more about databases in Auth.js and how they are used, check out [databases in the FAQ](/concepts/faq#databases).
|
||||
|
||||
---
|
||||
|
||||
## How to use a database
|
||||
|
||||
See the [documentation for adapters](/reference/adapters/overview) for more information on advanced configuration, including how to use Auth.js with other databases using a [custom adapter](/guides/adapters/creating-a-database-adapter).
|
||||
@@ -46,7 +46,7 @@ export default NextAuth({
|
||||
```
|
||||
|
||||
:::note
|
||||
Check the [Credentials Provider options](/reference/providers/credentials) for further customization
|
||||
Check the [Credentials Provider options](/reference/core/providers_credentials) for further customization
|
||||
:::
|
||||
|
||||
Note that we only need to define an `authorize` method that is in charge of receiving the credentials inserted by the user and call the authorization service.
|
||||
14
docs/docs/getting-started/databases.md
Normal file
14
docs/docs/getting-started/databases.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: Databases
|
||||
---
|
||||
|
||||
Auth.js offers multiple database adapters. Check our guides on:
|
||||
|
||||
- [Using a database adapter](/guides/adapters/using-a-database-adapter)
|
||||
- [Creating your own](/guides/adapters/creating-a-database-adapter)
|
||||
|
||||
To learn more about databases in Auth.js and how they are used, check out [databases in the FAQ](/concepts/faq#databases).
|
||||
|
||||
## How to use a database
|
||||
|
||||
See the [documentation for adapters](/reference/adapters) for more information on advanced configuration, including how to use Auth.js with other databases using a [custom adapter](/guides/adapters/creating-a-database-adapter).
|
||||
@@ -66,7 +66,7 @@ Nice! We're getting there. Now we need to read supply this values as the configu
|
||||
|
||||
```ts title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import EmailProvider from "next-auth/providers/email"
|
||||
import Email from "next-auth/providers/email"
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
@@ -128,7 +128,7 @@ import { useSession, signIn, signOut } from "next-auth/react"
|
||||
|
||||
export default function CamperVanPage() {
|
||||
const { data: session, status } = useSession()
|
||||
const userEmail = session?.user.email
|
||||
const userEmail = session?.user?.email
|
||||
|
||||
if (status === "loading") {
|
||||
return <p>Hang on there...</p>
|
||||
@@ -239,7 +239,7 @@ Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.1
|
||||
|
||||
## `nodemailer`
|
||||
|
||||
Like `typeorm` and `prisma`, [`nodemailer`](https://npmjs.com/package/nodemailer) is no longer included as a dependency by default. If you are using the Email provider you must install it in your project manually, or use any other Email library in the [`sendVerificationRequest`](/reference/providers/email) callback. This reduces bundle size for those not actually using the Email provider. Remember, when using the Email provider, it is mandatory to also use a database adapter due to the fact that verification tokens need to be persisted longer term for the magic link functionality to work.
|
||||
Like `typeorm` and `prisma`, [`nodemailer`](https://npmjs.com/package/nodemailer) is no longer included as a dependency by default. If you are using the Email provider you must install it in your project manually, or use any other Email library in the [`sendVerificationRequest`](/guides/providers/email) callback. This reduces bundle size for those not actually using the Email provider. Remember, when using the Email provider, it is mandatory to also use a database adapter due to the fact that verification tokens need to be persisted longer term for the magic link functionality to work.
|
||||
|
||||
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.2
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
---
|
||||
title: Using a custom Provider
|
||||
sidebar_label: Creating a Provider
|
||||
---
|
||||
|
||||
You can use an OAuth provider that isn't built-in by using a custom object.
|
||||
|
||||
As an example of what this looks like, this is the provider object returned for the Google provider:
|
||||
|
||||
```js
|
||||
{
|
||||
id: "google",
|
||||
name: "Google",
|
||||
type: "oauth",
|
||||
wellKnown: "https://accounts.google.com/.well-known/openid-configuration",
|
||||
authorization: { params: { scope: "openid email profile" } },
|
||||
idToken: true,
|
||||
checks: ["pkce", "state"],
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
name: profile.name,
|
||||
email: profile.email,
|
||||
image: profile.picture,
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, if your provider supports OpenID Connect and the `/.well-known/openid-configuration` endpoint contains support for the `grant_type`: `authorization_code`, you only need to pass the URL to that configuration file and define some basic fields like `name` and `type`.
|
||||
|
||||
Otherwise, you can pass a more full set of URLs for each OAuth2.0 flow step, for example:
|
||||
|
||||
```js
|
||||
{
|
||||
id: "kakao",
|
||||
name: "Kakao",
|
||||
type: "oauth",
|
||||
authorization: "https://kauth.kakao.com/oauth/authorize",
|
||||
token: "https://kauth.kakao.com/oauth/token",
|
||||
userinfo: "https://kapi.kakao.com/v2/user/me",
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.id,
|
||||
name: profile.kakao_account?.profile.nickname,
|
||||
email: profile.kakao_account?.email,
|
||||
image: profile.kakao_account?.profile.profile_image_url,
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Replace all the options in this JSON object with the ones from your custom provider - be sure to give it a unique ID and specify the required URLs, and finally add it to the providers array when initializing the library:
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import TwitterProvider from "next-auth/providers/twitter"
|
||||
...
|
||||
providers: [
|
||||
TwitterProvider({
|
||||
clientId: process.env.TWITTER_ID,
|
||||
clientSecret: process.env.TWITTER_SECRET,
|
||||
}),
|
||||
{
|
||||
id: 'customProvider',
|
||||
name: 'CustomProvider',
|
||||
type: 'oauth',
|
||||
scope: '' // Make sure to request the users email address
|
||||
...
|
||||
}
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
### Override default options
|
||||
|
||||
For built-in providers, in most cases you will only need to specify the `clientId` and `clientSecret`. If you need to override any of the defaults, add your own [options](#options).
|
||||
|
||||
Even if you are using a built-in provider, you can override any of these options to tweak the default configuration.
|
||||
|
||||
:::note
|
||||
The user provided options are deeply merged with the default options. That means you only have to override part of the options that you need to be different. For example if you want different scopes, overriding `authorization.params.scope` is enough, instead of the whole `authorization` option.
|
||||
:::
|
||||
|
||||
```js title=/api/auth/[...nextauth].js
|
||||
import Auth0Provider from "next-auth/providers/auth0"
|
||||
|
||||
Auth0Provider({
|
||||
clientId: process.env.CLIENT_ID,
|
||||
clientSecret: process.env.CLIENT_SECRET,
|
||||
issuer: process.env.ISSUER,
|
||||
authorization: { params: { scope: "openid your_custom_scope" } },
|
||||
})
|
||||
```
|
||||
|
||||
Another example, the `profile` callback will return `id`, `name`, `email` and `picture` by default, but you might need more information from the provider. After setting the correct scopes, you can then do something like this:
|
||||
|
||||
```js title=/api/auth/[...nextauth].js
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
profile(profile) {
|
||||
return {
|
||||
// Return all the profile information you need.
|
||||
// The only truly required field is `id`
|
||||
// to be able identify the account when added to a database
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
An example of how to enable automatic account linking:
|
||||
|
||||
```js title=/api/auth/[...nextauth].js
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
})
|
||||
```
|
||||
|
||||
### Adding a new built-in provider
|
||||
|
||||
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily!
|
||||
|
||||
You only need to add three changes:
|
||||
|
||||
1. Add your config: [`src/providers/{provider}.ts`](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers)<br />
|
||||
- Make sure you use a named default export, like this: `export default function YourProvider`
|
||||
- Add two SVG's of the provider logo, like `google-dark.svg` (dark mode) and `google.svg` (light mode), to the `/packages/next-auth/provider-logos/` directory as well as the styling config to the provider config object. See existing provider for example
|
||||
2. Add provider documentation: [`docs/docs/reference/05-oauth-providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/docs/docs/reference/05-oauth-providers)
|
||||
3. Add the new provider name to the `Provider type` dropdown options in [`the provider issue template`](https://github.com/nextauthjs/next-auth/edit/main/.github/ISSUE_TEMPLATE/2_bug_provider.yml)
|
||||
|
||||
That's it! 🎉 Others will be able to discover and use this provider much more easily now!
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"label": "Other",
|
||||
"collapsible": true,
|
||||
"collapsed": true
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
---
|
||||
title: LDAP Authentication
|
||||
---
|
||||
|
||||
Auth.js provides the ability to setup a [custom Credential provider](/guides/providers/credentials) which we can take advantage of to authenticate users against an existing LDAP server.
|
||||
|
||||
You will need an additional dependency, `ldapjs`, which you can install by running
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install ldapjs
|
||||
```
|
||||
|
||||
Then you must setup the `CredentialsProvider()` provider key like so:
|
||||
|
||||
```js title="[...nextauth].js"
|
||||
const ldap = require("ldapjs")
|
||||
import NextAuth from "next-auth"
|
||||
import CredentialsProvider from "next-auth/providers/credentials"
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
CredentialsProvider({
|
||||
name: "LDAP",
|
||||
credentials: {
|
||||
username: { label: "DN", type: "text", placeholder: "" },
|
||||
password: { label: "Password", type: "password" },
|
||||
},
|
||||
async authorize(credentials, req) {
|
||||
// You might want to pull this call out so we're not making a new LDAP client on every login attempt
|
||||
const client = ldap.createClient({
|
||||
url: process.env.LDAP_URI,
|
||||
})
|
||||
|
||||
// Essentially promisify the LDAPJS client.bind function
|
||||
return new Promise((resolve, reject) => {
|
||||
client.bind(credentials.username, credentials.password, (error) => {
|
||||
if (error) {
|
||||
console.error("Failed")
|
||||
reject()
|
||||
} else {
|
||||
console.log("Logged in")
|
||||
resolve({
|
||||
username: credentials.username,
|
||||
password: credentials.password,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
}),
|
||||
],
|
||||
callbacks: {
|
||||
async jwt({ token, user }) {
|
||||
const isSignIn = user ? true : false
|
||||
if (isSignIn) {
|
||||
token.username = user.username
|
||||
token.password = user.password
|
||||
}
|
||||
return token
|
||||
},
|
||||
async session({ session, token }) {
|
||||
return { ...session, user: { username: token.username } }
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
The idea is that once one is authenticated with the LDAP server, one can pass through both the username/DN and password to the JWT stored in the browser.
|
||||
|
||||
This is then passed back to any API routes and retrieved as such:
|
||||
|
||||
```js title="/pages/api/doLDAPWork.js"
|
||||
token = await jwt.getToken({
|
||||
req,
|
||||
})
|
||||
const { username, password } = token
|
||||
```
|
||||
|
||||
> Thanks to [Winwardo](https://github.com/Winwardo) for the code example
|
||||
@@ -1,60 +0,0 @@
|
||||
---
|
||||
title: Usage with class components
|
||||
---
|
||||
|
||||
If you want to use the [`useSession()`](/reference/react/#usesession) hook in your class components you can do so with the help of a higher order component or with a render prop.
|
||||
|
||||
## Higher Order Component
|
||||
|
||||
```js
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
const withSession = (Component) => (props) => {
|
||||
const session = useSession()
|
||||
|
||||
// if the component has a render property, we are good
|
||||
if (Component.prototype.render) {
|
||||
return <Component session={session} {...props} />
|
||||
}
|
||||
|
||||
// if the passed component is a function component, there is no need for this wrapper
|
||||
throw new Error(
|
||||
[
|
||||
"You passed a function component, `withSession` is not needed.",
|
||||
"You can `useSession` directly in your component.",
|
||||
].join("\n")
|
||||
)
|
||||
}
|
||||
|
||||
// Usage
|
||||
class ClassComponent extends React.Component {
|
||||
render() {
|
||||
const { data: session, status } = this.props.session
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const ClassComponentWithSession = withSession(ClassComponent)
|
||||
```
|
||||
|
||||
## Render Prop
|
||||
|
||||
```js
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
const UseSession = ({ children }) => {
|
||||
const session = useSession()
|
||||
return children(session)
|
||||
}
|
||||
|
||||
// Usage
|
||||
class ClassComponent extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<UseSession>
|
||||
{(session) => <pre>{JSON.stringify(session, null, 2)}</pre>}
|
||||
</UseSession>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -10,4 +10,4 @@ When using a database, you can still use JWT for session handling for fast acces
|
||||
|
||||
We have a list of official adapters that are distributed as their own packages under the `@next-auth/{name}-adapter` namespace. Their source code is available in their various adapters package directories at [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth/tree/main/packages):
|
||||
|
||||
- [All available adapters](/reference/adapters/overview)
|
||||
- [All available adapters](/reference/adapters)
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"label": "Basics",
|
||||
"collapsible": true,
|
||||
"collapsed": true
|
||||
"collapsed": false
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: Role-based authentication
|
||||
title: Role-based access control
|
||||
---
|
||||
|
||||
There are two ways to add role-based authentication (RBAC) to your application, based on the [session strategy](/concepts/session-strategies) you choose. Let's see an example for each of these.
|
||||
There are two ways to add role-based access control (RBAC) to your application, based on the [session strategy](/concepts/session-strategies) you choose. Let's see an example for each of these.
|
||||
|
||||
## Getting the role
|
||||
|
||||
@@ -150,4 +150,4 @@ When using Next.js and JWT, you can alternatively also use [Middleware](https://
|
||||
- [Next.js: Middleware](https://next-auth.js.org/configuration/nextjs#wrap-middleware)
|
||||
- [Adapters: User model](/reference/adapters/models#user)
|
||||
- [Adapters: Prisma adapter](/reference/adapters/prisma)
|
||||
- [TypeScript](/getting-started/typescript)
|
||||
- [TypeScript](/getting-started/typescript)
|
||||
@@ -1,9 +1,12 @@
|
||||
---
|
||||
title: Overview
|
||||
sidebar_label: Guides
|
||||
sidebar_position: 0
|
||||
---
|
||||
|
||||
We're creating internal guides to help understand how to use Auth.js and all the possible configurations and uses cases it supports.
|
||||
This section contains guides for common use cases.
|
||||
|
||||
If you can't find what you're looking for, [raise an issue](https://github.com/nextauthjs/next-auth/issues/new/choose) then take a look at our third-party [community resources](/guides/resources).
|
||||
If you can't find what you're looking for, [raise an issue](https://github.com/nextauthjs/next-auth/issues/new?assignees=&labels=triage%2Cdocumentation&template=4_documentation.yml).
|
||||
|
||||
:::warning Warning
|
||||
Guides are being migrated from the [old documentation page](https://next-auth.js.org), so there are going to be references to `next-auth` still. We are continuously working on updating the naming/references.
|
||||
:::
|
||||
@@ -3,21 +3,21 @@ id: credentials
|
||||
title: Credentials Provider
|
||||
---
|
||||
|
||||
The Credentials provider allows you to handle signing in with arbitrary credentials, such as a username and password, domain, or two factor authentication or hardware device (e.g. YubiKey U2F / FIDO).
|
||||
The Credentials provider allows you to handle signing in with arbitrary credentials, such as a username and password, domain, or two-factor authentication or hardware device (e.g. YubiKey U2F / FIDO).
|
||||
|
||||
It is intended to support use cases where you have an existing system you need to authenticate users against.
|
||||
|
||||
It comes with the constraint that users authenticated in this manner are not persisted in the database, and consequently that the Credentials provider can only be used if JSON Web Tokens are enabled for sessions.
|
||||
|
||||
:::warning
|
||||
The functionality provided for credentials based authentication is intentionally limited to discourage use of passwords due to the inherent security risks associated with them and the additional complexity associated with supporting usernames and passwords.
|
||||
The functionality provided for credentials-based authentication is intentionally limited to discourage the use of passwords due to the inherent security risks associated with them and the additional complexity associated with supporting usernames and passwords.
|
||||
:::
|
||||
|
||||
## Options
|
||||
|
||||
The **Credentials Provider** comes with a set of default options:
|
||||
|
||||
- [Credentials Provider options](/reference/providers/credentials)
|
||||
- [Credentials Provider options](/reference/core/providers_credentials)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
@@ -33,7 +33,7 @@ If you return an object it will be persisted to the JSON Web Token and the user
|
||||
|
||||
3. If you throw an Error, the user will be sent to the error page with the error message as a query parameter.
|
||||
|
||||
The Credentials provider's `authorize()` method also provides the request object as the second parameter (see example below).
|
||||
The Credentials provider's `authorize()` method also provides the request object as the second parameter (see the example below).
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
@@ -89,7 +89,7 @@ You can specify more than one credentials provider by specifying a unique `id` f
|
||||
|
||||
You can also use them in conjunction with other provider options.
|
||||
|
||||
As with all providers, the order you specify them is the order they are displayed on the sign in page.
|
||||
As with all providers, the order you specify is the order they are displayed on the sign-in page.
|
||||
|
||||
```js
|
||||
providers: [
|
||||
112
docs/docs/guides/providers/custom-provider.md
Normal file
112
docs/docs/guides/providers/custom-provider.md
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: OAuth Provider
|
||||
---
|
||||
|
||||
Auth.js comes with a set of built-in OAuth providers that you can import from `@auth/core/providers/*`. Every provider has their separate documentation page under the [core package's API Reference](/reference/core)
|
||||
|
||||
|
||||
## Use your own provider
|
||||
|
||||
However, you can use _any_ provider as long as they are compliant with the OAuth/OIDC specifications.
|
||||
|
||||
Auth.js uses the [`oauth4webapi`](https://github.com/panva/oauth4webapi/blob/main/docs/README.md) package under the hood.
|
||||
|
||||
To use a custom OAuth provider with Auth.js, pass an object to the [`providers` list](/reference/core#providers).
|
||||
|
||||
It can implement either the [`OAuth2Config`](/reference/core/providers#oauth2configprofile) or the [`OIDCConfig`](/reference/core/providers#oidcconfigprofile) interface, depending on if your provider is OAuth 2 or OpenID Connect compliant.
|
||||
|
||||
For example, if you have a fully OIDC-compliant provider, this is all you need:
|
||||
|
||||
```ts
|
||||
import type { OIDCConfig } from "@auth/core/providers"
|
||||
|
||||
...
|
||||
providers: [
|
||||
{
|
||||
id: "my-oidc-provider",
|
||||
name: "My Provider",
|
||||
type: "oidc",
|
||||
issuer: "https://my.oidc-provider.com",
|
||||
clientId: process.env.CLIENT_ID,
|
||||
clientSecret: process.env.CLIENT_SECRET
|
||||
} satisfies OIDCConfig
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
Then, you can set the [Redirect URI](https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-07.html#name-client-redirection-endpoint) in your provider's dashboard to something like `https://app-url.com/{path-to-auth-handler}/callback/my-oidc-provider`.
|
||||
|
||||
`{path-to-auth-handler}` is _usually_ `auth` or `api/auth`, depending on your framework of your choice.
|
||||
`my-oidc-provider` matches the `id` you set in the [`providers` list](/reference/core#providers).
|
||||
|
||||
|
||||
## Override default provider config
|
||||
|
||||
For built-in providers, in most cases you will only need to specify the `clientId` and `clientSecret`, and in case of OIDC providers, the `issuer` property. If you need to override any of the defaults, you can add them in the provider's function call and they will be deep-merged with the default configuration options.
|
||||
|
||||
:::note
|
||||
The user provided options are deeply merged with the default options. That means you only have to override part of the options that you need to be different. For example if you want different scopes, overriding `authorization.params.scope` is enough, instead of the whole `authorization` option.
|
||||
:::
|
||||
|
||||
|
||||
For example, to override a provider's default scopes, you can do the following:
|
||||
|
||||
```ts
|
||||
import Auth0Provider from "@auth/core/providers/auth0"
|
||||
|
||||
Auth0Provider({
|
||||
clientId: process.env.CLIENT_ID,
|
||||
clientSecret: process.env.CLIENT_SECRET,
|
||||
issuer: process.env.ISSUER,
|
||||
authorization: { params: { scope: "openid your_custom_scope" } },
|
||||
})
|
||||
```
|
||||
|
||||
Another example, the `profile` callback will return `id`, `name`, `email` and `picture` by default, but you might want to return more information from the provider. After setting the correct scopes, you can then do something like this:
|
||||
|
||||
```ts
|
||||
import GoogleProvider from "@auth/core/providers/google"
|
||||
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
profile(profile) {
|
||||
return {
|
||||
// Return all the profile information you need.
|
||||
// The only truly required field is `id`
|
||||
// to be able identify the account when added to a database
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
An example of how to enable automatic account linking:
|
||||
|
||||
```ts
|
||||
import GoogleProvider from "@auth/core/providers/google"
|
||||
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
})
|
||||
```
|
||||
|
||||
## Adding a new built-in provider
|
||||
|
||||
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list.
|
||||
|
||||
:::note
|
||||
We are only accepting new providers to `@auth/core`, and not `next-auth`. Follow the steps below to make sure your PR is merged!
|
||||
:::
|
||||
|
||||
1. Create a new `{provider}.ts` (for it to get merged, you must use TypeScript) file under the [`packages/core/src/providers`](https://github.com/nextauthjs/next-auth/tree/main/packages/core/src/providers) directory.
|
||||
2. Make sure that you are following other providers, ie.:
|
||||
- Use a named default export: `export default function YourProvider`
|
||||
- Export the TypeScript `interface` that defines the provider's available user info properties
|
||||
- Add the necessary JSDoc comments/documentation (Study the built-in providers to get an understanding what's needed. For example, the [Auth0 provider](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/auth0.ts) is a good example for OIDC and the [GitHub Provider](https://github.com/nextauthjs/next-auth/blob/main/packages/core/src/providers/github.ts) is an OAuth provider.)
|
||||
- Add links to the provider's API reference/documentation so others can understand how to use the provider
|
||||
3. Add the new provider name to the `Provider type` dropdown options in [`the provider issue template`](https://github.com/nextauthjs/next-auth/edit/main/.github/ISSUE_TEMPLATE/2_bug_provider.yml)
|
||||
4. (Optional): Add a logo `{provider}.svg` to the [`docs/static/img/providers`](https://github.com/nextauthjs/next-auth/tree/main/docs/static/img/providers) directory.
|
||||
|
||||
That's it! 🎉 Others will be able to discover and use this provider!
|
||||
109
docs/docs/guides/providers/email-http-api.md
Normal file
109
docs/docs/guides/providers/email-http-api.md
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
id: email-http
|
||||
title: HTTP-based Email Provider
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
:::note
|
||||
The following guide is written for `next-auth` (NextAuth.js), but it should work for any of the Auth.js framework libraries (`@auth/*`) as well.
|
||||
:::
|
||||
|
||||
|
||||
There is a built-in Email provider with which you could connect to the SMTP server of your choice to send "magic link" emails for sign-in purposes. However, the Email provider can also be used with HTTP-based email services, like AWS SES, Postmark, Sendgrid, etc. In this guide, we are going to explain how to use our Email magic link provider with any of the more modern HTTP-based Email APIs.
|
||||
|
||||
For this example, we will be using [SendGrid](https://sendgrid.com), but any email service providing an HTTP API or JS client library will work.
|
||||
We will also refer to the [Prisma Adapter](/reference/adapter/prisma). A [database adapter](/adapters/overview) is a requirement for the Email provider.
|
||||
|
||||
## Setup
|
||||
|
||||
First, if you do not have a project using Auth.js, clone and set up a basic Auth.js project like the one [provided in](https://github.com/nextauthjs/next-auth-example.git) our example repo](https://github.com/nextauthjs/next-auth-example.git).
|
||||
|
||||
- Install the [Prisma Adapter](/reference/adapter/prisma)
|
||||
- Generate an API key from your cloud Email provider of choice and add it to your `.env.*` file. For example, mine is going to be called `SENDGRID_API`
|
||||
- Add the following configuration to your configuration file:
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
adapter: PrismaAdapter(prisma),
|
||||
providers: [
|
||||
{
|
||||
id: 'sendgrid',
|
||||
type: 'email',
|
||||
async sendVerificationRequest({identifier: email, url}) {
|
||||
}
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
```
|
||||
|
||||
Next, all that's left to do is call the HTTP endpoint from our cloud email provider and pass it the required metadata like the `to` address, the email `body`, and any other fields we may need to include.
|
||||
|
||||
As mentioned earlier, we're going to be using SendGrid in this example, so the appropriate endpoint is `https://api.sendgrid.com/v3/mail/send` ([more info](https://docs.sendgrid.com/for-developers/sending-email/api-getting-started)). Therefore, we're going to pull out some of the important information from the `params` argument and use it in a `fetch()` call to the previously mentioned SendGrid API.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
adapter: PrismaAdapter(prisma),
|
||||
providers: [
|
||||
{
|
||||
id: 'sendgrid',
|
||||
type: 'email',
|
||||
async sendVerificationRequest({identifier: email, url}) {
|
||||
// highlight-start
|
||||
// Call the cloud Email provider API for sending emails
|
||||
// See https://docs.sendgrid.com/api-reference/mail-send/mail-send
|
||||
const response = await fetch("https://api.sendgrid.com/v3/mail/send", {
|
||||
// The body format will vary depending on provider, please see their documentation
|
||||
// for further details.
|
||||
body: JSON.stringify({
|
||||
personalizations: [{ to: [{ email }] }],
|
||||
from: { email: "noreply@company.com" },
|
||||
subject: "Sign in to Your page",
|
||||
content: [
|
||||
{
|
||||
type: "text/plain",
|
||||
value: `Please click here to authenticate - ${url}`,
|
||||
},
|
||||
],
|
||||
}),
|
||||
headers: {
|
||||
// Authentication will also vary from provider to provider, please see their docs.
|
||||
Authorization: `Bearer ${process.env.SENDGRID_API}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const { errors } = await response.json()
|
||||
throw new Error(JSON.stringify(errors))
|
||||
}
|
||||
// highlight-end
|
||||
},
|
||||
}
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
And that's all we need to do to send Emails via an HTTP API! Note here that the example is only using `text/plain` as the body type. You'll probably want to change that to `text/html` and pass in a nice-looking HTML email. See, for example, our `html` function in [the Auth.js docs](/providers/email#customizing-emails).
|
||||
|
||||
To sign in via this custom provider, you would refer to it by the `id` in when you are calling the sign-in method, for example: `signIn('sendgrid', { email: 'user@company.com' })`.
|
||||
|
||||
## References
|
||||
|
||||
- [Email provider documentation with HTML generation and more](/reference/core/modules/providers_email)
|
||||
- [SendGrid JSON Body documentation](https://docs.sendgrid.com/api-reference/mail-send/mail-send#body)
|
||||
@@ -23,7 +23,7 @@ The Email Provider can be used with both JSON Web Tokens and database sessions,
|
||||
|
||||
The **Email Provider** comes with a set of default options:
|
||||
|
||||
- [Email Provider options](/reference/providers/email)
|
||||
- [Email Provider options](/guides/providers/email)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
@@ -1,447 +0,0 @@
|
||||
---
|
||||
title: Initialization
|
||||
---
|
||||
|
||||
## Options
|
||||
|
||||
Options are passed to Auth.js when initializing it in a server environment like a Next.js API Route.
|
||||
|
||||
### providers
|
||||
|
||||
- **Default value**: `[]`
|
||||
- **Required**: _Yes_
|
||||
|
||||
#### Description
|
||||
|
||||
An array of authentication providers for signing in (e.g. Google, Facebook, Twitter, GitHub, Email, etc) in any order. This can be one of the built-in providers or an object with a custom provider.
|
||||
|
||||
Refer to the list of [all available Oauth providers](/reference/providers/oauth-builtin) and the [Oauth tutorial](/getting-started/oauth-tutorial) on how to use them.
|
||||
|
||||
---
|
||||
|
||||
### secret
|
||||
|
||||
- **Default value**: `string` (_SHA hash of the "options" object_) in development, no default in production.
|
||||
- **Required**: _Yes, in production!_
|
||||
|
||||
#### Description
|
||||
|
||||
A random string is used to hash tokens, sign/encrypt cookies and generate cryptographic keys.
|
||||
|
||||
If you set [`NEXTAUTH_SECRET`](#nextauth_secret) as an environment variable, you don't have to define this option.
|
||||
|
||||
If no value specified specified in development (and there is no `NEXTAUTH_SECRET` variable either), it uses a hash for all configuration options, including OAuth Client ID / Secrets for entropy.
|
||||
|
||||
:::warning
|
||||
Not providing any `secret` or `NEXTAUTH_SECRET` will throw [an error](/reference/errors#no_secret) in production.
|
||||
:::
|
||||
|
||||
You can quickly create a good value on the command line via this `openssl` command.
|
||||
|
||||
```bash
|
||||
$ openssl rand -base64 32
|
||||
```
|
||||
|
||||
:::tip
|
||||
If you rely on the default secret generation in development, you might notice JWT decryption errors, since the secret changes whenever you change your configuration. Defining an explicit secret will make this problem go away. We will likely make this option mandatory, even in development, in the future.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### session
|
||||
|
||||
- **Default value**: `object`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
The `session` object and all properties on it are optional.
|
||||
|
||||
Default values for this option are shown below:
|
||||
|
||||
```js
|
||||
session: {
|
||||
// Choose how you want to save the user session.
|
||||
// The default is `"jwt"`, an encrypted JWT (JWE) stored in the session cookie.
|
||||
// If you use an `adapter` however, we default it to `"database"` instead.
|
||||
// You can still force a JWT session by explicitly defining `"jwt"`.
|
||||
// When using `"database"`, the session cookie will only contain a `sessionToken` value,
|
||||
// which is used to look up the session in the database.
|
||||
strategy: "database",
|
||||
|
||||
// Seconds - How long until an idle session expires and is no longer valid.
|
||||
maxAge: 30 * 24 * 60 * 60, // 30 days
|
||||
|
||||
// Seconds - Throttle how frequently to write to database to extend a session.
|
||||
// Use it to limit write operations. Set to 0 to always update the database.
|
||||
// Note: This option is ignored if using JSON Web Tokens
|
||||
updateAge: 24 * 60 * 60, // 24 hours
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### jwt
|
||||
|
||||
- **Default value**: `object`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
JSON Web Tokens can be used for session tokens if enabled with `session: { strategy: "jwt" }` option. JSON Web Tokens are enabled by default if you have not specified an adapter. JSON Web Tokens are encrypted (JWE) by default. We recommend you keep this behaviour. See the [Override JWT `encode` and `decode` methods](#override-jwt-encode-and-decode-methods) advanced option.
|
||||
|
||||
#### JSON Web Token Options
|
||||
|
||||
```js
|
||||
jwt: {
|
||||
// The maximum age of the Auth.js issued JWT in seconds.
|
||||
// Defaults to `session.maxAge`.
|
||||
maxAge: 60 * 60 * 24 * 30,
|
||||
// You can define your own encode/decode functions for signing and encryption
|
||||
async encode() {},
|
||||
async decode() {},
|
||||
}
|
||||
```
|
||||
|
||||
An example JSON Web Token contains a payload like this:
|
||||
|
||||
```js
|
||||
{
|
||||
name: 'Iain Collins',
|
||||
email: 'me@iaincollins.com',
|
||||
picture: 'https://example.com/image.jpg',
|
||||
iat: 1594601838,
|
||||
exp: 1597193838
|
||||
}
|
||||
```
|
||||
|
||||
#### JWT Helper
|
||||
|
||||
You can use the built-in `getToken()` helper method to verify and decrypt the token, like this:
|
||||
|
||||
```js
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
const secret = process.env.NEXTAUTH_SECRET
|
||||
|
||||
export default async function handler(req, res) {
|
||||
// if using `NEXTAUTH_SECRET` env variable, we detect it, and you won't actually need to `secret`
|
||||
// const token = await getToken({ req })
|
||||
const token = await getToken({ req, secret })
|
||||
console.log("JSON Web Token", token)
|
||||
res.end()
|
||||
}
|
||||
```
|
||||
|
||||
_For convenience, this helper function is also able to read and decode tokens passed from the `Authorization: 'Bearer token'` HTTP header._
|
||||
|
||||
**Required**
|
||||
|
||||
The getToken() helper requires the following options:
|
||||
|
||||
- `req` - (object) Request object
|
||||
- `secret` - (string) JWT Secret. Use `NEXTAUTH_SECRET` instead.
|
||||
|
||||
You must also pass _any options configured on the `jwt` option_ to the helper.
|
||||
|
||||
e.g. Including custom session `maxAge` and custom signing and/or encryption keys or options
|
||||
|
||||
**Optional**
|
||||
|
||||
It also supports the following options:
|
||||
|
||||
- `secureCookie` - (boolean) Use secure prefixed cookie name
|
||||
|
||||
By default, the helper function will attempt to determine if it should use the secure prefixed cookie (e.g. `true` in production and `false` in development, unless NEXTAUTH_URL contains an HTTPS URL).
|
||||
|
||||
- `cookieName` - (string) Session token cookie name
|
||||
|
||||
The `secureCookie` option is ignored if `cookieName` is explicitly specified.
|
||||
|
||||
- `raw` - (boolean) Get raw token (not decoded)
|
||||
|
||||
If set to `true` returns the raw token without decrypting or verifying it.
|
||||
|
||||
:::note
|
||||
The JWT is stored in the Session Token cookie, the same cookie used for tokens with database sessions.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### pages
|
||||
|
||||
- **Default value**: `{}`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Specify URLs to be used if you want to create custom sign in, sign out and error pages.
|
||||
|
||||
Pages specified will override the corresponding built-in page.
|
||||
|
||||
_For example:_
|
||||
|
||||
```js
|
||||
pages: {
|
||||
signIn: '/auth/signin',
|
||||
signOut: '/auth/signout',
|
||||
error: '/auth/error', // Error code passed in query string as ?error=
|
||||
verifyRequest: '/auth/verify-request', // (used for check email message)
|
||||
newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest)
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
When using this configuration, ensure that these pages actually exist. For example `error: '/auth/error'` refers to a page file at `pages/auth/error.js`.
|
||||
:::
|
||||
|
||||
See the documentation for the [creating custom pages guide](/guides/basics/pages) for more information.
|
||||
|
||||
---
|
||||
|
||||
### callbacks
|
||||
|
||||
- **Default value**: `object`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Callbacks are asynchronous functions you can use to control what happens when an action is performed.
|
||||
|
||||
Callbacks are extremely powerful, especially in scenarios involving JSON Web Tokens as they allow you to implement access controls without a database and to integrate with external databases or APIs.
|
||||
|
||||
You can specify a handler for any of the callbacks below.
|
||||
|
||||
```js
|
||||
callbacks: {
|
||||
async signIn({ user, account, profile, email, credentials }) {
|
||||
return true
|
||||
},
|
||||
async redirect({ url, baseUrl }) {
|
||||
return baseUrl
|
||||
},
|
||||
async session({ session, token, user }) {
|
||||
return session
|
||||
},
|
||||
async jwt({ token, user, account, profile, isNewUser }) {
|
||||
return token
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [our callbacks guide](/guides/basics/callbacks) for more information on how to use the callback functions.
|
||||
|
||||
---
|
||||
|
||||
### events
|
||||
|
||||
- **Default value**: `object`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Events are asynchronous functions that do not return a response, they are useful for audit logging.
|
||||
|
||||
You can specify a handler for any of these events below - e.g. for debugging or to create an audit log.
|
||||
|
||||
The content of the message object varies depending on the flow (e.g. OAuth or Email authentication flow, JWT or database sessions, etc). See the [events guide](/guides/basics/events) for more information on the form of each message object and how to use the events functions.
|
||||
|
||||
```js
|
||||
events: {
|
||||
async signIn(message) { /* on successful sign in */ },
|
||||
async signOut(message) { /* on signout */ },
|
||||
async createUser(message) { /* user created */ },
|
||||
async updateUser(message) { /* user updated - e.g. their email was verified */ },
|
||||
async linkAccount(message) { /* account (e.g. Twitter) linked to a user */ },
|
||||
async session(message) { /* session is active */ },
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### adapter
|
||||
|
||||
- **Default value**: none
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
By default Auth.js does not include an adapter any longer. If you would like to persist user / account data, please install one of the many available adapters. More information can be found in the [adapter documentation](/reference/adapters/overview).
|
||||
|
||||
---
|
||||
|
||||
### debug
|
||||
|
||||
- **Default value**: `false`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Set debug to `true` to enable debug messages for authentication and database operations.
|
||||
|
||||
---
|
||||
|
||||
### logger
|
||||
|
||||
- **Default value**: `console`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Override any of the logger levels (`undefined` levels will use the built-in logger), and intercept logs in NextAuth. You can use this to send NextAuth logs to a third-party logging service.
|
||||
|
||||
The `code` parameter for `error` and `warn` are explained in the [Warnings](/reference/warnings) and [Errors](/reference/errors) pages respectively.
|
||||
|
||||
Example:
|
||||
|
||||
```js title="/pages/api/auth/[...nextauth].js"
|
||||
import log from "logging-service"
|
||||
|
||||
export default NextAuth({
|
||||
...
|
||||
logger: {
|
||||
error(code, metadata) {
|
||||
log.error(code, metadata)
|
||||
},
|
||||
warn(code) {
|
||||
log.warn(code)
|
||||
},
|
||||
debug(code, metadata) {
|
||||
log.debug(code, metadata)
|
||||
}
|
||||
}
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
:::note
|
||||
If the `debug` level is defined by the user, it will be called regardless of the `debug: false` [option](#debug).
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### theme
|
||||
|
||||
- **Default value**: `object`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Changes the color scheme theme of [pages](/reference/configuration/auth-config#pages) as well as allows some minor customization. Set `theme.colorScheme` to `"light"`, if you want to force pages to always be light. Set to `"dark"`, if you want to force pages to always be dark. Set to `"auto"`, (or leave this option out) if you want the pages to follow the preferred system theme. (Uses the [prefers-color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) media query.)
|
||||
|
||||
In addition, you can define a logo URL in `theme.logo` which will be rendered above the main card in the default signin/signout/error/verify-request pages, as well as a `theme.brandColor` which will affect the accent color of these pages.
|
||||
|
||||
```js
|
||||
theme: {
|
||||
colorScheme: "auto", // "auto" | "dark" | "light"
|
||||
brandColor: "", // Hex color code
|
||||
logo: "" // Absolute URL to image
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Options
|
||||
|
||||
Advanced options are passed the same way as basic options, but may have complex implications or side effects. You should try to avoid using advanced options unless you are very comfortable using them.
|
||||
|
||||
---
|
||||
|
||||
### useSecureCookies
|
||||
|
||||
- **Default value**: `true` for HTTPS sites / `false` for HTTP sites
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
When set to `true` (the default for all site URLs that start with `https://`) then all cookies set by Auth.js will only be accessible from HTTPS URLs.
|
||||
|
||||
This option defaults to `false` on URLs that start with `http://` (e.g. `http://localhost:3000`) for developer convenience.
|
||||
|
||||
:::note
|
||||
Properties on any custom `cookies` that are specified override this option.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
Setting this option to _false_ in production is a security risk and may allow sessions to be hijacked if used in production. It is intended to support development and testing. Using this option is not recommended.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
### cookies
|
||||
|
||||
- **Default value**: `{}`
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
Cookies in Auth.js are chunked by default, meaning that once they reach the 4kb limit, we will create a new cookie with the `.{number}` suffix and reassemble the cookies in the correct order when parsing / reading them. This was introduced to avoid size constraints which can occur when users want to store additional data in their sessionToken, for example.
|
||||
|
||||
You can override the default cookie names and options for any of the cookies used by Auth.js.
|
||||
|
||||
This is an advanced option and using it is not recommended as you may break authentication or introduce security flaws into your application.
|
||||
|
||||
You can specify one or more cookies with custom properties, but if you specify custom options for a cookie you must provide all the options for that cookie.
|
||||
|
||||
If you use this feature, you will likely want to create conditional behaviour to support setting different cookies policies in development and production builds, as you will be opting out of the built-in dynamic policy.
|
||||
|
||||
:::tip
|
||||
An example of a use case for this option is to support sharing session tokens across subdomains.
|
||||
:::
|
||||
|
||||
#### Example
|
||||
|
||||
```js
|
||||
cookies: {
|
||||
sessionToken: {
|
||||
name: `__Secure-next-auth.session-token`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: true
|
||||
}
|
||||
},
|
||||
callbackUrl: {
|
||||
name: `__Secure-next-auth.callback-url`,
|
||||
options: {
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: true
|
||||
}
|
||||
},
|
||||
csrfToken: {
|
||||
name: `__Host-next-auth.csrf-token`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: true
|
||||
}
|
||||
},
|
||||
pkceCodeVerifier: {
|
||||
name: `${cookiePrefix}next-auth.pkce.code_verifier`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
secure: useSecureCookies,
|
||||
maxAge: 900
|
||||
}
|
||||
},
|
||||
state: {
|
||||
name: `${cookiePrefix}next-auth.state`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
secure: useSecureCookies,
|
||||
maxAge: 900
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
Using a custom cookie policy may introduce security flaws into your application and is intended as an option for advanced users who understand the implications. Using this option is not recommended.
|
||||
:::
|
||||
@@ -1,38 +0,0 @@
|
||||
---
|
||||
title: Environment variables
|
||||
sidebar_label: Environment Variables
|
||||
---
|
||||
|
||||
## NEXTAUTH_URL
|
||||
|
||||
When deploying to production, set the `NEXTAUTH_URL` environment variable to the canonical URL of your site.
|
||||
|
||||
```
|
||||
NEXTAUTH_URL=https://example.com
|
||||
```
|
||||
|
||||
If your Next.js application uses a custom base path, specify the route to the API endpoint in full.
|
||||
|
||||
_e.g. `NEXTAUTH_URL=https://example.com/custom-route/api/auth`_
|
||||
|
||||
:::note
|
||||
Using [System Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables#system-environment-variables) we automatically detect when you deploy to [Vercel](https://vercel.com) so you don't have to define this variable. Make sure **Automatically expose System Environment Variables** is checked in your Project Settings.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## NEXTAUTH_SECRET
|
||||
|
||||
Used to encrypt the Auth.js JWT, and to hash [email verification tokens](/reference/adapters/models#verification-token). This is the default value for the [`secret`](/reference/configuration/auth-config#secret) option. The `secret` option might be removed in the future in favor of this.
|
||||
|
||||
If you are using [Middleware](/reference/nextjs/#prerequisites) this environment variable must be set.
|
||||
|
||||
---
|
||||
|
||||
## NEXTAUTH_URL_INTERNAL
|
||||
|
||||
If provided, server-side calls will use this instead of `NEXTAUTH_URL`. Useful in environments when the server doesn't have access to the canonical URL of your site. Defaults to `NEXTAUTH_URL`.
|
||||
|
||||
```
|
||||
NEXTAUTH_URL_INTERNAL=http://10.240.8.16
|
||||
```
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"label": "Configuration",
|
||||
"collapsible": true,
|
||||
"collapsed": true
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
---
|
||||
id: client
|
||||
title: Utilities
|
||||
---
|
||||
|
||||
The Auth.js client library makes it easy to interact with sessions from React applications.
|
||||
|
||||
#### Example Session Object
|
||||
|
||||
```ts
|
||||
{
|
||||
user: {
|
||||
name: string
|
||||
email: string
|
||||
image: string
|
||||
},
|
||||
expires: Date // This is the expiry of the session, not any of the tokens within the session
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
The session data returned to the client does not contain sensitive information such as the Session Token or OAuth tokens. It contains a minimal payload that includes enough data needed to display information on a page about the user who is signed in for presentation purposes (e.g name, email, image).
|
||||
|
||||
You can use the [session callback](/reference/configuration/auth-config#callbacks) to customize the session object returned to the client if you need to return additional data in the session object.
|
||||
:::
|
||||
|
||||
:::note
|
||||
The `expires` value is rotated, meaning whenever the session is retrieved from the [REST API](/reference/rest-api), this value will be updated as well, to avoid session expiry.
|
||||
:::
|
||||
|
||||
## getSession()
|
||||
|
||||
- Client Side: **Yes**
|
||||
- Server Side: **No** (See: [`unstable_getServerSession()`](/reference/nextjs/#unstable_getserversession)
|
||||
|
||||
Auth.js provides a `getSession()` helper which should be called **client side only** to return the current active session.
|
||||
|
||||
On the server side, **this is still available to use**, however, we recommend using `unstable_getServerSession` going forward. The idea behind this is to avoid an additional unnecessary `fetch` call on the server side. For more information, please check out [this issue](https://github.com/nextauthjs/next-auth/issues/1535).
|
||||
|
||||
:::note
|
||||
The `unstable_getServerSession` only has the prefix `unstable_` at the moment, because the API may change in the future. There are no known bugs at the moment and it is safe to use. If you discover any issues, please do report them as a [GitHub Issue](https://github.com/nextauthjs/next-auth/issues) and we will patch them as soon as possible.
|
||||
:::
|
||||
|
||||
This helper is helpful in case you want to read the session outside of the context of React.
|
||||
|
||||
When called, `getSession()` will send a request to `/api/auth/session` and returns a promise with a [session object](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/core/types.ts#L407-L425), or `null` if no session exists.
|
||||
|
||||
```js
|
||||
async function myFunction() {
|
||||
const session = await getSession()
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
Read the tutorial [securing pages and API routes](/guides/basics/securing-pages-and-api-routes) to know how to fetch the session in server side calls using `unstable_getServerSession()`.
|
||||
|
||||
---
|
||||
|
||||
## getCsrfToken()
|
||||
|
||||
- Client Side: **Yes**
|
||||
- Server Side: **Yes**
|
||||
|
||||
The `getCsrfToken()` method returns the current Cross Site Request Forgery Token (CSRF Token) required to make POST requests (e.g. for signing in and signing out).
|
||||
|
||||
You likely only need to use this if you are not using the built-in `signIn()` and `signOut()` methods.
|
||||
|
||||
#### Client Side Example
|
||||
|
||||
```js
|
||||
async function myFunction() {
|
||||
const csrfToken = await getCsrfToken()
|
||||
/* ... */
|
||||
}
|
||||
```
|
||||
|
||||
#### Server Side Example
|
||||
|
||||
```js
|
||||
import { getCsrfToken } from "next-auth/react"
|
||||
|
||||
export default async (req, res) => {
|
||||
const csrfToken = await getCsrfToken({ req })
|
||||
/* ... */
|
||||
res.end()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## getProviders()
|
||||
|
||||
- Client Side: **Yes**
|
||||
- Server Side: **Yes**
|
||||
|
||||
The `getProviders()` method returns the list of providers currently configured for sign in.
|
||||
|
||||
It calls `/api/auth/providers` and returns a list of the currently configured authentication providers.
|
||||
|
||||
It can be useful if you are creating a dynamic custom sign in page.
|
||||
|
||||
---
|
||||
|
||||
#### API Route
|
||||
|
||||
```jsx title="pages/api/example.js"
|
||||
import { getProviders } from "next-auth/react"
|
||||
|
||||
export default async (req, res) => {
|
||||
const providers = await getProviders()
|
||||
console.log("Providers", providers)
|
||||
res.end()
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
Unlike and `getCsrfToken()`, when calling `getProviders()` server side, you don't need to pass anything, just as calling it client side.
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## signIn()
|
||||
|
||||
- Client Side: **Yes**
|
||||
- Server Side: No
|
||||
|
||||
Using the `signIn()` method ensures the user ends back on the page they started on after completing a sign in flow. It will also handle CSRF Tokens for you automatically when signing in with email.
|
||||
|
||||
The `signIn()` method can be called from the client in different ways, as shown below.
|
||||
|
||||
### Redirects to sign in page when clicked
|
||||
|
||||
```js
|
||||
import { signIn } from "next-auth/react"
|
||||
|
||||
export default () => <button onClick={() => signIn()}>Sign in</button>
|
||||
```
|
||||
|
||||
### Starts OAuth sign-in flow when clicked
|
||||
|
||||
By default, when calling the `signIn()` method with no arguments, you will be redirected to the Auth.js sign-in page. If you want to skip that and get redirected to your provider's page immediately, call the `signIn()` method with the provider's `id`.
|
||||
|
||||
For example to sign in with Google:
|
||||
|
||||
```js
|
||||
import { signIn } from "next-auth/react"
|
||||
|
||||
export default () => (
|
||||
<button onClick={() => signIn("google")}>Sign in with Google</button>
|
||||
)
|
||||
```
|
||||
|
||||
### Starts Email sign-in flow when clicked
|
||||
|
||||
When using it with the email flow, pass the target `email` as an option.
|
||||
|
||||
```js
|
||||
import { signIn } from "next-auth/react"
|
||||
|
||||
export default ({ email }) => (
|
||||
<button onClick={() => signIn("email", { email })}>Sign in with Email</button>
|
||||
)
|
||||
```
|
||||
|
||||
### Specifying a `callbackUrl`
|
||||
|
||||
The `callbackUrl` specifies to which URL the user will be redirected after signing in. Defaults to the page URL the sign-in is initiated from.
|
||||
|
||||
You can specify a different `callbackUrl` by specifying it as the second argument of `signIn()`. This works for all providers.
|
||||
|
||||
e.g.
|
||||
|
||||
- `signIn(undefined, { callbackUrl: '/foo' })`
|
||||
- `signIn('google', { callbackUrl: 'http://localhost:3000/bar' })`
|
||||
- `signIn('email', { email, callbackUrl: 'http://localhost:3000/foo' })`
|
||||
|
||||
The URL must be considered valid by the [redirect callback handler](/reference/configuration/auth-config#callbacks). By default it requires the URL to be an absolute URL at the same host name, or a relative url starting with a slash. If it does not match it will redirect to the homepage. You can define your own [redirect callback](/guides/basics/callbacks#redirect-callback) to allow other URLs.
|
||||
|
||||
### Using the `redirect: false` option
|
||||
|
||||
:::note
|
||||
The redirect option is only available for `credentials` and `email` providers.
|
||||
:::
|
||||
|
||||
In some cases, you might want to deal with the sign in response on the same page and disable the default redirection. For example, if an error occurs (like wrong credentials given by the user), you might want to handle the error on the same page. For that, you can pass `redirect: false` in the second parameter object.
|
||||
|
||||
e.g.
|
||||
|
||||
- `signIn('credentials', { redirect: false, password: 'password' })`
|
||||
- `signIn('email', { redirect: false, email: 'bill@fillmurray.com' })`
|
||||
|
||||
`signIn` will then return a Promise, that resolves to the following:
|
||||
|
||||
```ts
|
||||
{
|
||||
/**
|
||||
* Will be different error codes,
|
||||
* depending on the type of error.
|
||||
*/
|
||||
error: string | undefined
|
||||
/**
|
||||
* HTTP status code,
|
||||
* hints the kind of error that happened.
|
||||
*/
|
||||
status: number
|
||||
/**
|
||||
* `true` if the signin was successful
|
||||
*/
|
||||
ok: boolean
|
||||
/**
|
||||
* `null` if there was an error,
|
||||
* otherwise the url the user
|
||||
* should have been redirected to.
|
||||
*/
|
||||
url: string | null
|
||||
}
|
||||
```
|
||||
|
||||
### Additional parameters
|
||||
|
||||
It is also possible to pass additional parameters to the `/authorize` endpoint through the third argument of `signIn()`.
|
||||
|
||||
See the [Authorization Request OIDC spec](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) for some ideas. (These are not the only possible ones, all parameters will be forwarded)
|
||||
|
||||
e.g.
|
||||
|
||||
- `signIn("identity-server4", null, { prompt: "login" })` _always ask the user to re-authenticate_
|
||||
- `signIn("auth0", null, { login_hint: "info@example.com" })` _hints the e-mail address to the provider_
|
||||
|
||||
:::note
|
||||
You can also set these parameters through [`provider.authorizationParams`](/reference/providers/oauth).
|
||||
:::
|
||||
|
||||
:::note
|
||||
The following parameters are always overridden server-side: `redirect_uri`, `state`
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## signOut()
|
||||
|
||||
- Client Side: **Yes**
|
||||
- Server Side: No
|
||||
|
||||
In order to logout, use the `signOut()` method to ensure the user ends back on the page they started on after completing the sign out flow. It also handles CSRF tokens for you automatically.
|
||||
|
||||
It reloads the page in the browser when complete.
|
||||
|
||||
```js
|
||||
import { signOut } from "next-auth/react"
|
||||
|
||||
export default () => <button onClick={() => signOut()}>Sign out</button>
|
||||
```
|
||||
|
||||
### Specifying a `callbackUrl`
|
||||
|
||||
As with the `signIn()` function, you can specify a `callbackUrl` parameter by passing it as an option.
|
||||
|
||||
e.g. `signOut({ callbackUrl: 'http://localhost:3000/foo' })`
|
||||
|
||||
The URL must be considered valid by the [redirect callback handler](/guides/basics/callbacks#redirect-callback). By default, it requires the URL to be an absolute URL at the same host name, or you can also supply a relative URL starting with a slash. If it does not match it will redirect to the homepage. You can define your own [redirect callback](/guides/basics/callbacks#redirect-callback) to allow other URLs.
|
||||
|
||||
### Using the `redirect: false` option
|
||||
|
||||
If you pass `redirect: false` to `signOut`, the page will not reload. The session will be deleted, and the `useSession` hook is notified, so any indication about the user will be shown as logged out automatically. It can give a very nice experience for the user.
|
||||
|
||||
:::tip
|
||||
If you need to redirect to another page but you want to avoid a page reload, you can try:
|
||||
`const data = await signOut({redirect: false, callbackUrl: "/foo"})`
|
||||
where `data.url` is the validated URL you can redirect the user to without any flicker by using Next.js's `useRouter().push(data.url)`
|
||||
:::
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
title: Available OAuth providers
|
||||
sidebar_label: OAuth providers
|
||||
---
|
||||
|
||||
Authentication Providers in **Auth.js** are services that can be used to sign a user in.
|
||||
|
||||
Auth.js comes with a set of built-in providers. You can find them [here](https://github.com/nextauthjs/next-auth/tree/main/packages/core/src/providers). Each built-in provider has its own documentation page:
|
||||
|
||||
:::note
|
||||
Auth.js supports any **2.x** and **OpenID Connect (OIDC)** compliant providers and has built-in support for the most popular services.
|
||||
:::
|
||||
|
||||
<ul>
|
||||
{Object.entries(require("../../../providers.json"))
|
||||
.filter(([key]) => !["email", "credentials"].includes(key))
|
||||
.sort(([, a], [, b]) => a.localeCompare(b))
|
||||
.map(([key, name]) => (
|
||||
<li key={key}>
|
||||
<a href={`/reference/oauth-providers/${key}`}>{name}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
@@ -1,193 +0,0 @@
|
||||
---
|
||||
title: OAuth Provider Options
|
||||
sidebar_label: OAuth options
|
||||
---
|
||||
|
||||
## Provider Options
|
||||
|
||||
Whenever you configure a custom or a built-in OAuth provider, you have the following options available:
|
||||
|
||||
```ts
|
||||
interface OAuthConfig {
|
||||
/**
|
||||
* OpenID Connect (OIDC) compliant providers can configure
|
||||
* this instead of `authorize`/`token`/`userinfo` options
|
||||
* without further configuration needed in most cases.
|
||||
* You can still use the `authorize`/`token`/`userinfo`
|
||||
* options for advanced control.
|
||||
*
|
||||
* [Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414#section-3)
|
||||
*/
|
||||
wellKnown?: string
|
||||
/**
|
||||
* The login process will be initiated by sending the user to this URL.
|
||||
*
|
||||
* [Authorization endpoint](https://datatracker.ietf.org/doc/html/rfc6749#section-3.1)
|
||||
*/
|
||||
authorization: EndpointHandler<AuthorizationParameters>
|
||||
/**
|
||||
* Endpoint that returns OAuth 2/OIDC tokens and information about them.
|
||||
* This includes `access_token`, `id_token`, `refresh_token`, etc.
|
||||
*
|
||||
* [Token endpoint](https://datatracker.ietf.org/doc/html/rfc6749#section-3.2)
|
||||
*/
|
||||
token: EndpointHandler<
|
||||
UrlParams,
|
||||
{
|
||||
/**
|
||||
* Parameters extracted from the request to the `/api/auth/callback/:providerId` endpoint.
|
||||
* Contains params like `state`.
|
||||
*/
|
||||
params: CallbackParamsType
|
||||
/**
|
||||
* When using this custom flow, make sure to do all the necessary security checks.
|
||||
* This object contains parameters you have to match against the request to make sure it is valid.
|
||||
*/
|
||||
checks: OAuthChecks
|
||||
},
|
||||
{ tokens: TokenSet }
|
||||
>
|
||||
/**
|
||||
* When using an OAuth 2 provider, the user information must be requested
|
||||
* through an additional request from the userinfo endpoint.
|
||||
*
|
||||
* [Userinfo endpoint](https://www.oauth.com/oauth2-servers/signing-in-with-google/verifying-the-user-info)
|
||||
*/
|
||||
userinfo?: EndpointHandler<UrlParams, { tokens: TokenSet }, Profile>
|
||||
type: "oauth"
|
||||
/**
|
||||
* Used in URLs to refer to a certain provider.
|
||||
* @example /api/auth/callback/twitter // where the `id` is "twitter"
|
||||
*/
|
||||
id: string
|
||||
version: string
|
||||
profile(profile: P, tokens: TokenSet): Awaitable<User & { id: string }>
|
||||
checks?: ChecksType | ChecksType[]
|
||||
clientId: string
|
||||
clientSecret: string
|
||||
/**
|
||||
* If set to `true`, the user information will be extracted
|
||||
* from the `id_token` claims, instead of
|
||||
* making a request to the `userinfo` endpoint.
|
||||
*
|
||||
* `id_token` is usually present in OpenID Connect (OIDC) compliant providers.
|
||||
*
|
||||
* [`id_token` explanation](https://www.oauth.com/oauth2-servers/openid-connect/id-tokens)
|
||||
*/
|
||||
idToken?: boolean
|
||||
region?: string
|
||||
issuer?: string
|
||||
client?: Partial<ClientMetadata>
|
||||
allowDangerousEmailAccountLinking?: boolean
|
||||
/**
|
||||
* Object containing the settings for the styling of the providers sign-in buttons
|
||||
*/
|
||||
style: ProviderStyleType
|
||||
}
|
||||
```
|
||||
|
||||
### `authorization` option
|
||||
|
||||
Configure how to construct the request to the [_Authorization endpoint_](https://datatracker.ietf.org/doc/html/rfc6749#section-3.1).
|
||||
|
||||
There are two ways to use this option:
|
||||
|
||||
1. You can either set `authorization` to be a full URL, like `"https://example.com/oauth/authorization?scope=email"`.
|
||||
2. Use an object with `url` and `params` like so
|
||||
```js
|
||||
authorization: {
|
||||
url: "https://example.com/oauth/authorization",
|
||||
params: { scope: "email" }
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
If your Provider is OpenID Connect (OIDC) compliant, we recommend using the `wellKnown` option instead.
|
||||
:::
|
||||
|
||||
### `token` option
|
||||
|
||||
Configure how to construct the request to the [_Token endpoint_](https://datatracker.ietf.org/doc/html/rfc6749#section-3.2).
|
||||
|
||||
There are three ways to use this option:
|
||||
|
||||
1. You can either set `token` to be a full URL, like `"https://example.com/oauth/token?some=param"`.
|
||||
2. Use an object with `url` and `params` like so
|
||||
```js
|
||||
token: {
|
||||
url: "https://example.com/oauth/token",
|
||||
params: { some: "param" }
|
||||
}
|
||||
```
|
||||
3. Completely take control of the request:
|
||||
```js
|
||||
token: {
|
||||
url: "https://example.com/oauth/token",
|
||||
async request(context) {
|
||||
// context contains useful properties to help you make the request.
|
||||
const tokens = await makeTokenRequest(context)
|
||||
return { tokens }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
Option 3. should not be necessary in most cases, but if your provider does not follow the spec, or you have some very unique constraints it can be useful. Try to avoid it, if possible.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If your Provider is OpenID Connect (OIDC) compliant, we recommend using the `wellKnown` option instead.
|
||||
:::
|
||||
|
||||
### `userinfo` option
|
||||
|
||||
A `userinfo` endpoint returns information about the logged-in user. It is not part of the OAuth specification, but usually available for most providers.
|
||||
|
||||
There are three ways to use this option:
|
||||
|
||||
1. You can either set `userinfo` to be a full URL, like `"https://example.com/oauth/userinfo?some=param"`.
|
||||
2. Use an object with `url` and `params` like so
|
||||
```js
|
||||
userinfo: {
|
||||
url: "https://example.com/oauth/userinfo",
|
||||
params: { some: "param" }
|
||||
}
|
||||
```
|
||||
3. Completely take control of the request:
|
||||
```js
|
||||
userinfo: {
|
||||
url: "https://example.com/oauth/userinfo",
|
||||
// The result of this method will be the input to the `profile` callback.
|
||||
async request(context) {
|
||||
// context contains useful properties to help you make the request.
|
||||
return await makeUserinfoRequest(context)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
Option 3. should not be necessary in most cases, but if your provider does not follow the spec, or you have some very unique constraints it can be useful. Try to avoid it, if possible.
|
||||
:::
|
||||
|
||||
:::tip
|
||||
In the rare case you don't care about what this endpoint returns, or your provider does not have one, you could create a noop function:
|
||||
|
||||
```js
|
||||
userinfo: {
|
||||
request: () => {}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
If your Provider is OpenID Connect (OIDC) compliant, we recommend using the `wellKnown` option instead. OIDC usually returns an `id_token` from the `token` endpoint. `next-auth` can decode the `id_token` to get the user information, instead of making an additional request to the `userinfo` endpoint. Just set `idToken: true` at the top-level of your provider configuration. If not set, `next-auth` will still try to contact this endpoint.
|
||||
:::
|
||||
|
||||
### `client` option
|
||||
|
||||
An advanced option, hopefully you won't need it in most cases. `next-auth` uses `openid-client` under the hood, see the docs on this option [here](https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-clientmetadata-jwks-options).
|
||||
|
||||
### `allowDangerousEmailAccountLinking` option
|
||||
|
||||
Normally, when you sign in with an OAuth provider and another account with the same email address already exists, the accounts are not linked automatically. Automatic account linking on sign in is not secure between arbitrary providers and is disabled by default (see our [Security FAQ](https://authjs.dev/reference/faq#security)). However, it may be desirable to allow automatic account linking if you trust that the provider involved has securely verified the email address associated with the account. Just set `allowDangerousEmailAccountLinking: true` in your provider configuration to enable automatic account linking.
|
||||
@@ -1,19 +0,0 @@
|
||||
---
|
||||
title: Email Provider options
|
||||
sidebar_label: Email options
|
||||
---
|
||||
|
||||
| Name | Description | Type | Required |
|
||||
| :---------------------: | :---------------------------------------------------------------------------------: | :------------------------------: | :------: |
|
||||
| id | Unique ID for the provider | `string` | Yes |
|
||||
| name | Descriptive name for the provider | `string` | Yes |
|
||||
| type | Type of provider, in this case `email` | `"email"` | Yes |
|
||||
| server | Path or object pointing to the email server | `string` or `Object` | Yes |
|
||||
| sendVerificationRequest | Callback to execute when a verification request is sent | `(params) => Promise<undefined>` | Yes |
|
||||
| from | The email address from which emails are sent, default: "<no-reply@example.com>" | `string` | No |
|
||||
| maxAge | How long until the e-mail can be used to log the user in seconds. Defaults to 1 day | `number` | No |
|
||||
|
||||
See our guides on magic links authentication for further tips on how to customize this provider:
|
||||
|
||||
- [Tutorial](/getting-started/email-tutorial)
|
||||
- [Guide deep-dive](/guides/providers/email)
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
title: Credentials Provider options
|
||||
sidebar_label: Credentials options
|
||||
---
|
||||
|
||||
| Name | Description | Type | Required |
|
||||
| :---------: | :-----------------------------------------------: | :-----------------------------------: | :------: |
|
||||
| id | Unique ID for the provider | `string` | Yes |
|
||||
| name | Descriptive name for the provider | `string` | Yes |
|
||||
| type | Type of provider, in this case `credentials` | `"credentials"` | Yes |
|
||||
| credentials | The credentials to sign-in with | `Object` | Yes |
|
||||
| authorize | Callback to execute once user is to be authorized | `(credentials, req) => Promise<User>` | Yes |
|
||||
|
||||
See our guides on credentials authentication for further tips on how to customize this provider:
|
||||
|
||||
- [Tutorial](/getting-started/credentials-tutorial)
|
||||
- [Guide deep-dive](guides/providers/credentials)
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"label": "Providers",
|
||||
"collapsible": true,
|
||||
"collapsed": true
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
title: Overview
|
||||
---
|
||||
|
||||
There's four ways a user can be signed in:
|
||||
|
||||
- [Using a built-in OAuth Provider](/reference/providers/oauth-builtin) (e.g Github, Twitter, Google, etc...)
|
||||
- [Using a custom OAuth Provider](/guides/providers/custom-provider)
|
||||
- [Using Email](/getting-started/email-tutorial)
|
||||
- [Using Credentials](/getting-started/credentials-tutorial)
|
||||
|
||||
In case you need further customization, see the options for each type of provider:
|
||||
|
||||
- [Oauth options](/reference/providers/oauth)
|
||||
- [Email options](/reference/providers/email)
|
||||
- [Credentials options](/reference/providers/credentials)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user