Compare commits

..

60 Commits

Author SHA1 Message Date
GitHub Actions
0ddd47cc0a chore(release): bump package version(s) [skip ci] 2023-04-20 09:38:01 +00:00
Balázs Orbán
0100888d9b fix: consume nonce exactly once (#7327)
* fix: consume nonce exactly once

* tweak state handling
2023-04-20 10:25:41 +01:00
Balázs Orbán
9eeea02fe2 feat: redirect proxy (#7326)
* types

* add `redirectProxy` option

* ignore if no state

* empty commit

* tweak proxy detection

* add origin proxy check to checks

* run randomstate decode

* don't generate state data when no proxy

* ignore next-2

* update dev app

* clarify `UnknownAction` error

* rename to `AUTH_REDIRECT_PROXY_URL`

* simplify state

* clear todos

* cleanup

* clarify comment

* use `InalidChecks` error

* simplify

* clarify errors

* add debug logger to redirect proxy

* add proxy redirect logger

* don't throw error when no origin on proxy

* fix redirect_uri in callback

* add docs/guide

* sort imports

* docs: rephrase
2023-04-20 09:53:44 +01:00
GitHub Actions
0a57fea430 chore(release): bump package version(s) [skip ci] 2023-04-20 08:41:41 +00:00
Tim Schneider
51750e1a06 fix(adapters): correct peer dependency (#7310)
Typo in package.json

Missing | in package.json causing ETARGET and peer dependency errors
2023-04-20 09:23:30 +01:00
Balázs Orbán
039a14d992 fix: clarify unknown action error 2023-04-19 10:40:51 +02:00
Balázs Orbán
da821d2789 chore: cleanup todos, format 2023-04-19 10:40:42 +02:00
Balázs Orbán
be5c42e350 Merge branch 'main' of github.com:nextauthjs/next-auth 2023-04-19 10:36:50 +02:00
Balázs Orbán
b68f461f8b chore: upgrade next 2023-04-19 10:35:34 +02:00
Nick Parsons
95c5ba0b5d docs: Update Clerk sponsorship URL (#7305)
- Change Clerk URL from `https://clerk.dev` to `https://clerk.com`

- Fix alt from copy/paste
2023-04-18 20:13:19 +01:00
GitHub Actions
25388de027 chore(release): bump package version(s) [skip ci] 2023-04-18 17:45:29 +00:00
Balázs Orbán
ad77e1c2b7 chore: trigger CI 2023-04-18 19:31:51 +02:00
Balázs Orbán
cd654c3001 chore: trigger CI 2023-04-18 19:09:53 +02:00
Balázs Orbán
6f9ca4143d fix: detect origin when instanceof Request check fails (#7303) 2023-04-18 17:46:49 +01:00
Balázs Orbán
e97b27414a Merge branch 'main' of github.com:nextauthjs/next-auth 2023-04-17 11:41:02 +02:00
Balázs Orbán
9018939ee7 docs: clean up databases intro page
#7221
2023-04-17 11:40:59 +02:00
Raul
c2fc41b44d chore: fix "Contributing guide" link (#7279) 2023-04-17 10:36:23 +01:00
Chris Hayes
01d7eb4feb docs: Remove --save from install command (#7277)
Remove --save from install command

--save is no longer needed on npm install.
2023-04-17 10:35:48 +01:00
Balázs Orbán
2388c20cc6 Merge branch 'main' of github.com:nextauthjs/next-auth 2023-04-17 11:32:26 +02:00
Balázs Orbán
9a1bef9e72 chore: skip adapters in docs dev by default 2023-04-17 11:32:23 +02:00
Balázs Orbán
35a72d2273 chore: update typedoc dependencies 2023-04-17 11:32:09 +02:00
Abdulaziz Askaraliev
5f1b75a7a2 fix(providers): fix type definition and docs for yandex (#7170)
Co-authored-by: Thang Vu <hi@thvu.dev>
2023-04-16 14:47:06 +07:00
Thang Vu
fa58065951 chore: move next-auth from v4 to main (#7265) 2023-04-15 17:02:46 +01:00
Balázs Orbán
b31f2af66c feat: misc improvements (#7228)
* tweak types, fix typos

* filter non-oauth files when generating provider types

* allow implicit config invoke

* remove workaround for multiple cookie settings in Next.js

* feat: return `null` when session does not exist

* error on missing checks when configured
2023-04-12 11:40:55 +01:00
Prana Adiwira
71bb6f2590 fix(providers): Use the proper check for Reddit (#7224)
Reddit expects the `state` parameter

https://github.com/reddit-archive/reddit/wiki/OAuth2#authorization
2023-04-12 11:37:31 +01:00
Balázs Orbán
6c07331cc5 chore: upgrade turbo 2023-04-06 12:58:10 +02:00
Saurav Maheshkar
c8ef94b2be chore: move prettier and eslint configs under package.json (#7145) 2023-04-06 12:57:16 +02:00
jakzo
75a59fbd92 chore(docs): fix dynamodb typo (#7130)
fix: typo
2023-04-06 12:57:09 +02:00
Balázs Orbán
3dd47b0735 docs(example): remove unstable_ prefix 2023-03-31 05:01:58 +02:00
Balázs Orbán
4dc1d421f8 docs: mention client in OAuth config options
Related issue #7114
2023-03-30 18:34:30 +02:00
Balázs Orbán
99ca67f1cf docs: fix typo 2023-03-28 13:59:08 +02:00
Balázs Orbán
a087df8494 docs: fix some links 2023-03-28 13:47:53 +02:00
Sai Srikar Dumpeti
1aa4994de6 docs: respect color scheme (#7076) 2023-03-28 04:06:21 +02:00
Alan Hoskins
88023f69b9 fix(docs): remove extra install (#7081) 2023-03-27 15:47:32 +02:00
Alan Hoskins
b02057a72d fix(docs): fix broken links links (#7083)
Co-authored-by: Alan Hoskins <ahoskins@knowland.com>
2023-03-27 15:46:43 +02:00
Balázs Orbán
400da8c766 fix(providers): mention Email Address as required for Azure B2C
closes #7071
2023-03-27 15:44:23 +02:00
Andres Rodriguez
b48104801b chore(provider): added svg for Reddit (#7050)
Added svg for Reddit

Co-authored-by: Nico Domino <yo@ndo.dev>
2023-03-27 09:36:47 +02:00
Balázs Orbán
ccbbc800d2 docs: rephrase buttons on landing page 2023-03-27 02:06:33 +02:00
Abdulaziz Askaraliev
d7888263ca fix(providers): update Yandex to TypeScript (#7054)
* fix(providers): yandex add typescript.

* fix(providers): yandex add avatar to scope

* fix(providers): Yandex - add types & avatar scope

* fix(providers): Yandex - permissions list

* Apply suggestions from code review

* Apply suggestions from code review

* docs(provider): added comments for

* revert yandex.ts from next-auth/providers/

* fix(providers): yandex fix typo

* revert

* Update [...nextauth].ts

* Update yandex.ts

* Update yandex.ts

* Update [...nextauth].ts

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-03-27 00:38:06 +01:00
Balázs Orbán
47d3151410 Merge branch 'main' of github.com:nextauthjs/next-auth 2023-03-27 01:32:54 +02:00
Balázs Orbán
7d264860ab chore: package builds as docs#dev task dependencies 2023-03-27 01:32:50 +02:00
Abdulaziz Askaraliev
6184b936f5 chore(docs): show close button on announcementBar (#7074)
* fix #6935: show close button.

* fix(global-css): show close button on annoucement bar

dev and build were generating different results, adding `!important` fixed on build.
2023-03-26 21:48:36 +02:00
Balázs Orbán
1954258a0a docs: make security page top-level 2023-03-26 03:46:51 +02:00
Jabed Zaman
c580f0db22 docs: fix session.user is possibly undefined. (#7058)
fixed the code snippet for the example to consume session via hooks. Threw an error earlier stating 'session.user' is possibly 'undefined'.
2023-03-25 20:15:38 +00:00
Balázs Orbán
d1cf701ed9 docs: change admonition titles 2023-03-24 12:46:02 +01:00
Balázs Orbán
69398e2d3a docs: clarify guides overview 2023-03-24 12:43:56 +01:00
Balázs Orbán
856b5c50fc docs: change section title 2023-03-24 12:43:40 +01:00
Balázs Orbán
2830b7de5b docs: fix some typos 2023-03-24 12:43:23 +01:00
Balázs Orbán
40a0faa586 docs: remove outdated guides 2023-03-24 12:43:08 +01:00
Balázs Orbán
a6b4d958ac docs: open basics guides by default 2023-03-24 12:42:52 +01:00
Balázs Orbán
cc13df9d51 docs: tweak announcement bar 2023-03-24 12:42:41 +01:00
Balázs Orbán
06b8d4772c docs: simplify 2023-03-24 03:44:59 +01:00
Balázs Orbán
d644d1fcbf docs: add sidebar to API reference 2023-03-24 03:43:15 +01:00
Balázs Orbán
380f2de961 docs: add API reference overview 2023-03-24 03:29:29 +01:00
Nikhil Dev Chunchu
dc5f3e1873 chore(docs): update using-a-database-adapter.md (#7028)
Update using-a-database-adapter.md
2023-03-22 09:30:56 +01:00
Balázs Orbán
93f3fcd1b7 chore: update TypeDoc 2023-03-21 19:38:50 +01:00
Lluis Agusti
1d9b9ba47c docs(adapters): source content + overview (#7023)
* docs(adapters): source content + overview

* Apply suggestions from code review

* add adapter packages as docs dependencies

* clean up docusaurus config

* clean up database overview

* fix some links

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-03-21 18:26:52 +00:00
Balázs Orbán
8f6108f230 docs: fix Mermaid rendering, lock gatsby playground versions 2023-03-21 18:54:10 +01:00
Balázs Orbán
15943d6696 docs: fix indent 2023-03-21 01:02:20 +01:00
Balázs Orbán
81589bf738 docs: remove/rename files/directories 2023-03-21 00:49:39 +01:00
522 changed files with 13893 additions and 10207 deletions

View File

@@ -1,74 +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/pages/reference/core
docs/pages/reference/sveltekit
docs/pages/reference/adapter
static
# TODO: Enable
docs-nextra
# --------------- 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*

View File

@@ -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,
}

View File

@@ -2,7 +2,7 @@
adapters: ["packages/core/src/adapters.ts", "packages/adapter-*/**/*"]
core: ["packages/core/src/**/*"]
dgraph: ["packages/adapter-dgraph/**/*"]
documentation: ["packages/docs/pages/**/*"]
documentation: ["packages/docs/docs/**/*"]
dynamodb: ["packages/adapter-dynamodb/**/*"]
examples: ["apps/examples/**/*"]
fauna: ["packages/adapter-fauna/**/*"]

7
.gitignore vendored
View File

@@ -43,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
@@ -82,7 +83,8 @@ packages/core/src/providers/oauth-types.ts
packages/core/lib
packages/core/providers
packages/core/src/lib/pages/styles.ts
docs/pages/reference/core
docs/docs/reference/core
docs/docs/reference/sveltekit
# SvelteKit
@@ -92,8 +94,7 @@ packages/frameworks-sveltekit/.svelte-kit
packages/frameworks-sveltekit/package
packages/frameworks-sveltekit/vite.config.js.timestamp-*
packages/frameworks-sveltekit/vite.config.ts.timestamp-*
docs/pages/reference/sveltekit
# Adapters
docs/pages/reference/adapter
docs/docs/reference/adapter

View File

@@ -13,14 +13,16 @@ pnpm-lock.yaml
*.d.ts.map
.svelte-kit
.next
.nuxt
# --------------- Docs ---------------
.next
docs/pages/reference/core
docs/pages/reference/sveltekit
docs/pages/reference/adapter
.docusaurus
build
docs/docs/reference/core
docs/docs/reference/sveltekit
static
docs/providers.json
# --------------- Packages ---------------

View File

@@ -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",
},
},
],
}

View 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

View File

@@ -0,0 +1,4 @@
{
"typescript.tsdk": "../../node_modules/.pnpm/typescript@4.8.4/node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}

View 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)

View 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 }

View File

@@ -0,0 +1,12 @@
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<head></head>
<body>{children}</body>
</html>
)
}

View 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>
}

View 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>
</>
)
}

View 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>
)
}

View 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;
}

View 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>
)
}

View 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;
}

View 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 />
</>
)
}

View 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,
// },
// })

View File

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

View File

@@ -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 },
}

View 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"
}
}

View 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>
)
}

View 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>
)
}

View 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)

View 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))
}

View 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.",
})
}
}

View 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)
}

View 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))
}

View 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>&lt;/Header&gt;</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>
)
}

View 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>
)
}

View 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>
)
}

View 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>
)
}

View File

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

View 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>
)
}

View 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,
},
}
}

View 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>
)
}

View 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),
},
}
}

View 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);
}

View 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>
)
}

View 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,
},
}
}

View File

@@ -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");

View 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"

View 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])
}

View File

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

20
apps/dev/nextjs-v4/types/nextauth.d.ts vendored Normal file
View 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
}
}

View File

@@ -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

View File

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

View File

@@ -22,7 +22,7 @@
"@prisma/client": "^3",
"@supabase/supabase-js": "^2.0.5",
"faunadb": "^4",
"next": "13.1.1",
"next": "13.3.0",
"next-auth": "workspace:*",
"nodemailer": "^6",
"react": "^18",

View File

@@ -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"
@@ -101,7 +102,7 @@ export const authConfig: AuthConfig = {
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 }),
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, redirectProxy: process.env.AUTH_REDIRECT_PROXY_URL }),
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
// IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
@@ -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 }),

View File

@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
@@ -19,8 +23,17 @@
{
"name": "next"
}
]
],
"strictNullChecks": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules", "jest.config.js"]
}
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
"exclude": [
"node_modules",
"jest.config.js"
]
}

View File

@@ -1,4 +1,4 @@
import { unstable_getServerSession } from "next-auth/next"
import { getServerSession } from "next-auth/next"
import { authOptions } from "./api/auth/[...nextauth]"
import Layout from "../components/layout"
@@ -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

View File

@@ -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"
}
}

View File

@@ -1,3 +0,0 @@
{
"extends": "next/core-web-vitals"
}

66
docs/README.md Normal file
View File

@@ -0,0 +1,66 @@
<p align="center">
<br/>
<a href="https://authjs.dev" target="_blank"><img width="150px" src="https://authjs.dev/img/logo/logo-sm.png" /></a>
<h3 align="center">Auth.js</h3>
<p align="center">Authentication for Next.js</p>
<p align="center">
Open Source. Full Stack. Own Your Data.
</p>
<p align="center" style="align: center;">
<a href="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml?query=workflow%3ARelease">
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg" alt="Release" />
</a>
<a href="https://packagephobia.com/result?p=@auth/core">
<img src="https://packagephobia.com/badge?p=@auth/core" alt="Bundle Size"/>
</a>
<a href="https://www.npmtrends.com/@auth/core">
<img src="https://img.shields.io/npm/dm/@auth/core" alt="Downloads" />
</a>
<a href="https://github.com/nextauthjs/next-auth/stargazers">
<img src="https://img.shields.io/github/stars/nextauthjs/next-auth" alt="Github Stars" />
</a>
<a href="https://www.npmjs.com/package/@auth/core">
<img src="https://img.shields.io/github/v/release/nextauthjs/next-auth?label=latest" alt="Github Stable Release" />
</a>
</p>
</p>
## Overview
This is the repository for the documentation page for Auth.js!
NextAuth.js is a complete open source authentication solution for [Next.js](http://nextjs.org/) applications.
This documentation site is based on the [Docusaurus](https://docusaurus.io) framework.
## Getting Started
To start a local environment of this project, please do the following.
1. Clone the repository.
```bash
$ git clone https://github.com/nextauthjs/docs.git
```
2. Install dependencies
```bash
$ npm install
```
3. Start the development server
```bash
$ npm start
```
And thats all! Now you should have a local copy of this docs site running at [localhost:3000](http://localhost:3000)!
## Contributing
We're open to all community contributions! If you'd like to contribute in any way, please first read our [Contributing Guide](https://github.com/nextauthjs/.github/blob/main/CONTRIBUTING.md).
## License
ISC

View File

@@ -1,19 +0,0 @@
<!-- <svg width="1077" height="990" viewBox="0 0 1077 990" fill="none" xmlns="http://www.w3.org/2000/svg"> -->
<!-- <path d="M909.079 176.687C486.468 1429.32 94.8519 797.145 -245.666 989.191L-273.518 122.311C-98.0847 109.104 255.784 81.3405 267.79 75.9479C282.798 69.2072 1153.31 -485.661 1071.51 -140.889C1022.28 -26.4819 1001.45 -97.0987 909.079 176.687Z" fill="url(#paint0_linear_228_76)" fill-opacity="1" /> -->
<!-- <defs> -->
<!-- <linearGradient id="paint0_linear_228_76" x1="588.47" y1="791.265" x2="238.137" y2="497.91" gradientUnits="userSpaceOnUse"> -->
<!-- <stop stop-color="#FF4400"/> -->
<!-- <stop offset="1" stop-color="#111" /> -->
<!-- </linearGradient> -->
<!-- </defs> -->
<!-- </svg> -->
<svg width="1056" height="855" viewBox="0 0 1056 855" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M888.078 42.3027C465.467 1294.94 73.851 662.761 -266.667 854.807L-294.519 -12.0732C-119.086 -25.2807 234.783 -53.0438 246.789 -58.4364C261.797 -65.1771 1132.31 -620.045 1050.51 -275.273C1001.28 -160.866 980.447 -231.483 888.078 42.3027Z" fill="url(#paint0_radial_228_76)"/>
<defs>
<radialGradient id="paint0_radial_228_76" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(666.999 571.116) rotate(-129.513) scale(513.947 862.777)">
<stop stop-color="#FF4400"/>
<stop offset="1" stop-color="#111111"/>
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,20 +0,0 @@
<!-- <svg width="1405" height="1025" viewBox="0 0 1405 1025" fill="none" xmlns="http://www.w3.org/2000/svg"> -->
<!-- <path d="M1180.05 977.4C483.802 708.04 103.247 143.506 0 -105.091L1102.61 -196C1418.53 307.367 1876.29 1246.76 1180.05 977.4Z" fill="url(#paint0_linear_228_83)" fill-opacity="0.44"/> -->
<!-- <defs> -->
<!-- <linearGradient id="paint0_linear_228_83" x1="185.171" y1="460.565" x2="641.405" y2="-62.9701" gradientUnits="userSpaceOnUse"> -->
<!-- <stop stop-color="#BB44CC"/> -->
<!-- <stop offset="1" stop-color="#BB44CC" stop-opacity="0"/> -->
<!-- </linearGradient> -->
<!-- </defs> -->
<!-- </svg> -->
<svg width="1405" height="1025" viewBox="0 0 1405 1025" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1180.05 977.4C483.802 708.04 103.247 143.506 0 -105.091L1102.61 -196C1418.53 307.367 1876.29 1246.76 1180.05 977.4Z" fill="url(#paint0_radial_228_83)"/>
<defs>
<radialGradient id="paint0_radial_228_83" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(498 619) rotate(-46.5881) scale(548.572 1194.34)">
<stop stop-color="#BB44CC"/>
<stop offset="1" stop-color="#111111"/>
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,20 +0,0 @@
<!-- <svg width="2402" height="275" viewBox="0 0 2402 275" fill="none" xmlns="http://www.w3.org/2000/svg"> -->
<!-- <path d="M305.668 155.376C1150.52 -387.169 3270.85 708.01 2011.14 262.274L1847.48 804.627C1613.84 721.267 1142.31 553.804 1125.29 550.832C1104 547.117 -168.361 431.431 18.8067 264.119C109.949 220.108 121.011 273.958 305.668 155.376Z" fill="url(#paint0_linear_228_78)" fill-opacity="0.66"/> -->
<!-- <defs> -->
<!-- <linearGradient id="paint0_linear_228_78" x1="869.047" y1="-51.7999" x2="921.583" y2="353.448" gradientUnits="userSpaceOnUse"> -->
<!-- <stop stop-color="#44BBCC"/> -->
<!-- <stop offset="1" stop-color="#44BBCC" stop-opacity="0.12"/> -->
<!-- </linearGradient> -->
<!-- </defs> -->
<!-- </svg> -->
<svg width="2402" height="275" viewBox="0 0 2402 275" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M305.668 155.376C1150.52 -387.169 3270.85 708.01 2011.14 262.274L1847.48 804.627C1613.84 721.267 1142.31 553.804 1125.29 550.832C1104 547.117 -168.361 431.431 18.8067 264.119C109.949 220.108 121.011 273.958 305.668 155.376Z" fill="url(#paint0_radial_228_78)"/>
<defs>
<radialGradient id="paint0_radial_228_78" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(883.5 -66) rotate(93.0267) scale(757.557 879.417)">
<stop stop-color="#44BBCC"/>
<stop offset="1" stop-color="#111111"/>
</radialGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,66 +0,0 @@
import { useState, useEffect } from "react"
import { motion } from "framer-motion"
const clamp = (num, min, max) => Math.min(Math.max(num, min), max)
export default function Marquee({ files }) {
const [{ width, height }, setSize] = useState({ height: 0, width: 0 })
useEffect(() => {
setSize({
width: window.innerWidth,
height: window.innerHeight,
})
}, [])
if (width === 0) return
return (
<div className="absolute w-full h-full top-0 left-0 dark:opacity-5 opacity-20 saturate-0 brightness-75 dark:brightness-[1000] -z-20 overflow-hidden flex flex-col marquee-wrapper">
{files.map((name) => (
<MarqueeItem key={name} name={name} width={width} height={height} />
))}
</div>
)
}
function MarqueeItem({ name, width, height }) {
const [y] = useState(height * Math.random())
const [reset, setReset] = useState(false)
const [duration] = useState(clamp(Math.random() * 25, 20, 25))
const offset = Math.random() * width
useEffect(() => {
const timeout =
setTimeout(() => {
setReset(true)
}, (1000 * (width - offset)) / duration) - 2000
return () => clearTimeout(timeout)
}, [duration, width, offset])
return (
<motion.span
key={name + reset}
className="absolute flex items-center justify-center"
initial={{ x: reset ? 0 : offset, y }}
animate={{ x: width }}
transition={{
repeat: Infinity,
duration: reset ? duration : (width - offset) / duration,
ease: "linear",
}}
>
<motion.img
src={`/img/providers/${name}`}
alt={name}
className="relative w-12 drop-shadow-xl"
initial={{ opacity: 0, scale: 0.5 }}
animate={{ opacity: 1, scale: 1 }}
transition={{
delay: reset ? 0 : Math.random() * 5,
duration: 1,
type: "spring",
stiffness: 150,
}}
/>
</motion.span>
)
}

View File

@@ -1,85 +0,0 @@
export default function Triangle({ className }) {
return (
<svg
id="triangle"
viewBox="0 0 445 379"
className={className}
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<style jsx>
{`
@media (prefers-color-scheme: light) {
#triangle-0 {
fill: #000;
}
#triangle-1 {
fill: #ff4400;
}
#triangle-2 {
fill: #bb44cc;
}
#triangle-3 {
fill: #44bbcc;
}
}
`}
</style>
<path
id="triangle-0"
d="M334.033 238.33L222.692 46.7201L111.352 238.33H334.033Z"
fill="#fff"
/>
<path
id="triangle-1"
d="M198.174 1.12812L4.62255 51.2473C1.37638 52.0878 -0.550786 55.4258 0.344333 58.6574L53.7157 251.338C55.1362 256.466 62.0336 257.344 64.6942 252.736L204.874 9.93656C207.535 5.32834 203.325 -0.205751 198.174 1.12812Z"
fill="url(#triangle-1-gradient)"
/>
<path
id="triangle-2"
d="M246.294 1.12825L439.846 51.2473C443.092 52.0879 445.019 55.4259 444.124 58.6574L390.753 251.338C389.332 256.466 382.435 257.344 379.774 252.736L239.594 9.93665C236.933 5.32844 241.143 -0.205634 246.294 1.12825Z"
fill="url(#triangle-2-gradient)"
/>
<path
id="triangle-3"
d="M361.388 286.577L225.585 377.959C223.559 379.322 220.91 379.322 218.885 377.959L83.0814 286.577C78.1672 283.27 80.5079 275.599 86.4311 275.599H358.039C363.962 275.599 366.303 283.27 361.388 286.577Z"
fill="url(#triangle-3-gradient)"
/>
<defs>
<linearGradient
id="triangle-1-gradient"
x1="-1.28386"
y1="52.7769"
x2="134.785"
y2="131.336"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#992900" />
<stop offset="1" stopColor="#FF4400" />
</linearGradient>
<linearGradient
id="triangle-2-gradient"
x1="445.753"
y1="52.7769"
x2="309.684"
y2="131.336"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#6D2178" />
<stop offset="1" stopColor="#BB44CC" />
</linearGradient>
<linearGradient
id="triangle-3-gradient"
x1="222.236"
y1="380.213"
x2="222.236"
y2="275.599"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#1B5B64" />
<stop offset="1" stopColor="#44BBCC" />
</linearGradient>
</defs>
</svg>
)
}

View File

@@ -0,0 +1,5 @@
{
"label": "Concepts",
"collapsible": true,
"collapsed": true
}

View File

@@ -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>

View File

@@ -2,16 +2,14 @@
title: How OAuth works
---
import { Callout } from 'nextra-theme-docs'
Authentication Providers in **Auth.js** are OAuth definitions that allow your users to sign in with their favorite preexisting logins. You can use any of our many predefined providers, or write your own custom OAuth configuration.
- [Using a built-in OAuth Provider](#built-in-providers) (e.g Github, Twitter, Google, etc...)
- [Using a custom OAuth Provider](#using-a-custom-provider)
<Callout>
:::note
Auth.js is designed to work with any OAuth service, it supports **OAuth 1.0**, **1.0A**, **2.0** and **OpenID Connect** and has built-in support for most popular sign-in services.
</Callout>
:::
Without going into too much detail, the OAuth flow generally has 6 parts:

View File

@@ -1,6 +1,11 @@
---
title: Contributors
displayed_sidebar: null
---
## Core team
Without these people, the project could not have become one of the most used authentication libraries in its category.
Without these people, the project could not have become one of the most used authentication library in its category.
- [Balázs Orbán](https://github.com/balazsorban44) - **Lead Maintainer**
- [Thang Vu](https://github.com/ThangHuuVu) - Maintainer (Core)
@@ -9,7 +14,7 @@ Without these people, the project could not have become one of the most used aut
## Special thanks
Special thanks to Lori Karikari for creating most of the original provider configurations, to Fredrik Pettersen for creating the original Prisma Adapter, to Gerald Nolan for adding support for Sign in with Apple, and to Jefferson Bledsoe for working on the original testing automation.
Special thanks to Lori Karikari for creating most of the original provider configurations to Fredrik Pettersen for creating the original Prisma Adapter, to Gerald Nolan for adding support for Sign in with Apple, and to Jefferson Bledsoe for working on original testing automations.
- [Lori Karikari](https://github.com/LoriKarikari)
- [Fredrik Pettersen](https://github.com/Fumler)
@@ -20,7 +25,7 @@ Special thanks to Lori Karikari for creating most of the original provider confi
Auth.js as it exists today has been possible thanks to the work of many individual contributors.
Thank you to the [dozens of individual contributors](https://github.com/nextauthjs/next-auth/graphs/contributors) who have helped shape Auth.js.
Thank you to the [dozens of individual contributors](https://github.com/nextauthjs/next-auth/graphs/contributors) who have help shaped Auth.js.
## Open Collective
@@ -30,12 +35,8 @@ More information can be found at: https://opencollective.com/nextauth
## History
- NextAuth.js was originally developed by <a href="https://github.com/iaincollins">Iain Collins</a> in 2016 for Next.js.
- Auth.js was originally developed by <a href="https://github.com/iaincollins">Iain Collins</a> in 2016 for Next.js.
- In 2020, NextAuth.js was rebuilt from the ground up to support Serverless, with support for MySQL, Postgres and MongoDB, JSON Web Tokens and built-in support for over a dozen authentication providers.
- In 2020, Auth.js was rebuilt from the ground up to support Serverless, with support for MySQL, Postgres and MongoDB, JSON Web Tokens and built in support for over a dozen authentication providers.
- In 2021, efforts have started to move NextAuth.js to other frameworks and to support as many databases and providers as possible.
- In 2022, NextAuth.js was rebranded to Auth.js and became framework/runtime agnostic. The core library `@auth/core` was written by <a href="https://twitter.com/balazsorban44">Balázs Orbán</a>
- In 2023 // TODO: 👀🤫
- In 2021, efforts have started to move Auth.js to other frameworks and to support as many databases and providers as possible.

View File

@@ -0,0 +1,5 @@
{
"label": "Getting Started",
"collapsible": true,
"collapsed": true
}

View File

@@ -1,9 +1,7 @@
---
title: Credentials Authentication
title: Credentials authentication
---
import { Callout } from 'nextra-theme-docs'
Auth.js is built in a way that is flexible to integrate it with any authentication back-end you or your company may already have.
This library has been designed to handle the user session client-wise, to support multiple authentication methods (OAuth, Email, etc...) so that you're not forced to run your own authentication service.
@@ -12,9 +10,9 @@ In case you already have an authentication service, you can use the Credentials
For this tutorial, we're going to use [Auth.js example app](https://github.com/nextauthjs/next-auth-example) as a base.
<Callout type="warning">
:::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.
</Callout>
:::
Integrating the Credentials Provider is as simple as initializing it in the Auth.js configuration file:
@@ -47,12 +45,12 @@ export default NextAuth({
})
```
<Callout type="info">
Check the [Credentials Provider options](/reference/providers/credentials) for further customization
</Callout>
:::note
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.
<Callout type="info">
:::info
If you're using TypeScript, you can [augment the `User` interface](/getting-started/typescript#module-augmentation) to match the response of your `authorize` callback, so whenever you read the user in other callbacks (like the `jwt`) the type will match correctly.
</Callout>
:::

View 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).

View File

@@ -2,9 +2,6 @@
title: Email authentication
---
import { Callout } from "nextra-theme-docs"
import Image from "next/image"
import smtpConfig from "./img/dashboard-smtp.png"
import startPageImg from "./img/email-tutorial-start.png"
import checkPageImg from "./img/email-tutorial-check.png"
@@ -21,12 +18,9 @@ The Email provider can be used in conjunction with (or instead of) one or more O
On initial sign in, a **Verification Token** is sent to the email address provided. By default this token **is valid for 24 hours**. If the Verification Token is used within that time (i.e. by clicking on the link in the email) an account is created for the user and they are signed in.
<Callout>
The Email Provider can be used with both JSON Web Tokens and database
sessions, but you [must configure a database
adapter](/guides/adapters/using-a-database-adapter) to use it. It is not
possible to enable email sign in without using a database.
</Callout>
:::tip
The Email Provider can be used with both JSON Web Tokens and database sessions, but you [must configure a database adapter](/guides/adapters/using-a-database-adapter) to use it. It is not possible to enable email sign in without using a database.
:::
## 1. Installing `nodemailer`
@@ -42,14 +36,13 @@ npm install -D nodemailer
Next we need a [SMTP service](https://sendgrid.com/blog/what-is-an-smtp-server/) which will be in charge of sending emails from our application. There's a number of services available for this, however [here are the ones](http://nodemailer.com/smtp/well-known/) known to work with `nodemailer`.
<Callout>
For this tutorial, we're going to be using [Sendgrid](https://sendgrid.com/),
but any of the services linked above should work the same
</Callout>
:::info
For this tutorial, we're going to be using [Sendgrid](https://sendgrid.com/), but any of the services linked above should work the same
:::
First create an account in and then login to the dashboard, then navigate to "Settings → API Keys" and create an API key:
<Image src={smtpConfig} />
<img src={smtpConfig} />
Next paste the API in your terminal as so, and run the command:
@@ -73,17 +66,17 @@ 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: [
Email({
server: {
host: process.env.EMAIL_SERVER_HOST,
port: Number(process.env.EMAIL_SERVER_PORT),
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
auth: {
user: process.env.EMAIL_SERVER_USER,
pass: process.env.EMAIL_SERVER_PASSWORD,
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
},
},
from: process.env.EMAIL_FROM,
@@ -154,8 +147,8 @@ import EmailProvider from "next-auth/providers/email"
export default NextAuth({
secret: process.env.NEXTAUTH_SECRET,
+ adapter: MongoDBAdapter(clientPromise),
providers: [
+ adapter: MongoDBAdapter(clientPromise),
EmailProvider({
server: {
host: process.env.EMAIL_SERVER_HOST,
@@ -179,34 +172,30 @@ Let's start by running a Next.js application with NextAuth, making sure the **Em
For this tutorial we're going to be using NextAuth example app. Launch the app and click on "Sign in", we're redirected to the Sign In page:
<Image src={startPageImg} alt="Screenshot of sign in page" />
<img src={startPageImg} alt="Screenshot of sign in page" />
<Callout>
You can customize the look and feel of your Sign in page pretty easily with
NextAuth. Refer to our [pages guide](/guides/basics/pages) for that!
</Callout>
:::info
You can customize the look and feel of your Sign in page pretty easily with NextAuth. Refer to our [pages guide](/guides/basics/pages) for that!
:::
Then we insert the email address we want to log-in with in the Email credentials section and click on "Sign in with Email".
NextAuth will then display another page hinting the user to check their email:
<Image src={checkPageImg} alt="Screenshot of check email page" />
<img src={checkPageImg} alt="Screenshot of check email page" />
Let's now check our email, and look for one sent from NextAuth (check your spam folder just in case):
<Image src={mailboxImg} alt="Screenshot of mailbox" />
<img src={mailboxImg} alt="Screenshot of mailbox" />
Nice! We got one, coming from the sender specified in the `EMAIL_FROM` environment variable from our configuration above and that's is the sender we verified in Sengrid.
Nice! We got one, coming from the sender specified in the `EMAIL_FROM` environment variable from our configuration above and that's is the sender we verified in Sendgrid.
Click on "Sign in" and a new browser tab will open, you should then land on your application as authenticated!
<Image src={loggedInImg} alt="Screenshot of logged in" />
<img src={loggedInImg} alt="Screenshot of logged in" />
Easy right? We had to configure Sendgrid and install a database adapter so the user sessions can be saved somewhere, but once done NextAuth will deal with all the user session management for us in a secure way!
<Callout>
A user account (i.e. an entry in the Users table) will not be created for the
user until the first time they verify their email address. If an email address
is already associated with an account, the user will be signed in to that
account when they use the link in the email.
</Callout>
:::info
A user account (i.e. an entry in the Users table) will not be created for the user until the first time they verify their email address. If an email address is already associated with an account, the user will be signed in to that account when they use the link in the email.
:::

View File

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

View File

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

View File

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 175 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 127 KiB

View File

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 157 KiB

View File

Before

Width:  |  Height:  |  Size: 183 KiB

After

Width:  |  Height:  |  Size: 183 KiB

View File

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 204 KiB

View File

Before

Width:  |  Height:  |  Size: 172 KiB

After

Width:  |  Height:  |  Size: 172 KiB

View File

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 193 KiB

View File

@@ -0,0 +1,44 @@
---
title: Introduction
sidebar_position: 0
---
## About Auth.js
Auth.js is a complete open-source authentication solution for web applications. Check out the live demos of Auth.js in action:
- [Next.js](https://next-auth-example.vercel.app/)
- [SvelteKit](https://sveltekit-auth-example.vercel.app/)
- [SolidStart](https://auth-solid.vercel.app/)
Continue to our tutorials to see how to use Auth.js for authentication:
- [Setup with OAuth](/getting-started/oauth-tutorial)
- [Setup with magic links](/getting-started/email-tutorial)
- [Integrating with external auth](/getting-started/credentials-tutorial)
### Battery included
- Built in support for 60+ popular services (Google, Facebook, Auth0, Apple…)
- Built-in email/password-less/magic link
- Use with any OAuth 2 or OpenID Connect provider
- Use with any username/password store
### Flexible
- Runtime agnostic - run anywhere! Vercel Edge Functions, Node.js, Serverless, etc.
- Use with any modern framework! Next.js, SolidStart, SvelteKit, etc.
- [Bring Your Own Database](/getting-started/databases) - or none! MySQL, Postgres, MSSQL, MongoDB, etc. Choose database sessions or JWT.
_Note: Email sign-in requires a database to store single-use verification tokens._
### Secure by default
- Signed, prefixed, server-only cookies
- Built-in CSRF protection
- Doesn't rely on client-side JavaScript
- JWT with JWS / JWE / JWK.
## Credits
Auth.js is an open-source project that is only possible [thanks to contributors](/contributors).
To financially support the development of Auth.js, you can check our [OpenCollective](https://opencollective.com/nextauth) page. We appreciate your support 💚.

View File

@@ -0,0 +1,369 @@
---
title: OAuth authentication
---
import creatingOauthAppImg from "./img/getting-started-creating-oauth-app.png"
import addingCallbackUrlImg from "./img/getting-started-oauth-callback-url.png"
import gettingClientIdSecretImg from "./img/getting-started-oauth-clientid-secret.png"
import startAppAndSignInImg from "./img/getting-started-app-start.png"
import githubAuthCredentials from "./img/getting-started-github-auth.png"
import nextAuthUserLoggedIn from "./img/getting-started-nextauth-success.png"
import Tabs from "@theme/Tabs"
import TabItem from "@theme/TabItem"
The goal of Auth.js is that you can add authentication easily to your project with just a few lines of code.
The fastest way to set up Auth.js is with an [OAuth](/concepts/oauth) provider. In this tutorial, we'll be setting Auth.js in a web application to be able to log in with **GitHub**.
:::info
Auth.js comes with a list of [built-in providers](/reference/providers/oauth-builtin) (Google, Facebook, Twitter, etc.). You can also integrate it with your OAuth service by [building a custom provider](/guides/providers/custom-provider).
:::
## 1. Configuring Auth.js
To add Auth.js to your project:
<Tabs groupId="frameworks" queryString>
<TabItem value="next" label="Next.js" default>
### Prerequisites
This tutorial assumes you have a Next.js application set up. If you don't, you can follow the [Next.js tutorial](https://nextjs.org/learn/basics/create-nextjs-app) to get started.
### Installing NextAuth.js
```bash npm2yarn
npm install next-auth
```
:::info
We are working on a new `@auth/nextjs` package that will make it easier to set up Auth.js with Next.js. Stay tuned! For now, you can use the `next-auth` package.
:::
### Creating the server config
Create the following [API route](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes) file. This route contains the necessary configuration for NextAuth.js, as well as the dynamic route handler:
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
export default NextAuth({
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
],
})
```
:::info
Behind the scenes, this creates all the relevant OAuth API routes within `/api/auth/*` so that auth API requests to:
- [GET `/api/auth/signin`](https://authjs.dev/reference/rest-api#get--apiauthsignin)
- [POST `/api/auth/signin/:provider`](https://authjs.dev/reference/rest-api#post--apiauthsigninprovider)
- [GET/POST `/api/auth/callback/:provider`](https://authjs.dev/reference/rest-api#get--post--apiauthcallbackprovider)
- [GET `/api/auth/signout`](https://authjs.dev/reference/rest-api#get--apiauthsignout)
- [POST `/api/auth/signout`](https://authjs.dev/reference/rest-api#post--apiauthsignout)
- [GET `/api/auth/session`](https://authjs.dev/reference/rest-api#get--apiauthsession)
- [GET `/api/auth/csrf`](https://authjs.dev/reference/rest-api#get--apiauthcsrf)
- [GET `/api/auth/providers`](https://authjs.dev/reference/rest-api#get--apiauthproviders)
can be handled by NextAuth.js. In this way, NextAuth.js stays in charge of the whole application's authentication request/response flow.
NextAuth.js is fully customizable - [our guides section](/guides/overview) teaches you how to set it up to handle auth in different ways. All the possible configuration options are [listed here](/reference/configuration/auth-config).
:::
### Adding environment variables
You may notice we are using environment variables in the code example above. We take the value of `GITHUB_ID` and `GITHUB_SECRET` from the GitHub Developer OAuth Portal. See [Configuring OAuth Provider](/getting-started/oauth-tutorial#2-configuring-oauth-provider) section on how to get those.
In your project root, create a `.env.local` file and add the `NEXTAUTH_SECRET` environment variable:
```title=".env.local"
NEXTAUTH_SECRET="This is an example"
```
`NEXTAUTH_SECRET` is a random string used by the library to encrypt tokens and email verification hashes, and **it's mandatory to keep things secure**! 🔥 🔐 . You can use:
```
$ openssl rand -base64 32
```
or https://generate-secret.vercel.app/32 to generate a random value for it.
### Exposing the session via `SessionProvider`:
NextAuth.js provides [`useSession()`](/reference/react/#usesession) - a [React Hooks](https://reactjs.org/docs/hooks-intro.html) to access the session data and status. To use it first you'll need to expose the session context - [`<SessionProvider />`](/reference/react/#sessionprovider) - at the top level of your application:
```ts title="pages/_app.tsx"
import { SessionProvider } from "next-auth/react"
export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
)
}
```
Instances of `useSession` (more on it in the next section) will have access to the session data and status. The `<SessionProvider />` also keep the session updated and synced between browser tabs and windows. 💪🏽
:::tip
Check our [client docs](/reference/react/) to learn all the available options for handling sessions on the browser.
:::
### Consuming the session via hooks
You can use the `useSession` hook from anywhere in your application (E.g. in a header component). Behind the scenes, the hook will connect to the `<SessionProvider />` to read the current user session. Learn more about React Context in the [React docs](https://reactjs.org/docs/context.html).
```ts title="pages/overview.tsx"
import { useSession, signIn, signOut } from "next-auth/react"
export default function CamperVanPage() {
const { data: session, status } = useSession()
const userEmail = session?.user?.email
if (status === "loading") {
return <p>Hang on there...</p>
}
if (status === "authenticated") {
return (
<>
<p>Signed in as {userEmail}</p>
<button onClick={() => signOut()}>Sign out</button>
<img src="https://cdn.pixabay.com/photo/2017/08/11/19/36/vw-2632486_1280.png" />
</>
)
}
return (
<>
<p>Not signed in.</p>
<button onClick={() => signIn("github")}>Sign in</button>
</>
)
}
```
### Protecting API Routes
To protect your API Routes (blocking unauthorized access to resources), you can use [`getServerSession()`](/reference/nextjs#getserversession) to know whether a session exists or not:
```ts title="pages/api/movies/list.ts"
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]"
export default async function listMovies(req, res) {
const session = await getServerSession(req, res, authOptions)
if (session) {
res.send({
movies: [
{ title: "Alien vs Predator", id: 1 },
{ title: "Reservoir Dogs", id: 2 },
],
})
} else {
res.send({
error: "You must sign in to view movies.",
})
}
}
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO: SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO: SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
## 2. Configuring OAuth Provider
Ok, we have our app set up with NextAuth.js, however, if you run the app right now, it won't work as we haven't configured our OAuth provider (**GitHub**) yet.
:::info
When using OAuth you're asking for a third-party service (in this case GitHub, although it could be Google, Twitter, etc...) to handle user authentication for your app.
:::
We need to register our new app in GitHub, so that when NextAuth.js forwards the authorization requests to it, GitHub can recognize your application and prompt the user to sign in.
<img src={creatingOauthAppImg} />
Log in to **GitHub**, go to [`Settings / Developers / OAuth Apps`](https://github.com/settings/developers) and click "New OAuth App"
Next, you'll be presented with a screen to add details about your new application. Fill in the required fields, but pay extra attention to the **Authorization Callback URL** one:
<img src={addingCallbackUrlImg} />
The callback URL we insert should have the following pattern:
```
[origin]/api/auth/callback/[provider]
```
In this case, given we want to try our authentication working locally on our machine and we're using **GitHub** as our OAuth provider, it'll be:
<Tabs groupId="frameworks">
<TabItem value="next" label="Next.js" default>
```
http://localhost:3000/api/auth/callback/github
```
:::info
NextAuth.js will already create this API endpoint for you when we start the application later. Note that because we're using Next.js, locally it starts our server on port `3000` by default. Hence, the origin is `http://localhost:3000`.
:::
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
```
http://localhost:5173/auth/callback/github
```
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
:::info
The last part of the URL, `[provider]`, is the ID of the provider you're using. In this case, we're using GitHub, so it's `github`. If you're using Google, it'll be `google`, etc... We keep track of the provider IDs internally.
The same id is used in the `signIn()` method we saw earlier.
:::
To register, tap on "Register application" button.
The next screen shows all the configurations for your newly created OAuth app. For now, we need two things from it - the **Client ID** and **Client Secret**:
<img src={gettingClientIdSecretImg} />
The Client ID is always there, a public identifier of your OAuth application within GitHub. Click on the **Generate a new client Secret** button and should be presented with a new string (which is just a randomized string).
:::warning
Keep both your Client ID and Client Secret secure and never expose them to the public or share them with people outside your organization. With them, a malicious actor could hijack your application and cause you and your user serious problems!
:::
Cool! We have finished configuring our OAuth provider, now let's wire all together so we can finally see authentication working in our app!
:::info
As noted previously, NextAuth.js has built-in support for multiple OAuth providers, <a href="">here is the full list</a>. You can also easily build your own in case the provider you need is not on the list.
Note that, for each provider, the configuration process will be similar to what we just did:
1. Log in to the provider
2. Create create your OAuth application within it
3. Set the callback URL
4. Get the Client ID and Generate a Client Secret
:::
## 3. Wiring all together
Finally, we just need to reference our **Client ID** and **Client Secret** we just generated in the previous in our Auth.js config. In this way, the library will be able to use them when forwarding users to GitHub, and GitHub will be able to recognize the request as generated from our application.
Now let's copy both the Client ID and Client Secret and paste them into an environment file in the root of your project like so:
```title=".env.local"
GITHUB_ID=12345
GITHUB_SECRET=67890
```
Here is our server configuration file again:
<Tabs groupId="frameworks">
<TabItem value="next" label="Next.js" default>
```ts title="pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
export default NextAuth({
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
],
})
```
Great! We're now ready to run our application locally. Start the Next.js app by running on your terminal the following command and navigating to [`http://localhost:3000`](http://localhost:3000):
```
$ npm run next dev
```
</TabItem>
<TabItem value="sveltekit" label="SvelteKit">
TODO SvelteKit
</TabItem>
<TabItem value="solidstart" label="SolidStart">
TODO SolidStart
</TabItem>
<TabItem value="core" label="Vanilla (No Framework)">
TODO Core
</TabItem>
</Tabs>
You should see the following page:
<img src={startAppAndSignInImg} />
Click on "Sign in" and then on "Sign in with GitHub": Auth.js will redirect you to GitHub, and GitHub will recognize our app [that we just registered](#2-configuring-oauth-provider) and ask the user (in this case you) to enter its credentials to proceed:
<img src={githubAuthCredentials} />
Once inserted and correct, GitHub will redirect the user to our app and NextAuth.js will take care of any further calls with GitHub to get access to the user profile and start a user session safely in the background:
<img src={nextAuthUserLoggedIn} />
Great! We have completed the whole E2E authentication flow setup so that users can log in to our application through GitHub!
## 4. Deploying to production
### Configuring different environments
It's normal to test your application in different environments. Usually, you'll have a development environment (when you run the application locally on your machine), a staging environment (for team members to try the application), and a production environment.
For each environment, you need to create an OAuth application in your provider respectively, as [we did previously](#2-configuring-oauth-provider), and point the **callback URL** to it.
For instance, in the previous section, we pointed the callback URL to `http://localhost:3000/api/auth/callback/github` as we wanted to test our application in the development environment.
If we were to deploy our app to production, we would need to create a new **OAuth App** in GitHub (calling it something like "Van life prod") and point the **callback URL** to our production domain: `https://example.com/api/auth/callback/github`
Finally, we would need to point the environment variables we set ( `GITHUB_ID` and `GITHUB_SECRET` ) to the credentials of the OAuth app we want our application to run with.
### Setting up `NEXTAUTH_URL`
:::tip
Skip this section if you are deploying to Vercel.
:::
When deploying your site, **you need to set** the `NEXTAUTH_URL` environment variable to the canonical URL of your website:
```
NEXTAUTH_URL=https://example.com
```
:::warning
In production, this needs to be set as an environment variable on the service you use to deploy your app.
To set environment variables on Vercel, you can use the [dashboard](https://vercel.com/dashboard) or the `vercel env pull` [command](https://vercel.com/docs/build-step#development-environment-variables).
:::
For more information please check out our [deployment page](/guides/basics/deployment).

View File

@@ -2,12 +2,10 @@
title: TypeScript
---
import { Callout } from 'nextra-theme-docs'
Auth.js has its own type definitions to use in your TypeScript projects safely. Even if you don't use TypeScript, IDEs like VSCode will pick this up to provide you with a better developer experience. While you are typing, you will get suggestions about what certain objects/functions look like, and sometimes links to documentation, examples, and other valuable resources.
Check out the example repository showcasing how to use `next-auth` on a Next.js application with TypeScript:
https://github.com/nextauthjs/next-auth-typescript-example
https://github.com/nextauthjs/next-auth-example
---
@@ -36,9 +34,9 @@ function MyAdapter() {
}
```
<Callout>
:::note
This will work in code editors with a strong TypeScript integration like VSCode or WebStorm. It might not work if you're using more lightweight editors like VIM or Atom.
</Callout>
:::
## Module Augmentation
@@ -159,6 +157,6 @@ declare module "next-auth/jwt" {
Contributions of any kind are always welcome, especially for TypeScript. Please keep in mind that we are a small team working on this project in our free time. We will try our best to give support, but if you think you have a solution for a problem, please open a PR!
<Callout>
:::note
When contributing to TypeScript, if the actual JavaScript user API does not change in a breaking manner, we reserve the right to push any TypeScript change in a minor release. This ensures that we can keep on a faster release cycle.
</Callout>
:::

View File

@@ -0,0 +1,612 @@
---
title: Upgrade Guide (v4)
---
Auth.js version 4 includes a few breaking changes from the last major version (3.x). So we're here to help you upgrade your applications as smoothly as possible. It should be possible to upgrade from any version of 3.x to the latest 4 release by following the next few migration steps.
:::note
Version 4 has been released to GA 🚨
We encourage users to try it out and report any and all issues they come across.
:::
You can upgrade to the new version by running:
```bash npm2yarn
npm install next-auth
```
## `next-auth/jwt`
We no longer have a default export in `next-auth/jwt`.
To comply with this, change the following:
```diff
- import jwt from "next-auth/jwt"
+ import { getToken } from "next-auth/jwt"
```
## `next-auth/react`
We've renamed the client-side import source to `next-auth/react`. To comply with this change, you will simply have to rename anywhere you were using `next-auth/client`.
For example:
```diff
- import { useSession } from "next-auth/client"
+ import { useSession } from "next-auth/react"
```
We've also made the following changes to the names of the exports:
- `setOptions`: Not exposed anymore, use [`SessionProvider` props](/reference/react/#sessionprovider)
- `options`: Not exposed anymore, [use `SessionProvider` props](/reference/react/#sessionprovider)
- `session`: Renamed to `getSession`
- `providers`: Renamed to `getProviders`
- `csrfToken`: Renamed to `getCsrfToken`
- `signin`: Renamed to `signIn`
- `signout`: Renamed to `signOut`
- `Provider`: Renamed to `SessionProvider`
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.12
## `SessionProvider`
Version 4 makes using the `SessionProvider` mandatory. This means that you will have to wrap any part of your application using `useSession` in this provider, if you were not doing so already. The `SessionProvider` has also undergone a few further changes:
- `Provider` is renamed to `SessionProvider`
- The options prop is now flattened as the props of SessionProvider.
- `keepAlive` has been renamed to `refetchInterval`.
- `clientMaxAge` has been removed in favor of `refetchInterval`, as they overlap in functionality, with the difference that `refetchInterval` will keep re-fetching the session periodically in the background.
The best practice for wrapping your app in Providers is to do so in your `pages/_app.jsx` file.
An example use-case with these new changes:
```jsx
import { SessionProvider } from "next-auth/react"
export default function App({
Component,
pageProps: { session, ...pageProps },
}) {
return (
// `session` comes from `getServerSideProps` or `getInitialProps`.
// Avoids flickering/session loading on first load.
<SessionProvider session={session} refetchInterval={5 * 60}>
<Component {...pageProps} />
</SessionProvider>
)
}
```
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.12
## Providers
Providers now need to be imported individually.
```diff
- import Provider from "next-auth/providers"
- Providers.Auth0({...})
- Providers.Google({...})
+ import Auth0Provider from "next-auth/providers/auth0"
+ import GoogleProvider from "next-auth/providers/google"
+ Auth0Provider({...})
+ GoogleProvider({...})
```
1. The `AzureADB2C` provider has been renamed `AzureAD`.
2. The `Basecamp` provider has been removed, see explanation [here](https://github.com/basecamp/api/blob/master/sections/authentication.md#on-authenticating-users-via-oauth).
3. The GitHub provider by default now will not request full write access to user profiles. If you need this scope, please add `user` to the scope option manually.
The following new options are available when defining your Providers in the configuration:
1. `authorization` (replaces `authorizationUrl`, `authorizationParams`, `scope`)
2. `token` replaces (`accessTokenUrl`, `headers`, `params`)
3. `userinfo` (replaces `profileUrl`)
4. `issuer`(replaces `domain`)
For more details on their usage, please see [options](/reference/providers/oauth) section of the OAuth Provider documentation.
When submitting a new OAuth provider to the repository, the `profile` callback is expected to only return these fields from now on: `id`, `name`, `email`, and `image`. If any of these are missing values, they should be set to `null`.
Also worth noting is that `id` is expected to be returned as a `string` type (For example if your provider returns it as a number, you can cast it by using the `.toString()` method). This makes the returned profile object comply across all providers/accounts/adapters, and hopefully cause less confusion in the future.
Implemented in: https://github.com/nextauthjs/next-auth/pull/2411
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.20
## `useSession` Hook
The `useSession` hook has been updated to return an object. This allows you to test states much more cleanly with the new `status` option.
```diff
- const [ session, loading ] = useSession()
+ const { data: session, status } = useSession()
+ const loading = status === "loading"
```
[Check the docs](/reference/react/#usesession) for the possible values of both `session.status` and `session.data`.
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.18
## Named Parameters
We have changed the arguments to our callbacks to the named parameters pattern. This way you don't have to use dummy `_` placeholders or other tricks.
### Callbacks
The signatures for the callback methods now look like this:
```diff
- signIn(user, account, profileOrEmailOrCredentials)
+ signIn({ user, account, profile, email, credentials })
```
```diff
- redirect(url, baseUrl)
+ redirect({ url, baseUrl })
```
```diff
- session(session, tokenOrUser)
+ session({ session, token, user })
```
```diff
- jwt(token, user, account, OAuthProfile, isNewUser)
+ jwt({ token, user, account, profile, isNewUser })
```
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.17
### Events
Two event signatures have changed to also use the named parameters pattern, `signOut` and `updateUser`.
```diff
// [...nextauth].js
...
events: {
- signOut(tokenOrSession),
+ signOut({ token, session }), // token if using JWT, session if DB persisted sessions.
- updateUser(user)
+ updateUser({ user })
}
```
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.20
## JWT configuration
We have removed some of the [configuration options](/reference/configuration/auth-config) when using JSON Web Tokens, [here's the PR](https://github.com/nextauthjs/next-auth/pull/3039) for more context.
```diff
export default NextAuth({
// ...
jwt: {
secret,
maxAge,
- encryptionKey
- signingKey
- encryptionKey
- verificationOptions
encode({
token
secret
maxAge
- signingKey
- signingOptions
- encryptionKey
- encryptionOptions
- encryption
}) {},
decode({
token
secret
- maxAge
- signingKey
- verificationKey
- verificationOptions
- encryptionKey
- decryptionKey
- decryptionOptions
- encryption
}) {}
}
})
```
## Logger API
The logger API has been simplified to use at most two parameters, where the second is usually an object (`metadata`) containing an `error` object. If you are not using the logger settings you can ignore this change.
```diff
// [...Auth.js]
import log from "some-logger-service"
...
logger: {
- error(code, ...message) {},
+ error(code, metadata) {},
- warn(code, ...message) {},
+ warn(code) {}
- debug(code, ...message) {}
+ debug(code, metadata) {}
}
```
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.19
## `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`](/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
## Theme
We have added some basic customization options to our built-in pages like `signin`, `signout`, etc.
These can be set under the `theme` configuration key. This used to be a string which only controlled the color scheme option. Now it is an object with the following options:
```js
theme: {
colorScheme: "auto", // "auto" | "dark" | "light"
brandColor: "", // Hex color value
logo: "" // Absolute URL to logo image
}
```
The hope is that with some minimal configuration / customization options, users won't immediately feel the need to replace the built-in pages with their own.
More details and screenshots of the new theme options can be found under [custom pages tutorial](/guides/basics/pages).
Introduced in https://github.com/nextauthjs/next-auth/pull/2788
## Session
The `session.jwt: boolean` option has been renamed to `session.strategy: "jwt" | "database"`. The goal is to make the user's options more intuitive:
1. No adapter, `strategy: "jwt"`: This is the default. The session is saved in a cookie and never persisted anywhere.
2. With Adapter, `strategy: "database"`: If an Adapter is defined, this will be the implicit setting. No user config is needed.
3. With Adapter, `strategy: "jwt"`: The user can explicitly instruct `next-auth` to use JWT even if a database is available. This can result in faster lookups in compromise of lowered security. Read more about: https://authjs.dev/concepts/faq#json-web-tokens
Example:
```diff
session: {
- jwt: true,
+ strategy: "jwt",
}
```
Introduced in https://github.com/nextauthjs/next-auth/pull/3144
## Adapters
Most importantly, the core `next-auth` package no longer ships with `typeorm` or any other database adapter by default. This brings the default bundle size down significantly for those not needing to persist user data to a database.
You can find the official Adapters in the `packages` directory in the primary monorepo ([nextauthjs/next-auth](https://github.com/nextauthjs/next-auth)). Although you can still [create your own](/guides/adapters/creating-a-database-adapter) with a new, [simplified Adapter API](https://github.com/nextauthjs/next-auth/pull/2361).
If you have a database that was created with a `3.x.x` or earlier version of Auth.js, you will need to run a migration to update the schema to the new version 4 database model. See the bottom of this migration guide for database specific migration examples.
1. If you use the built-in TypeORM or Prisma adapters, these have been removed from the core `next-auth` package. Thankfully the migration is easy; you just need to install the external packages for your database and change the import in your `[...nextauth].js`.
The `database` option has been removed, you must now do the following instead:
```diff
// [...nextauth].js
import NextAuth from "next-auth"
+ import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
...
export default NextAuth({
- database: "yourconnectionstring",
+ adapter: TypeORMLegacyAdapter("yourconnectionstring")
})
```
2. The `prisma-legacy` adapter has been removed, please use the [`@next-auth/prisma-adapter`](https://npmjs.com/package/@next-auth/prisma-adapter) instead.
3. The `typeorm-legacy` adapter has been upgraded to use the newer adapter API, but has retained the `typeorm-legacy` name. We aim to migrate this to individual lighter weight adapters for each database type in the future, or switch out `typeorm`.
4. MongoDB has been moved to its own adapter under `@next-auth/mongodb-adapter`. See the [MongoDB Adapter docs](/reference/adapters/mongodb).
Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.8 and https://github.com/nextauthjs/next-auth/pull/2361
### Adapter API
**This does not require any changes from the user - these are adapter specific changes only**
The Adapter API has been rewritten and significantly simplified in NextAuth v4. The adapters now have less work to do as some functionality has been migrated to the core of NextAuth, like hashing the [verification token](/reference/adapters/models/#verification-token).
If you are an adapter maintainer or are interested in writing your own adapter, you can find more information about this change in https://github.com/nextauthjs/next-auth/pull/2361 and release https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.22.
### Schema changes
The way we save data with adapters have slightly changed. With the new Adapter API, we wanted to make it easier to extend your database with additional fields. For example if your User needs an extra `phone` field, it should be enough to add that to your database's schema, and no changes will be necessary in your adapter.
- `created_at`/`createdAt` and `updated_at`/`updatedAt` fields are removed from all Models.
- `user_id`/`userId` consistently named `userId`.
- `compound_id`/`compoundId` is removed from Account.
- `access_token`/`accessToken` is removed from Session.
- `email_verified`/`emailVerified` on User is consistently named `emailVerified`.
- `provider_id`/`providerId` renamed to `provider` on Account
- `provider_type`/`providerType` renamed to `type` on Account
- `provider_account_id`/`providerAccountId` on Account is consistently named `providerAccountId`
- `access_token_expires`/`accessTokenExpires` on Account renamed to `expires_at`
- New fields on Account: `token_type`, `scope`, `id_token`, `session_state`
- `verification_requests` table has been renamed to `verification_tokens`
<!-- REVIEW: Would something like this below be helpful? -->
<details>
<summary>
See the changes
</summary>
<pre>
```diff
User {
id
name
email
- emailVerified
+ email_verified
image
- created_at
- updated_at
}
Account {
id
- compound_id
- user_id
+ userId
- provider_type
+ type
- provider_id
+ provider
- provider_account_id
+ providerAccountId
refresh_token
access_token
- access_token_expires
+ expires_in
+ expires_at
+ token_type
+ scope
+ id_token
+ session_state
- created_at
- updated_at
}
Session {
id
userId
expires
sessionToken
- access_token
- created_at
- updated_at
}
VerificationToken {
id
token
expires
identifier
- created_at
- updated_at
}
```
</pre>
</details>
For more info, see the [Models page](/reference/adapters/models).
### Database migration
Auth.js v4 has a slightly different database schema compared to v3. If you're using any of our adapters and want to upgrade, you can use on of the below schemas.
They are designed to be run directly against the database itself. So instead of having one in Prisma syntax, one in TypeORM syntax, etc. we've decided to just make one for each underlying database type. i.e. one for Postgres, one for MySQL, one for MongoDB, etc.
#### MySQL
```sql
/* ACCOUNT */
ALTER TABLE accounts
CHANGE "access_token_expires" "expires_at" int
CHANGE "user_id" "userId" varchar(255)
ADD CONSTRAINT fk_user_id FOREIGN KEY (userId) REFERENCES users(id)
RENAME COLUMN "provider_id" "provider"
RENAME COLUMN "provider_account_id" "providerAccountId"
DROP COLUMN "provider_type"
DROP COLUMN "compound_id"
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
ADD COLUMN "token_type" varchar(255) NULL
ADD COLUMN "scope" varchar(255) NULL
ADD COLUMN "id_token" varchar(255) NULL
ADD COLUMN "session_state" varchar(255) NULL
/* Note: These are only needed if you're going to be using the old Twitter OAuth 1.0 provider. */
ADD COLUMN "oauth_token_secret" varchar(255) NULL
ADD COLUMN "oauth_token" varchar(255) NULL
/* USER */
ALTER TABLE users
RENAME COLUMN "email_verified" "emailVerified"
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
/* SESSION */
ALTER TABLE sessions
RENAME COLUMN "session_token" "sessionToken"
CHANGE "user_id" "userId" varchar(255)
ADD CONSTRAINT fk_user_id FOREIGN KEY (userId) REFERENCES users(id)
DROP COLUMN "access_token"
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
/* VERIFICATION REQUESTS */
ALTER TABLE verification_requests RENAME verification_tokens
ALTER TABLE verification_tokens
DROP COLUMN id
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
DROP COLUMN "created_at"
DROP COLUMN "updated_at"
```
#### Postgres
```sql
/* ACCOUNT */
ALTER TABLE accounts RENAME COLUMN "user_id" TO "userId";
ALTER TABLE accounts RENAME COLUMN "provider_id" TO "provider";
ALTER TABLE accounts RENAME COLUMN "provider_account_id" TO "providerAccountId";
ALTER TABLE accounts RENAME COLUMN "access_token_expires" TO "expires_at";
ALTER TABLE accounts RENAME COLUMN "provider_type" TO "type";
/* Do conversion of TIMESTAMPTZ to BIGINT */
ALTER TABLE accounts ALTER COLUMN "expires_at" TYPE TEXT USING CAST(extract(epoch FROM "expires_at") AS BIGINT)*1000;
/* Keep id as SERIAL with autoincrement when using ORM. Using new v4 uuid format won't work because of incompatibility */
/* ALTER TABLE accounts ALTER COLUMN "id" TYPE TEXT; */
/* ALTER TABLE accounts ALTER COLUMN "userId" TYPE TEXT; */
ALTER TABLE accounts ALTER COLUMN "type" TYPE TEXT;
ALTER TABLE accounts ALTER COLUMN "provider" TYPE TEXT;
ALTER TABLE accounts ALTER COLUMN "providerAccountId" TYPE TEXT;
ALTER TABLE accounts ADD CONSTRAINT fk_user_id FOREIGN KEY ("userId") REFERENCES users(id);
ALTER TABLE accounts
DROP COLUMN IF EXISTS "compound_id";
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
ALTER TABLE accounts
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
ALTER TABLE accounts
ADD COLUMN IF NOT EXISTS "token_type" TEXT NULL,
ADD COLUMN IF NOT EXISTS "scope" TEXT NULL,
ADD COLUMN IF NOT EXISTS "id_token" TEXT NULL,
ADD COLUMN IF NOT EXISTS "session_state" TEXT NULL;
/* Note: These are only needed if you're going to be using the old Twitter OAuth 1.0 provider. */
/* ALTER TABLE accounts
ADD COLUMN IF NOT EXISTS "oauth_token_secret" TEXT NULL,
ADD COLUMN IF NOT EXISTS "oauth_token" TEXT NULL; */
/* USER */
ALTER TABLE users RENAME COLUMN "email_verified" TO "emailVerified";
/* Keep id as SERIAL with autoincrement when using ORM. Using new v4 uuid format won't work because of incompatibility */
/* ALTER TABLE users ALTER COLUMN "id" TYPE TEXT; */
ALTER TABLE users ALTER COLUMN "name" TYPE TEXT;
ALTER TABLE users ALTER COLUMN "email" TYPE TEXT;
ALTER TABLE users ALTER COLUMN "image" TYPE TEXT;
/* Do conversion of TIMESTAMPTZ to BIGINT and then TEXT */
ALTER TABLE users ALTER COLUMN "emailVerified" TYPE TEXT USING CAST(CAST(extract(epoch FROM "emailVerified") AS BIGINT)*1000 AS TEXT);
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
ALTER TABLE users
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
/* SESSION */
ALTER TABLE sessions RENAME COLUMN "session_token" TO "sessionToken";
ALTER TABLE sessions RENAME COLUMN "user_id" TO "userId";
/* Keep id as SERIAL with autoincrement when using ORM. Using new v4 uuid format won't work because of incompatibility */
/* ALTER TABLE sessions ALTER COLUMN "id" TYPE TEXT; */
/* ALTER TABLE sessions ALTER COLUMN "userId" TYPE TEXT; */
ALTER TABLE sessions ALTER COLUMN "sessionToken" TYPE TEXT;
ALTER TABLE sessions ADD CONSTRAINT fk_user_id FOREIGN KEY ("userId") REFERENCES users(id);
/* Do conversion of TIMESTAMPTZ to BIGINT and then TEXT */
ALTER TABLE sessions ALTER COLUMN "expires" TYPE TEXT USING CAST(CAST(extract(epoch FROM "expires") AS BIGINT)*1000 AS TEXT);
ALTER TABLE sessions DROP COLUMN IF EXISTS "access_token";
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
ALTER TABLE sessions
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
/* VERIFICATION REQUESTS */
ALTER TABLE verification_requests RENAME TO verification_tokens;
/* Keep id as ORM needs it */
/* ALTER TABLE verification_tokens DROP COLUMN IF EXISTS id; */
ALTER TABLE verification_tokens ALTER COLUMN "identifier" TYPE TEXT;
ALTER TABLE verification_tokens ALTER COLUMN "token" TYPE TEXT;
/* Do conversion of TIMESTAMPTZ to BIGINT and then TEXT */
ALTER TABLE verification_tokens ALTER COLUMN "expires" TYPE TEXT USING CAST(CAST(extract(epoch FROM "expires") AS BIGINT)*1000 AS TEXT);
/* The following two timestamp columns have never been necessary for Auth.js to function, but can be kept if you want */
ALTER TABLE verification_tokens
DROP COLUMN IF EXISTS "created_at",
DROP COLUMN IF EXISTS "updated_at";
```
#### MongoDB
MongoDB is a document database and as such new fields will be automatically populated. You do, however, need to update the names of existing fields which are going to be reused.
```mongo
db.getCollection('accounts').updateMany({}, {
$rename: {
"provider_id": "provider",
"provider_account_id": "providerAccountId",
"user_id": "userId",
"access_token_expires": "expires_at"
}
})
db.getCollection('users').updateMany({}, {
$rename: {
"email_verified": "emailVerified"
}
})
db.getCollection('sessions').updateMany({}, {
$rename: {
"session_token": "sessionToken",
"user_id": "userId"
}
})
```
## Missing `secret`
Auth.js used to generate a secret for convenience, when the user did not define one. This might have been useful in development, but can be a concern in production. We have always been clear about that in the docs, but from now on, if you forget to define a `secret` property in production, we will show the user an error page. Read more about this option [here](/reference/configuration/auth-config#secret)
You can generate a secret to be placed in the `secret` configuration option via the following command:
```bash
$ openssl rand -base64 32
```
Therefore, your Auth.js config should look something like this:
```javascript title="/pages/api/auth/[...nextauth].js"
...
export default NextAuth({
...
providers: [...],
secret: "LlKq6ZtYbr+hTC073mAmAh9/h2HwMfsFo4hrfCx5mLg=",
...
})
```
Introduced in https://github.com/nextauthjs/next-auth/issues/3143
## Session `strategy`
We have always supported two different session strategies. The first being our most popular and default strategy - the JWT based one. The second is the database adapter persisted session strategy. Both have their advantages/disadvantages, you can learn more about them on the [FAQ](/concepts/faq) page.
Previously, the way you configured this was through the `jwt: boolean` flag in the `session` option. The names `session` and `jwt` might have been a bit overused in the options, and so for a clearer message, we renamed this option to `strategy: "jwt" | "database"`, it is still in the `session` object. This will hopefully better indicate the purpose of this option as well as make very explicit which type of session you are going to use.
See the [`session` option docs](/reference/configuration/auth-config#session) for more details.
Introduced in https://github.com/nextauthjs/next-auth/pull/3144
## Summary
We hope this migration goes smoothly for each and every one of you! If you have any questions or get stuck anywhere, feel free to create [a new issue](https://github.com/nextauthjs/next-auth/issues/new) on GitHub.

View File

@@ -0,0 +1,5 @@
{
"label": "Adapters",
"collapsible": true,
"collapsed": true
}

View File

@@ -1,15 +1,13 @@
---
title: Using a Database Adapter
title: Using a database adapter
---
import { Callout } from 'nextra-theme-docs'
An **Adapter** in Auth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc. Adapters are optional, unless you need to persist user information in your own database, or you want to implement certain flows. The [Email Provider](/getting-started/email-tutorial) requires an adapter to be able to save [Verification Tokens](/reference/adapters/models#verification-token).
<Callout>
:::tip
When using a database, you can still use JWT for session handling for fast access. See the [`session.strategy`](/reference/configuration/auth-config#session) option. Read about the trade-offs of JWT in the [FAQ](/concepts/faq#json-web-tokens).
</Callout>
:::
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)

View File

@@ -0,0 +1,5 @@
{
"label": "Basics",
"collapsible": true,
"collapsed": false
}

View File

@@ -2,18 +2,13 @@
title: Callbacks
---
import { Callout } from "nextra-theme-docs"
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.
<Callout>
If you want to pass data such as an Access Token or User ID to the browser
when using JSON Web Tokens, you can persist the data in the token when the
`jwt` callback is called, then pass the data through to the browser in the
`session` callback.
</Callout>
:::tip
If you want to pass data such as an Access Token or User ID to the browser when using JSON Web Tokens, you can persist the data in the token when the `jwt` callback is called, then pass the data through to the browser in the `session` callback.
:::
You can specify a handler for any of the callbacks below.
@@ -64,19 +59,17 @@ callbacks: {
* When using the **Credentials Provider** the `user` object is the response returned from the `authorize` callback and the `profile` object is the raw body of the `HTTP POST` submission.
<Callout>
:::note
When using Auth.js with a database, the User object will be either a user object from the database (including the User ID) if the user has signed in before or a simpler prototype user object (i.e. name, email, image) for users who have not signed in before.
When using Auth.js without a database, the user object will always be a prototype user object, with information extracted from the profile.
:::
</Callout>
<Callout>
:::note
Redirects returned by this callback cancel the authentication flow. Only redirect to error pages that, for example, tell the user why they're not allowed to sign in.
To redirect to a page after a successful sign in, please use [the `callbackUrl` option](/reference/utilities/#specifying-a-callbackurl) or [the redirect callback](/reference/configuration/auth-config#callbacks).
</Callout>
:::
## Redirect callback
@@ -98,9 +91,9 @@ callbacks: {
}
```
<Callout>
The redirect callback may be invoked more than once in the same flow.
</Callout>
:::note
The redirect callback may be invoked more than once in the same flow.
:::
## JWT callback
@@ -126,13 +119,9 @@ callbacks: {
}
```
<Callout>
Use an if branch to check for the existence of parameters (apart from
`token`). If they exist, this means that the callback is being invoked for the
first time (i.e. the user is being signed in). This is a good place to persist
additional data like an `access_token` in the JWT. Subsequent invocations will
only contain the `token` parameter.
</Callout>
:::tip
Use an if branch to check for the existence of parameters (apart from `token`). If they exist, this means that the callback is being invoked for the first time (i.e. the user is being signed in). This is a good place to persist additional data like an `access_token` in the JWT. Subsequent invocations will only contain the `token` parameter.
:::
## Session callback
@@ -153,18 +142,15 @@ callbacks: {
}
```
<Callout>
When using JSON Web Tokens the `jwt()` callback is invoked before the
`session()` callback, so anything you add to the JSON Web Token will be
immediately available in the session callback, like for example an
`access_token` from a provider.
</Callout>
:::tip
When using JSON Web Tokens the `jwt()` callback is invoked before the `session()` callback, so anything you add to the
JSON Web Token will be immediately available in the session callback, like for example an `access_token` from a provider.
:::
<Callout type="warning">
:::warning
The session object is not persisted server side, even when using database sessions - only data such as the session token, the user, and the expiry time is stored in the session table.
If you need to persist session data server side, you can use the `accessToken` returned for the session as a key - and connect to the database in the `session()` callback to access it. Session `accessToken` values do not rotate and are valid as long as the session is valid.
If using JSON Web Tokens instead of database sessions, you should use the User ID or a unique key stored in the token (you will need to generate a key for this yourself on sign in, as access tokens for sessions are not generated when using JSON Web Tokens).
</Callout>
:::

View File

@@ -0,0 +1,72 @@
---
title: Deployment
---
Deploying Auth.js only requires a few steps. It can be run anywhere a Next.js application can. Therefore, in a default configuration using only JWT session strategy, i.e. without a database, you will only need these few things in addition to your application:
1. Auth.js environment variables
- `NEXTAUTH_SECRET`
- `NEXTAUTH_URL`
2. Auth.js API Route and its configuration (`/pages/api/auth/[...nextauth].js`).
- OAuth Provider `clientId` / `clientSecret`
Deploying a modern JavaScript application using Auth.js consists of making sure your environment variables are set correctly as well as the configuration in the Auth.js API route is setup, as well as any configuration (like Callback URLs, etc.) are correctly done in your OAuth provider(s) themselves.
See below for more detailed provider settings.
## Vercel
1. Make sure to expose the Vercel [System Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables#system-environment-variables) in your project settings. This way, we can detect the environment. (Setting `NEXTAUTH_URL` environment variable on Vercel is **unnecessary**).
2. Create a `NEXTAUTH_SECRET` environment variable for both Production and Preview environments.
a. You can use `openssl rand -base64 32` or https://generate-secret.vercel.app/32 to generate a random value.
3. Add your provider's client ID and client secret to environment variables. _(Skip this step if not using an [OAuth Provider](/reference/providers/index))_
4. Deploy!
Example repository: https://github.com/nextauthjs/next-auth-example
A few notes about deploying to Vercel. The environment variables are read server-side, so you **should not** prefix them with `NEXT_PUBLIC_` to avoid accidentally bundling a secret in the client-side JavaScript code.
### Securing a preview deployment
Most OAuth providers cannot be configured with multiple callback URLs or using a wildcard.
However, Auth.js **supports Preview deployments**, even **with OAuth providers**:
1. Determine a stable deployment URL. Eg.: A deployment whose URL does not change between builds, for example. `auth.yourdomain.com`),
2. Set `AUTH_REDIRECT_PROXY_URL` to that URL, adding the path up until your `[...nextauth]` route. Eg.: (`https://auth.yourdomain.com/api/auth`)
3. For your OAuth provider, set the callback URL using the stable deployment URL. Eg.: For GitHub `https://auth.yourdomain.com/api/auth/callback/github`)
:::info
To support preview deployments, the `AUTH_SECRET` value needs to be the same for the stable deployment and deployments that will need OAuth support.
:::
<details>
<summary>
<b>How does this work?</b>
</summary>
To support preview deployments, Auth.js uses the stable deployment URL as a redirect proxy server.
It will redirect the OAuth callback request to the preview deployment URL, but only when the `AUTH_REDIRECT_PROXY_URL` environment variable is set. The stable deployment can still act as a regular app.
When a user initiates an OAuth sign-in flow on a preview deployment, we save its URL in the `state` query parameter but set the `redirect_uri` to the stable deployment.
Then, the OAuth provider will redirect the user to the stable deployment, which then will verify the `state` parameter and redirect the user to the preview deployment URL if the `state` is valid. This is secured by relying on the same server-side `AUTH_SECRET` for the stable deployment and the preview deployment.
See also:
<ul>
<li><a href="https://www.ietf.org/rfc/rfc6749.html#section-4.1.1">OAuth 2.0 specification: `state` query parameter</a></li>
</ul>
</details>
## Netlify
Netlify is very similar to Vercel in that you can deploy a Next.js project without almost any extra work.
To set up Auth.js correctly here, you will want to make sure you add your `NEXTAUTH_SECRET` environment variable in the project settings. If you are using the [Essential Next.js Build Plugin](https://github.com/netlify/netlify-plugin-nextjs) within your project, you **do not** need to set the `NEXTAUTH_URL` environment variable as it is set automatically as part of the build process.
Netlify also exposes some [system environment variables](https://docs.netlify.com/configure-builds/environment-variables/) from which you can check which `NODE_ENV` you are currently in and much more.
After this, make sure you either have your OAuth provider set up correctly with `clientId` / `clientSecret`'s and callback URLs.

View File

@@ -2,15 +2,13 @@
title: Events
---
import { Callout } from 'nextra-theme-docs'
Events are asynchronous functions that do not return a response, they are useful for audit logs / reporting or handling any other side-effects.
You can specify a handler for any of these events below, for debugging or for an audit log.
<Callout>
:::note
The execution of your authentication API will be blocked by an `await` on your event handler. If your event handler starts any burdensome work it should not block its own promise on that work.
</Callout>
:::
## Events

View File

@@ -2,8 +2,6 @@
title: Custom Initialization
---
import { Callout } from 'nextra-theme-docs'
In Next.js, you can define an API route that will catch all requests that begin with a certain path. Conveniently, this is called [Catch all API routes](https://nextjs.org/docs/api-routes/dynamic-api-routes#catch-all-api-routes).
When you define a `/pages/api/auth/[...nextauth]` JS/TS file, you instruct Auth.js that every API request beginning with `/api/auth/*` should be handled by the code written in the `[...nextauth]` file.
@@ -48,15 +46,15 @@ The `...` section will still be your [options](/reference/configuration/auth-con
You could for example log the request, add headers, read `query` or `body` parameters, whatever you would do in an API route.
<Callout>
:::tip
Since this is a catch-all route, remember to check what kind of Auth.js "action" is running. Compare the REST API with the `req.query.nextauth` parameter.
For example to execute something on the "callback" action when the request is a POST method, you can check for `req.query.nextauth.includes("callback") && req.method === "POST"`
</Callout>
:::
<Callout>
:::note
`NextAuth` will implicitly close the response (by calling `res.end`, `res.send` or similar), so you should not run code **after** `NextAuth` in the function body. Using `return NextAuth` makes sure you don't forget that.
</Callout>
:::
Any variable you create this way will be available in the `NextAuth` options as well, since they are in the same scope.
@@ -119,6 +117,6 @@ For more details on all available actions and which methods are supported, pleas
This way of initializing `NextAuth` is very powerful, but should be used sparingly.
<Callout type="warning">
:::warning
Changing parts of the request that is essential to `NextAuth` to do it's job - like messing with the [default cookies](/reference/configuration/auth-config#cookies) - can have unforeseen consequences, and have the potential to introduce security holes if done incorrectly. Only change those if you understand consequences.
</Callout>
:::

View File

@@ -3,11 +3,9 @@ title: Override JWT `encode` and `decode` methods
sidebar_label: Custom JWT encoding
---
import { Callout } from "nextra-theme-docs"
<Callout type="warning">
:::warning
If you use middleware to protect routes, make sure the same method is also set in the [`_middleware.ts` options](/reference/nextjs/#custom-jwt-decode-method)
</Callout>
:::
Auth.js uses encrypted JSON Web Tokens ([JWE](https://datatracker.ietf.org/doc/html/rfc7516)) by default. Unless you have a good reason, we recommend keeping this behaviour. Although you can override this using the `encode` and `decode` methods. Both methods must be defined at the same time.

View File

@@ -2,8 +2,6 @@
title: Pages
---
import { Callout } from 'nextra-theme-docs'
Auth.js automatically creates simple, unbranded authentication pages for handling Sign in, Sign out, Email Verification and displaying error messages.
The options displayed on the sign-up page are automatically generated based on the providers specified in the options passed to Auth.js.
@@ -22,9 +20,9 @@ To add a custom login page, you can use the `pages` option:
...
```
<Callout>
:::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`.
</Callout>
:::
## Error codes
@@ -178,6 +176,6 @@ You can also use the `signIn()` function which will handle obtaining the CSRF to
signIn("credentials", { username: "jsmith", password: "1234" })
```
<Callout type="info">
:::tip
Remember to put any custom pages in a folder outside **/pages/api** which is reserved for API code. As per the examples above, a location convention suggestion is `pages/auth/...`.
</Callout>
:::

View File

@@ -2,14 +2,11 @@
title: Refresh token rotation
---
import { Callout } from "nextra-theme-docs"
Refresh token rotation is the practice of updating an `access_token` on behalf of the user, without requiring interaction (eg.: re-sign in). `access_token`s are usually issued for a limited time. After they expire, the service verifying them will ignore the value. Instead of asking the user to sign in again to obtain a new `access_token`, certain providers support exchanging a `refresh_token` for a new `access_token`, renewing the expiry time. Let's see how this can be achieved.
<Callout>
Our goal is to add zero-config support for built-in providers eventually. Let
us know if you would like to help.
</Callout>
:::note
Our goal is to add zero-config support for built-in providers eventually. Let us know if you would like to help.
:::
## Implementation
@@ -19,15 +16,13 @@ First, make sure that the provider you want to use supports `refresh_token`'s. C
Depending on the session strategy, `refresh_token` can be persisted either in a database, or in a cookie, in an encrypted JWT.
<Callout type="info">
Using a JWT to store the `refresh_token` is less secure than saving it in a
database, and you need to evaluate based on your requirements which strategy
you choose.
</Callout>
:::info
Using a JWT to store the `refresh_token` is less secure than saving it in a database, and you need to evaluate based on your requirements which strategy you choose.
:::
#### JWT strategy
Using the [jwt](../../reference/03-core/interfaces/types.CallbacksOptions.md#jwt) and [session](../../reference/03-core/interfaces/types.CallbacksOptions.md#session) callbacks, we can persist OAuth tokens and refresh them when they expire.
Using the [jwt](../../reference/core/types#jwt) and [session](../../reference/core/types#session) callbacks, we can persist OAuth tokens and refresh them when they expire.
Below is a sample implementation using Google's Identity Provider. Please note that the OAuth 2.0 request in the `refreshAccessToken()` function will vary between different providers, but the core logic should remain similar.
@@ -50,10 +45,10 @@ export default Auth(new Request("https://example.com"), {
// Save the access token and refresh token in the JWT on the initial login
return {
access_token: account.access_token,
expires_at: Date.now() + account.expires_in * 1000,
expires_at: Math.floor(Date.now() / 1000 + account.expires_in),
refresh_token: account.refresh_token,
}
} else if (Date.now() < token.expires_at) {
} else if (Date.now() < token.expires_at * 1000) {
// If the access token has not expired yet, return it
return token
} else {
@@ -79,7 +74,7 @@ export default Auth(new Request("https://example.com"), {
return {
...token, // Keep the previous token properties
access_token: tokens.access_token,
expires_at: Date.now() + tokens.expires_in * 1000,
expires_at: Math.floor(Date.now() / 1000 + tokens.expires_in),
// Fall back to old refresh token, but note that
// many providers may only allow using a refresh token once.
refresh_token: tokens.refresh_token ?? token.refresh_token,
@@ -141,7 +136,7 @@ export default Auth(new Request("https://example.com"), {
const [google] = await prisma.account.findMany({
where: { userId: user.id, provider: "google" },
})
if (google.expires_at >= Date.now()) {
if (google.expires_at * 1000 < Date.now()) {
// If the access token has expired, try to refresh it
try {
// https://accounts.google.com/.well-known/openid-configuration
@@ -164,7 +159,7 @@ export default Auth(new Request("https://example.com"), {
await prisma.account.update({
data: {
access_token: tokens.access_token,
expires_at: Date.now() + tokens.expires_in * 1000,
expires_at: Math.floor(Date.now() / 1000 + tokens.expires_in),
refresh_token: tokens.refresh_token ?? google.refresh_token,
},
where: {
@@ -227,3 +222,4 @@ return (...)
## Source Code
A working example can be accessed [here](https://github.com/nextauthjs/next-auth-refresh-token-example).

View File

@@ -0,0 +1,153 @@
---
title: Role-based access control
---
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
We are going to start by adding a `profile()` callback to the providers' config to determine the user role:
```ts title="/pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
export default NextAuth({
providers: [
Google({
profile(profile) {
return { role: profile.role ?? "user", ... }
},
...
})
],
})
```
:::tip
To determine the user's role, you can either add your logic or if your provider assigns roles already, use that instead.
:::
## Persisting the role
### With JWT
When you don't have a database configured, the role will be persisted in a cookie, by using the `jwt()` callback. On sign-in, the `role` property is exposed from the `profile` callback on the `user` object. Persist the `user.role` value by assigning it to `token.role`. That's it!
If you also want to use the role on the client, you can expose it via the `session` callback.
```ts title="/pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
export default NextAuth({
providers: [
Google({
profile(profile) {
return { role: profile.role ?? "user", ... }
},
...
})
],
// highlight-start
callbacks: {
jwt({ token, user }) {
if(user) token.role = user.role
return token
},
session({ session, token }) {
session.user.role = token.role
return session
}
}
// highlight-end
})
```
:::info
With this strategy, if you want to update the role, the user needs to be forced to sign in again.
:::
### With Database
When you have a database, you can save the user role on the [User model](/reference/adapters/models#user). The below example is showing you how to do this with Prisma, but the idea is the same for all adapters.
First, add a `role` column to the User model.
```ts title="/prisma/schema.prisma"
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
role String? // New column
accounts Account[]
sessions Session[]
}
```
The `profile()` callback's return value is used to create users in the database. That's it! Your newly created users will now have an assigned role.
If you also want to use the role on the client, you can expose it via the `session` callback.
```ts title="/pages/api/auth/[...nextauth].ts"
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
// highlight-next-line
import prisma from "lib/prisma"
export default NextAuth({
// highlight-next-line
adapter: PrismaAdapter(prisma),
providers: [
Google({
profile(profile) {
return { role: profile.role ?? "user", ... }
}
...
})
],
// highlight-start
callbacks: {
session({ session, user }) {
session.user.role = user.role
return session
}
}
// highlight-end
})
```
:::info
It is up to you how you want to manage to update the roles, either through direct database access or building your role update API.
:::
## Using the role
If you want to use the role in the client, for both cases above, when using the `useSession` hook, `session.user.role` will have the required role if you exposed it via the `session` callback. You can use this to render a different UI for different users.
```ts title="/pages/admin.tsx"
import { useSession } from "next-auth/react"
export default function Page() {
const session = await useSession()
if (session?.user.role === "admin") {
return <p>You are an admin, welcome!</p>
}
return <p>You are not authorized to view this page!</p>
}
```
:::tip
When using Next.js and JWT, you can alternatively also use [Middleware](https://next-auth.js.org/configuration/nextjs#wrap-middleware) to redirect the user based on their role, even before rendering the page.
:::
## Resources
- [Concepts: Session strategies](/concepts/session-strategies)
- [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)

View File

@@ -2,15 +2,13 @@
title: Securing Pages & API routes
---
import { Callout } from "nextra-theme-docs"
You can easily protect client and server side rendered pages and API routes with Auth.js.
_You can find working examples of the approaches shown below in the [example project](https://github.com/nextauthjs/next-auth-example/)._
<Callout>
:::tip
The methods `getSession()` and `getToken()` both return an `object` if a session is valid and `null` if a session is invalid or has expired.
</Callout>
:::
## Securing Pages
@@ -93,7 +91,7 @@ export async function getServerSideProps(context) {
}
```
<Callout>
:::tip
When you supply a `session` prop in `_app.js`, `useSession` won't show a loading state, as it'll already have the session available. In this way, you can provide a more seamless user experience.
```js title="pages/_app.js"
@@ -111,7 +109,7 @@ export default function App({
}
```
</Callout>
:::
## Securing API Routes
@@ -158,12 +156,12 @@ export default async (req, res) => {
}
```
<Callout>
:::tip
You can use the `getToken()` helper function in any application as long as you set the `NEXTAUTH_URL` environment variable and the application is able to read the JWT cookie (e.g. is on the same domain).
</Callout>
:::
<Callout>
:::note
Pass `getToken` the same value for `secret` as specified in `pages/api/auth/[...nextauth].js`.
See [the documentation for the JWT option](/reference/configuration/auth-config#jwt) for more information.
</Callout>
:::

View File

@@ -0,0 +1,5 @@
{
"label": "Corporate proxies",
"collapsible": true,
"collapsed": true
}

View File

@@ -2,18 +2,16 @@
title: Corporate proxy
---
import { Callout } from 'nextra-theme-docs'
Using Auth.js behind a corporate proxy is not supported out of the box. This is due to the fact that the underlying library we use, [`openid-client`](https://npm.im/openid-client) which uses the built-in Node.js `http` / `https` libraries, and those do not support proxys by default:
Using Auth.js behind a corporate proxy is not supported out of the box. This is due to the fact that the underlying library we use, [`openid-client`](https://npm.im/openid-client) which uses the built-in Node.js `http` / `https` libraries, and those do not support proxies by default:
- [`http` docs](https://nodejs.org/dist/latest-v18.x/docs/api/http.html)
- [`https` docs](https://nodejs.org/dist/latest-v18.x/docs/api/https.html)
Therefore, we'll need to add an additional proxy agent to the http client, such as `https-proxy-agent`.
<Callout type="info">
:::info
`openid-client` allows the user to set an `agent` for requests ([source](https://github.com/panva/node-openid-client/blob/main/docs/README.md#customizing-individual-http-requests)).
</Callout>
:::
Thanks to [raphaelpc](https://github.com/raphaelpc) for the below diff, which when applied to `v4.2.1`, adds this agent support to the `client.js` file.

12
docs/docs/guides/index.md Normal file
View File

@@ -0,0 +1,12 @@
---
title: Overview
sidebar_position: 0
---
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?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.
:::

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