mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
47 Commits
@next-auth
...
next-auth@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58e30a6af6 | ||
|
|
b7ff987baf | ||
|
|
782812a52b | ||
|
|
32f2a0cea3 | ||
|
|
3343ef18b2 | ||
|
|
6280fe9e10 | ||
|
|
52a2bf3e28 | ||
|
|
180c6252d9 | ||
|
|
362e981e6d | ||
|
|
5198eb19f7 | ||
|
|
0210cfccf3 | ||
|
|
e90925bea0 | ||
|
|
27a0b70d87 | ||
|
|
c676e93d8a | ||
|
|
f498e9cd0a | ||
|
|
2f3396d376 | ||
|
|
e62f879ebd | ||
|
|
f67959eb04 | ||
|
|
060953dacf | ||
|
|
30ad639d16 | ||
|
|
777da4302d | ||
|
|
733fd5f234 | ||
|
|
a787efc6be | ||
|
|
261968b9bb | ||
|
|
4dbbe5b2d9 | ||
|
|
d9df582fa8 | ||
|
|
af840b2106 | ||
|
|
ba89907d5a | ||
|
|
08eaeba79f | ||
|
|
c31eabfcc6 | ||
|
|
4423673424 | ||
|
|
281d0948b9 | ||
|
|
5246183c55 | ||
|
|
cb56cd44ca | ||
|
|
6758e1c6d1 | ||
|
|
462cca1087 | ||
|
|
ab48fcfe5b | ||
|
|
fe7aaeded8 | ||
|
|
c53c09ea5c | ||
|
|
4bcba45294 | ||
|
|
eb5a9bad9d | ||
|
|
9a6d95c17c | ||
|
|
5b2fc7b570 | ||
|
|
6f459225fa | ||
|
|
f38ee19a8a | ||
|
|
38a03ed7d8 | ||
|
|
e1eb684cc6 |
1
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
1
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
@@ -68,6 +68,7 @@ body:
|
||||
- "Slack"
|
||||
- "Spotify"
|
||||
- "Strava"
|
||||
- "Todoist"
|
||||
- "Trakt"
|
||||
- "Twitch"
|
||||
- "Twitter"
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
1
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -33,6 +33,7 @@ body:
|
||||
- "@next-auth/sequelize-adapter"
|
||||
- "@next-auth/typeorm-legacy-adapter"
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
- "@next-auth/xata-adapter"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
3
.github/issue-labeler.yml
vendored
3
.github/issue-labeler.yml
vendored
@@ -35,3 +35,6 @@ typeorm-legacy:
|
||||
|
||||
upstash-redis:
|
||||
- "@next-auth/upstash-redis-adapter"
|
||||
|
||||
xata:
|
||||
- "@next-auth/xata-adapter"
|
||||
|
||||
3
.github/pr-labeler.yml
vendored
3
.github/pr-labeler.yml
vendored
@@ -48,6 +48,9 @@ typeorm-legacy:
|
||||
upstash-redis:
|
||||
- packages/adapter-upstash-redis/**
|
||||
|
||||
xata:
|
||||
- packages/adapter-xata/**
|
||||
|
||||
core:
|
||||
- packages/next-auth/src/**/*
|
||||
|
||||
|
||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -2,7 +2,7 @@ name: Code Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, beta, next]
|
||||
branches: [beta, next]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
schedule:
|
||||
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
@@ -26,7 +26,6 @@ Anyone can be a contributor. Either you found a typo, or you have an awesome fea
|
||||
|
||||
A quick guide on how to setup _next-auth_ locally to work on it and test out any changes:
|
||||
|
||||
|
||||
1. Clone the repo:
|
||||
|
||||
```sh
|
||||
@@ -34,13 +33,21 @@ git clone git@github.com:nextauthjs/next-auth.git
|
||||
cd next-auth
|
||||
```
|
||||
|
||||
1. Install packages. Developing requires Node.js v16:
|
||||
2. Set up the correct pnpm version, using [Corepack](https://nodejs.org/api/corepack.html). Run the following in the project'a root:
|
||||
|
||||
```sh
|
||||
corepack enable pnpm
|
||||
```
|
||||
|
||||
(Now, if you run `pnpm --version`, it should print the same verion as the `packageManager` property in the [`package.json` file](https://github.com/nextauthjs/next-auth/blob/main/package.json))
|
||||
|
||||
3. Install packages. Developing requires Node.js v18:
|
||||
|
||||
```sh
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Populate `.env.local`:
|
||||
4. Populate `.env.local`:
|
||||
|
||||
Copy `apps/dev/.env.local.example` to `apps/dev/.env.local`, and add your env variables for each provider you want to test.
|
||||
|
||||
@@ -52,11 +59,12 @@ cp .env.local.example .env.local
|
||||
> NOTE: You can add any environment variables to .env.local that you would like to use in your dev app.
|
||||
> You can find the next-auth config under`apps/dev/pages/api/auth/[...nextauth].js`.
|
||||
|
||||
4. Start the developer application/server:
|
||||
5. Start the developer application/server:
|
||||
|
||||
```sh
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Your developer application will be available on `http://localhost:3000`
|
||||
|
||||
That's it! 🎉
|
||||
|
||||
12
apps/dev/app/layout.tsx
Normal file
12
apps/dev/app/layout.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html>
|
||||
<head></head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
6
apps/dev/app/server-component/page.tsx
Normal file
6
apps/dev/app/server-component/page.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await unstable_getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
}
|
||||
@@ -17,9 +17,7 @@ export default function Footer() {
|
||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/policy">
|
||||
<a>Policy</a>
|
||||
</Link>
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>{packageJSON.version}</em>
|
||||
|
||||
@@ -64,49 +64,31 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/">
|
||||
<a>Home</a>
|
||||
</Link>
|
||||
<Link href="/">Home</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/client">
|
||||
<a>Client</a>
|
||||
</Link>
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server">
|
||||
<a>Server</a>
|
||||
</Link>
|
||||
<Link href="/server">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">
|
||||
<a>Protected</a>
|
||||
</Link>
|
||||
<Link href="/protected">Protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected-ssr">
|
||||
<a>Protected(SSR)</a>
|
||||
</Link>
|
||||
<Link href="/protected-ssr">Protected(SSR)</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/api-example">
|
||||
<a>API</a>
|
||||
</Link>
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/credentials">
|
||||
<a>Credentials</a>
|
||||
</Link>
|
||||
<Link href="/credentials">Credentials</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/email">
|
||||
<a>Email</a>
|
||||
</Link>
|
||||
<Link href="/email">Email</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/middleware-protected">
|
||||
<a>Middleware protected</a>
|
||||
</Link>
|
||||
<Link href="/middleware-protected">Middleware protected</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -4,5 +4,6 @@ module.exports = {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
experimental: { appDir: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"faunadb": "^4",
|
||||
"next": "12.2.0",
|
||||
"next": "13.0.2",
|
||||
"next-auth": "workspace:*",
|
||||
"nodemailer": "^6",
|
||||
"react": "^18",
|
||||
|
||||
@@ -30,6 +30,7 @@ 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 Todoist from "next-auth/providers/todoist"
|
||||
import Trakt from "next-auth/providers/trakt"
|
||||
import Twitch from "next-auth/providers/twitch"
|
||||
import Twitter, { TwitterLegacy } from "next-auth/providers/twitter"
|
||||
@@ -39,45 +40,34 @@ import WorkOS from "next-auth/providers/workos"
|
||||
import Zitadel from "next-auth/providers/zitadel"
|
||||
|
||||
// Adapters
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { Client as FaunaClient } from "faunadb"
|
||||
import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
||||
import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
|
||||
// Add an adapter you want to test here.
|
||||
const adapters = {
|
||||
prisma() {
|
||||
const client = globalThis.prisma || new PrismaClient()
|
||||
if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||
return PrismaAdapter(client)
|
||||
},
|
||||
typeorm() {
|
||||
return TypeORMLegacyAdapter({
|
||||
type: "sqlite",
|
||||
name: "next-auth-test-memory",
|
||||
database: "./typeorm/dev.db",
|
||||
synchronize: true,
|
||||
})
|
||||
},
|
||||
fauna() {
|
||||
const client =
|
||||
globalThis.fauna ||
|
||||
new FaunaClient({
|
||||
secret: process.env.FAUNA_SECRET,
|
||||
domain: process.env.FAUNA_DOMAIN,
|
||||
})
|
||||
if (process.env.NODE_ENV !== "production") global.fauna = client
|
||||
return FaunaAdapter(client)
|
||||
},
|
||||
noop() {
|
||||
return undefined
|
||||
},
|
||||
}
|
||||
// // 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,
|
||||
// })
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
adapter: adapters.noop(),
|
||||
debug: true,
|
||||
// adapter,
|
||||
debug: process.env.NODE_ENV !== "production",
|
||||
theme: {
|
||||
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||
brandColor: "#1786fb",
|
||||
@@ -116,6 +106,7 @@ export const authOptions: NextAuthOptions = {
|
||||
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 }),
|
||||
Todoist({ clientId: process.env.TODOIST_ID, clientSecret: process.env.TODOIST_SECRET }),
|
||||
Trakt({ clientId: process.env.TRAKT_ID, clientSecret: process.env.TRAKT_SECRET }),
|
||||
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
||||
Twitter({ version: "2.0", clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
||||
|
||||
@@ -9,6 +9,7 @@ export default async (req, res) => {
|
||||
res.send({
|
||||
content:
|
||||
"This is protected content. You can access this content because you are signed in.",
|
||||
session,
|
||||
})
|
||||
} else {
|
||||
res.send({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from '../auth/[...nextauth]';
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
res.send(JSON.stringify(session, null, 2))
|
||||
res.json(session)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
@@ -15,7 +19,20 @@
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules", "jest.config.js"]
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jest.config.js"
|
||||
]
|
||||
}
|
||||
|
||||
18
apps/dev/types/nextauth.d.ts
vendored
Normal file
18
apps/dev/types/nextauth.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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 {
|
||||
user: {
|
||||
/** The user's postal address. */
|
||||
address: string
|
||||
} & User
|
||||
}
|
||||
|
||||
interface User {
|
||||
foo: string
|
||||
}
|
||||
}
|
||||
104
apps/example-nextjs/.gitignore
vendored
104
apps/example-nextjs/.gitignore
vendored
@@ -1,110 +1,20 @@
|
||||
# Logs
|
||||
.DS_Store
|
||||
|
||||
node_modules/
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.yarn-integrity
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
.vercel
|
||||
.now
|
||||
.env.local
|
||||
|
||||
.DS_Store
|
||||
.env*.local
|
||||
@@ -17,9 +17,7 @@ export default function Footer() {
|
||||
<a href="https://github.com/nextauthjs/next-auth-example">GitHub</a>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/policy">
|
||||
<a>Policy</a>
|
||||
</Link>
|
||||
<Link href="/policy">Policy</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<em>next-auth@{packageJSON.dependencies["next-auth"]}</em>
|
||||
|
||||
@@ -67,39 +67,25 @@ export default function Header() {
|
||||
<nav>
|
||||
<ul className={styles.navItems}>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/">
|
||||
<a>Home</a>
|
||||
</Link>
|
||||
<Link href="/">Home</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/client">
|
||||
<a>Client</a>
|
||||
</Link>
|
||||
<Link href="/client">Client</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/server">
|
||||
<a>Server</a>
|
||||
</Link>
|
||||
<Link href="/server">Server</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/protected">
|
||||
<a>Protected</a>
|
||||
</Link>
|
||||
<Link href="/protected">Protected</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/api-example">
|
||||
<a>API</a>
|
||||
</Link>
|
||||
<Link href="/api-example">API</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/admin">
|
||||
<a>Admin</a>
|
||||
</Link>
|
||||
<Link href="/admin">Admin</Link>
|
||||
</li>
|
||||
<li className={styles.navItem}>
|
||||
<Link href="/me">
|
||||
<a>Me</a>
|
||||
</Link>
|
||||
<Link href="/me">Me</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import Header from "./header"
|
||||
import Footer from "./footer"
|
||||
import type { ReactChildren } from "react"
|
||||
import type { ReactNode } from "react"
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export default function Layout({ children }: Props) {
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
|
||||
@@ -13,13 +13,12 @@ export default function ServerSidePage({ session }: { session: Session }) {
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||
in <strong>unstable_getServerSideProps()</strong>.
|
||||
in <strong>getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||
<strong>unstable_getServerSideProps()</strong> is the recommended
|
||||
approach if you need to support Server Side Rendering with
|
||||
authentication.
|
||||
<strong>getServerSideProps()</strong> is the recommended approach if you
|
||||
need to support Server Side Rendering with authentication.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of Server Side Rendering is this page does not require
|
||||
|
||||
12
apps/playground-nuxt/.editorconfig
Normal file
12
apps/playground-nuxt/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
4
apps/playground-nuxt/.eslintignore
Normal file
4
apps/playground-nuxt/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
tsconfig.json
|
||||
package.json
|
||||
10
apps/playground-nuxt/.eslintrc
Normal file
10
apps/playground-nuxt/.eslintrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": [
|
||||
"@nuxtjs/eslint-config-typescript"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"off"
|
||||
]
|
||||
}
|
||||
}
|
||||
52
apps/playground-nuxt/.gitignore
vendored
Normal file
52
apps/playground-nuxt/.gitignore
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
*.log*
|
||||
|
||||
# Temp directories
|
||||
.temp
|
||||
.tmp
|
||||
.cache
|
||||
|
||||
# Yarn
|
||||
**/.yarn/cache
|
||||
**/.yarn/*state*
|
||||
|
||||
# Generated dirs
|
||||
dist
|
||||
|
||||
# Nuxt
|
||||
.nuxt
|
||||
.output
|
||||
.vercel_build_output
|
||||
.build-*
|
||||
.env
|
||||
.netlify
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Testing
|
||||
reports
|
||||
coverage
|
||||
*.lcov
|
||||
.nyc_output
|
||||
|
||||
# VSCode
|
||||
.vscode
|
||||
|
||||
# Intellij idea
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
.vercel
|
||||
1
apps/playground-nuxt/.nuxtrc
Normal file
1
apps/playground-nuxt/.nuxtrc
Normal file
@@ -0,0 +1 @@
|
||||
imports.autoImport=false
|
||||
108
apps/playground-nuxt/README.md
Normal file
108
apps/playground-nuxt/README.md
Normal file
@@ -0,0 +1,108 @@
|
||||
# NextAuth + Nuxt 3 Playground
|
||||
|
||||
NextAuth.js is committed to bringing easy authentication to other frameworks. [#2294](https://github.com/nextauthjs/next-auth/issues/2294)
|
||||
|
||||
Nuxt 3 support with NextAuth.js is currently experimental. This directory contains a minimal, proof-of-concept application. Parts of this is expected to be abstracted away into a package like` @next-auth/nuxt.`
|
||||
|
||||
This package uses Nuxt's [module starter](https://github.com/nuxt/starter/tree/module).
|
||||
|
||||
Demo: https://next-auth-nuxt-demo.vercel.app
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Add the module to the modules section of `nuxt.config.ts`:
|
||||
|
||||
```ts
|
||||
export default defineNuxtConfig({
|
||||
// temporary module name.
|
||||
modules: ['next-auth-nuxt'],
|
||||
// https://v3.nuxtjs.org/migration/runtime-config#runtime-config
|
||||
runtimeConfig: {
|
||||
secret: process.env.NEXTAUTH_SECRET
|
||||
github: {
|
||||
clientId: process.env.GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET
|
||||
}
|
||||
},
|
||||
// https://v3.nuxtjs.org/guide/concepts/esm#aliasing-libraries
|
||||
// Fix for GithubProvider (or whichever provider you choose) is not a function error in Vite
|
||||
alias: {
|
||||
'next-auth/providers/github': 'node_modules/next-auth/providers/github.js'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Add API route
|
||||
|
||||
To add `NextAuth.js` to a project create a file called `[...].ts` in `server/api/auth`. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
|
||||
|
||||
```ts
|
||||
// ~/server/api/auth/[...].ts
|
||||
import { NextAuthNuxtHandler } from 'next-auth-nuxt/handler'
|
||||
import GithubProvider from 'next-auth/providers/github'
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
export const authOptions = {
|
||||
secret: runtimeConfig.secret,
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: runtimeConfig.github.clientId,
|
||||
clientSecret: runtimeConfig.github.clientSecret
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
export default NextAuthNuxtHandler(authOptions)
|
||||
```
|
||||
|
||||
All requests to `/api/auth/*` (`signIn`, `callback`, `signOut`, etc.) will automatically be handled by NextAuth.js.
|
||||
|
||||
### Frontend - Add Vue Composable
|
||||
|
||||
The `useSession()` Vue Composable is the easiest way to check if someone is signed in.
|
||||
|
||||
```html
|
||||
<script setup lang="ts">
|
||||
const { data: session } = useSession()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="session">
|
||||
Signed in as {{ session.user.email }} <br />
|
||||
<button @click="signOut">Sign out</button>
|
||||
</div>
|
||||
<div v-else>
|
||||
Not signed in <br />
|
||||
<button @click="signIn">Sign in</button>
|
||||
</div>
|
||||
</template>
|
||||
```
|
||||
|
||||
### Backend - API Route
|
||||
|
||||
To protect an API Route, you can use the `getServerSession()` method.
|
||||
|
||||
```ts
|
||||
import { getServerSession } from 'next-auth-nuxt/handler'
|
||||
import { authOptions } from '~/server/api/auth/[...]'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await getServerSession(event, authOptions)
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
content: 'This is protected content. You can access this content because you are signed in.'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error: 'You must be signed in to view the protected content on this page.'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
- Run `pnpm dev:generate` to generate type stubs.
|
||||
- Use `pnpm dev` to start `playground` in development mode.
|
||||
1
apps/playground-nuxt/client.d.ts
vendored
Normal file
1
apps/playground-nuxt/client.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dist/runtime/client'
|
||||
1
apps/playground-nuxt/handler.d.ts
vendored
Normal file
1
apps/playground-nuxt/handler.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export * from './dist/runtime/server/handler'
|
||||
49
apps/playground-nuxt/package.json
Normal file
49
apps/playground-nuxt/package.json
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "next-auth-nuxt",
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"packageManager": "pnpm@7.1.1",
|
||||
"license": "MIT",
|
||||
"main": "./dist/module.cjs",
|
||||
"types": "./dist/types.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/module.mjs",
|
||||
"require": "./dist/module.cjs"
|
||||
},
|
||||
"./handler": {
|
||||
"import": "./dist/runtime/server/handler.mjs",
|
||||
"types": "./dist/runtime/server/handler.d.ts"
|
||||
},
|
||||
"./client": {
|
||||
"import": "./dist/runtime/client/index.mjs",
|
||||
"types": "./dist/runtime/client/index.d.ts"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"handler.d.ts",
|
||||
"client.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"prepack": "nuxt-module-build",
|
||||
"dev": "pnpm prepack && nuxi dev playground",
|
||||
"dev:build": "nuxi build playground",
|
||||
"dev:build:vercel": "NITRO_PRESET=vercel nuxi build playground",
|
||||
"dev:prepare": "nuxt-module-build --stub && nuxi prepare playground"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/kit": "^3.0.0-rc.13",
|
||||
"h3": "^0.8.6",
|
||||
"next-auth": "^4.16.2",
|
||||
"pathe": "^0.3.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/module-builder": "^0.2.0",
|
||||
"@nuxt/schema": "^3.0.0-rc.12",
|
||||
"@nuxtjs/eslint-config-typescript": "^11.0.0",
|
||||
"eslint": "^8.26.0",
|
||||
"nuxt": "^3.0.0-rc.13",
|
||||
"next-auth-nuxt": "workspace:*"
|
||||
}
|
||||
}
|
||||
4
apps/playground-nuxt/playground/.env.example
Normal file
4
apps/playground-nuxt/playground/.env.example
Normal file
@@ -0,0 +1,4 @@
|
||||
GITHUB_CLIENT_ID=
|
||||
GITHUB_CLIENT_SECRET=
|
||||
NEXTAUTH_URL=
|
||||
NEXTAUTH_SECRET=
|
||||
40
apps/playground-nuxt/playground/app.vue
Normal file
40
apps/playground-nuxt/playground/app.vue
Normal file
@@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<Header />
|
||||
<NuxtPage />
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
background: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Access Denied</h1>
|
||||
<p>
|
||||
<a href="/api/auth/signin">You must be signed in to view this page</a>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
30
apps/playground-nuxt/playground/components/Footer.vue
Normal file
30
apps/playground-nuxt/playground/components/Footer.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<footer class="fotter">
|
||||
<hr>
|
||||
<ul class="navItems">
|
||||
<li class="navItem">
|
||||
<a href="https://github.com/nextauthjs/next-auth/tree/main/apps/playground-nuxt">Demo GitHub</a>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<a href="https://next-auth.js.org">Next.js Documentation</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.footer {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.navItems {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.navItem {
|
||||
display: inline-block;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
</style>
|
||||
155
apps/playground-nuxt/playground/components/Header.vue
Normal file
155
apps/playground-nuxt/playground/components/Header.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<script setup lang="ts">
|
||||
import { useSession, signIn, signOut, computed } from '#imports'
|
||||
|
||||
const { data: session, status } = useSession()
|
||||
const loading = computed(() => status.value === 'loading')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<div class="signedInStatus">
|
||||
<p :class="['nojs-show', !session && loading ? 'loading' : 'loaded']">
|
||||
<template v-if="session">
|
||||
<span v-if="session.user?.image" :style="{ backgroundImage: `url(${session.user.image})` }" class="avatar" />
|
||||
<span class="signedInText">
|
||||
<small>Signed in as</small><br>
|
||||
<strong>{{ session.user?.email || session.user?.name }}</strong>
|
||||
</span>
|
||||
<a href="/api/auth/signout" class="button" @click.prevent="signOut">Sign out</a>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="notSignedInText">You are not signed in</span>
|
||||
<a href="/api/auth/signin" class="buttonPrimary" @click.prevent="signIn">Sign in</a>
|
||||
</template>
|
||||
</p>
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="navItems">
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/">
|
||||
Home
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/client">
|
||||
Client
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/server">
|
||||
Server
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/protected">
|
||||
Protected
|
||||
</NuxtLink>
|
||||
</li>
|
||||
<li class="navItem">
|
||||
<NuxtLink to="/api-example">
|
||||
API
|
||||
</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.nojs-show {
|
||||
opacity: 1;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
</style>
|
||||
20
apps/playground-nuxt/playground/nuxt.config.ts
Normal file
20
apps/playground-nuxt/playground/nuxt.config.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import MyModule from '../src/module'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
modules: [
|
||||
MyModule
|
||||
],
|
||||
// https://v3.nuxtjs.org/migration/runtime-config#runtime-config
|
||||
runtimeConfig: {
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
github: {
|
||||
clientId: process.env.GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET
|
||||
}
|
||||
},
|
||||
// https://v3.nuxtjs.org/guide/concepts/esm#aliasing-libraries
|
||||
// Fix for GithubProvider is not a function error in Vite
|
||||
alias: {
|
||||
'next-auth/providers/github': 'node_modules/next-auth/providers/github.js'
|
||||
}
|
||||
})
|
||||
4
apps/playground-nuxt/playground/package.json
Normal file
4
apps/playground-nuxt/playground/package.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "playground",
|
||||
"private": true
|
||||
}
|
||||
15
apps/playground-nuxt/playground/pages/api-example.vue
Normal file
15
apps/playground-nuxt/playground/pages/api-example.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<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" />
|
||||
</div>
|
||||
</template>
|
||||
18
apps/playground-nuxt/playground/pages/client.vue
Normal file
18
apps/playground-nuxt/playground/pages/client.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Client Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>useSession()</strong> Vue Composable in the <strong><Header/></strong> component.
|
||||
</p>
|
||||
<p>
|
||||
The <strong>useSession()</strong> Vue Composable is 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 a provided session via <strong>Vue Plugin</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>
|
||||
</div>
|
||||
</template>
|
||||
8
apps/playground-nuxt/playground/pages/index.vue
Normal file
8
apps/playground-nuxt/playground/pages/index.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Nuxt 3 + NextAuth.js Example</h1>
|
||||
<p>
|
||||
This is an example site to demonstrate how to use <a href="https://v3.nuxtjs.org/">Nuxt 3</a> with <a href="https://next-auth.js.org">NextAuth.js</a> for authentication.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
19
apps/playground-nuxt/playground/pages/protected.vue
Normal file
19
apps/playground-nuxt/playground/pages/protected.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { useSession, useFetch, useLazyFetch } from '#imports'
|
||||
import AccessDenied from '~/components/AccessDenied.vue'
|
||||
|
||||
const { data: session } = useSession()
|
||||
const { data } = await useLazyFetch('/api/examples/protected', {
|
||||
server: false
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<AccessDenied v-if="!session" />
|
||||
<template v-else>
|
||||
<h1>Protected Page</h1>
|
||||
<p><strong>{{ data?.content || "\u00a0" }}</strong></p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
24
apps/playground-nuxt/playground/pages/server.vue
Normal file
24
apps/playground-nuxt/playground/pages/server.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { useFetch } from '#imports'
|
||||
|
||||
await useFetch('/api/examples/session')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the <strong>getServerSession()</strong> method inside an api route and is fetched using the <strong>useFetch()</strong> composable.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getServerSession()</strong> is the recommended approach if you need to
|
||||
support Server Side Rendering with authentication.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of Server Side Rendering is this page does not require client side JavaScript.
|
||||
</p>
|
||||
<p>
|
||||
The disadvantage of Server Side Rendering is that this page is slower to render.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
17
apps/playground-nuxt/playground/server/api/auth/[...].ts
Normal file
17
apps/playground-nuxt/playground/server/api/auth/[...].ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { NextAuthNuxtHandler } from 'next-auth-nuxt/handler'
|
||||
import GithubProvider from 'next-auth/providers/github'
|
||||
import type { NextAuthOptions } from 'next-auth'
|
||||
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
secret: runtimeConfig.secret,
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: runtimeConfig.github.clientId,
|
||||
clientSecret: runtimeConfig.github.clientSecret
|
||||
})
|
||||
]
|
||||
}
|
||||
|
||||
export default NextAuthNuxtHandler(authOptions)
|
||||
10
apps/playground-nuxt/playground/server/api/examples/jwt.ts
Normal file
10
apps/playground-nuxt/playground/server/api/examples/jwt.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { getToken } from 'next-auth/jwt'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// @ts-expect-error: cookies property is not present in h3
|
||||
event.req.cookies = parseCookies(event)
|
||||
const token = await getToken({
|
||||
req: event.req
|
||||
})
|
||||
return token
|
||||
})
|
||||
@@ -0,0 +1,16 @@
|
||||
import { getServerSession } from 'next-auth-nuxt/handler'
|
||||
import { authOptions } from '../auth/[...]'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await getServerSession(event, authOptions)
|
||||
|
||||
if (session) {
|
||||
return {
|
||||
content: 'This is protected content. You can access this content because you are signed in.'
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
error: 'You must be signed in to view the protected content on this page.'
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
import { getServerSession } from 'next-auth-nuxt/handler'
|
||||
import { authOptions } from '../auth/[...]'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const session = await getServerSession(event, authOptions)
|
||||
return session
|
||||
})
|
||||
6386
apps/playground-nuxt/pnpm-lock.yaml
generated
Normal file
6386
apps/playground-nuxt/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
apps/playground-nuxt/pnpm-workspace.yaml
Normal file
2
apps/playground-nuxt/pnpm-workspace.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
packages:
|
||||
- playground
|
||||
40
apps/playground-nuxt/src/module.ts
Normal file
40
apps/playground-nuxt/src/module.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { fileURLToPath } from 'url'
|
||||
import { addImports, addPlugin, defineNuxtModule, extendViteConfig } from '@nuxt/kit'
|
||||
import { resolve } from 'pathe'
|
||||
|
||||
export interface ModuleOptions {
|
||||
}
|
||||
|
||||
export default defineNuxtModule<ModuleOptions>({
|
||||
meta: {
|
||||
name: 'next-auth-nuxt',
|
||||
configKey: 'auth'
|
||||
},
|
||||
defaults: {
|
||||
},
|
||||
async setup (_options, nuxt) {
|
||||
const runtimeDir = fileURLToPath(new URL('./runtime', import.meta.url))
|
||||
nuxt.options.build.transpile.push(runtimeDir)
|
||||
|
||||
addPlugin(resolve(runtimeDir, 'plugin.client'))
|
||||
|
||||
// Composables are auto-imported in client.
|
||||
const client = resolve(runtimeDir, 'client')
|
||||
await addImports([
|
||||
{ name: 'getSession', from: client },
|
||||
{ name: 'getCsrfToken', from: client },
|
||||
{ name: 'getProviders', from: client },
|
||||
{ name: 'signIn', from: client },
|
||||
{ name: 'signOut', from: client },
|
||||
{ name: 'useSession', from: client }
|
||||
])
|
||||
|
||||
// We can safely expose this to client.
|
||||
extendViteConfig((config) => {
|
||||
config.define = config.define || {}
|
||||
config.define['process.env.NEXTAUTH_URL'] = JSON.stringify(process.env.NEXTAUTH_URL)
|
||||
config.define['process.env.NEXTAUTH_URL_INTERNAL'] = JSON.stringify(process.env.NEXTAUTH_URL_INTERNAL)
|
||||
config.define['process.env.VERCEL_URL'] = JSON.stringify(process.env.VERCEL_URL)
|
||||
})
|
||||
}
|
||||
})
|
||||
369
apps/playground-nuxt/src/runtime/client/index.ts
Normal file
369
apps/playground-nuxt/src/runtime/client/index.ts
Normal file
@@ -0,0 +1,369 @@
|
||||
import type { NextAuthClientConfig } from 'next-auth/client/_utils'
|
||||
import type { Plugin, Ref } from 'vue'
|
||||
import { ref, reactive, computed, inject, toRefs } from 'vue'
|
||||
import { BroadcastChannel, apiBaseUrl, fetchData, now } from 'next-auth/client/_utils'
|
||||
import type { Session } from 'next-auth'
|
||||
import type {
|
||||
BuiltInProviderType,
|
||||
RedirectableProviderType
|
||||
} from 'next-auth/providers'
|
||||
import type { H3EventContext } from 'h3'
|
||||
import parseUrl from '../lib/parse-url'
|
||||
import _logger, { proxyLogger } from '../lib/logger'
|
||||
import type {
|
||||
ClientSafeProvider,
|
||||
LiteralUnion,
|
||||
SessionProviderProps,
|
||||
SignInAuthorizationParams,
|
||||
SignInOptions,
|
||||
SignInResponse,
|
||||
SignOutParams,
|
||||
SignOutResponse
|
||||
} from '../types'
|
||||
|
||||
// This behaviour mirrors the default behaviour for getting the site name that
|
||||
// happens server side in server/index.js
|
||||
// 1. An empty value is legitimate when the code is being invoked client side as
|
||||
// relative URLs are valid in that context and so defaults to empty.
|
||||
// 2. When invoked server side the value is picked up from an environment
|
||||
// variable and defaults to 'http://localhost:3000'.
|
||||
const __NEXTAUTH: NextAuthClientConfig = {
|
||||
baseUrl: parseUrl(process.env.NEXTAUTH_URL ?? process.env.VERCEL_URL).origin,
|
||||
basePath: parseUrl(process.env.NEXTAUTH_URL).path,
|
||||
baseUrlServer: parseUrl(
|
||||
process.env.NEXTAUTH_URL_INTERNAL ??
|
||||
process.env.NEXTAUTH_URL ??
|
||||
process.env.VERCEL_URL
|
||||
).origin,
|
||||
basePathServer: parseUrl(
|
||||
process.env.NEXTAUTH_URL_INTERNAL ?? process.env.NEXTAUTH_URL
|
||||
).path,
|
||||
_lastSync: 0,
|
||||
_session: undefined,
|
||||
_getSession: () => {}
|
||||
}
|
||||
|
||||
export interface CtxOrReq {
|
||||
req?: H3EventContext['req']
|
||||
event?: { req: H3EventContext['req'] }
|
||||
}
|
||||
|
||||
export type GetSessionParams = CtxOrReq & {
|
||||
event?: 'storage' | 'timer' | 'hidden' | string
|
||||
triggerEvent?: boolean
|
||||
broadcast?: boolean
|
||||
}
|
||||
|
||||
const logger = proxyLogger(_logger, __NEXTAUTH.basePath)
|
||||
|
||||
const broadcast = BroadcastChannel()
|
||||
|
||||
function isServer () {
|
||||
return (process as any).server
|
||||
}
|
||||
|
||||
export async function getSession (params?: GetSessionParams) {
|
||||
const session = await fetchData<Session>(
|
||||
'session',
|
||||
__NEXTAUTH,
|
||||
logger,
|
||||
params
|
||||
)
|
||||
if (params?.broadcast ?? true) { broadcast.post({ event: 'session', data: { trigger: 'getSession' } }) }
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current Cross Site Request Forgery Token (CSRF Token)
|
||||
* required to make POST requests (e.g. for signing in and signing out).
|
||||
* You likely only need to use this if you are not using the built-in
|
||||
* `signIn()` and `signOut()` methods.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#getcsrftoken)
|
||||
*/
|
||||
export async function getCsrfToken (params?: CtxOrReq) {
|
||||
const response = await fetchData<{ csrfToken: string }>(
|
||||
'csrf',
|
||||
__NEXTAUTH,
|
||||
logger,
|
||||
params
|
||||
)
|
||||
return response?.csrfToken
|
||||
}
|
||||
|
||||
/**
|
||||
* It calls `/api/auth/providers` and returns
|
||||
* a list of the currently configured authentication providers.
|
||||
* It can be useful if you are creating a dynamic custom sign in page.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#getproviders)
|
||||
*/
|
||||
export async function getProviders () {
|
||||
return await fetchData<
|
||||
Record<LiteralUnion<BuiltInProviderType>, ClientSafeProvider>
|
||||
>('providers', __NEXTAUTH, logger)
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-side method to initiate a signin flow
|
||||
* or send the user to the signin page listing all possible providers.
|
||||
* Automatically adds the CSRF token to the request.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#signin)
|
||||
*/
|
||||
export async function signIn<
|
||||
P extends RedirectableProviderType | undefined = undefined,
|
||||
> (
|
||||
provider?: LiteralUnion<BuiltInProviderType>,
|
||||
options?: SignInOptions,
|
||||
authorizationParams?: SignInAuthorizationParams
|
||||
): Promise<
|
||||
P extends RedirectableProviderType ? SignInResponse | undefined : undefined
|
||||
> {
|
||||
const { callbackUrl = window.location.href, redirect = true } = options ?? {}
|
||||
|
||||
const baseUrl = apiBaseUrl(__NEXTAUTH)
|
||||
const providers = await getProviders()
|
||||
|
||||
if (!providers) {
|
||||
window.location.href = `${baseUrl}/error`
|
||||
return
|
||||
}
|
||||
|
||||
if (!provider || !(provider in providers)) {
|
||||
window.location.href = `${baseUrl}/signin?${new URLSearchParams({
|
||||
callbackUrl
|
||||
})}`
|
||||
return
|
||||
}
|
||||
|
||||
const isCredentials = providers[provider].type === 'credentials'
|
||||
const isEmail = providers[provider].type === 'email'
|
||||
const isSupportingReturn = isCredentials || isEmail
|
||||
|
||||
const signInUrl = `${baseUrl}/${
|
||||
isCredentials ? 'callback' : 'signin'
|
||||
}/${provider}`
|
||||
|
||||
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`
|
||||
|
||||
const res = await fetch(_signInUrl, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
// @ts-expect-error: Internal
|
||||
body: new URLSearchParams({
|
||||
...options,
|
||||
csrfToken: await getCsrfToken(),
|
||||
callbackUrl,
|
||||
json: true
|
||||
})
|
||||
})
|
||||
|
||||
const data = await res.json()
|
||||
|
||||
if (redirect || !isSupportingReturn) {
|
||||
const url = data.url ?? callbackUrl
|
||||
window.location.href = url
|
||||
// If url contains a hash, the browser does not reload the page. We reload manually
|
||||
if (url.includes('#')) { window.location.reload() }
|
||||
return
|
||||
}
|
||||
|
||||
const error = new URL(data.url).searchParams.get('error')
|
||||
|
||||
if (res.ok) { await __NEXTAUTH._getSession({ event: 'storage' }) }
|
||||
|
||||
return {
|
||||
error,
|
||||
status: res.status,
|
||||
ok: res.ok,
|
||||
url: error ? null : data.url
|
||||
} as any
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs the user out, by removing the session cookie.
|
||||
* Automatically adds the CSRF token to the request.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#signout)
|
||||
*/
|
||||
export async function signOut<R extends boolean = true> (
|
||||
options?: SignOutParams<R>
|
||||
): Promise<R extends true ? undefined : SignOutResponse> {
|
||||
const { callbackUrl = window.location.href } = options ?? {}
|
||||
const baseUrl = apiBaseUrl(__NEXTAUTH)
|
||||
const fetchOptions = {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
// @ts-expect-error: Internal
|
||||
body: new URLSearchParams({
|
||||
csrfToken: await getCsrfToken(),
|
||||
callbackUrl,
|
||||
json: true
|
||||
})
|
||||
}
|
||||
const res = await fetch(`${baseUrl}/signout`, fetchOptions)
|
||||
const data = await res.json()
|
||||
|
||||
broadcast.post({ event: 'session', data: { trigger: 'signout' } })
|
||||
|
||||
if (options?.redirect ?? true) {
|
||||
const url = data.url ?? callbackUrl
|
||||
window.location.href = url
|
||||
// If url contains a hash, the browser does not reload the page. We reload manually
|
||||
if (url.includes('#')) { window.location.reload() }
|
||||
// @ts-expect-error: Internal
|
||||
return
|
||||
}
|
||||
|
||||
await __NEXTAUTH._getSession({ event: 'storage' })
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export function SessionProviderPlugin (options: SessionProviderProps): Plugin {
|
||||
return {
|
||||
install (app) {
|
||||
const { basePath } = options
|
||||
|
||||
if (basePath) { __NEXTAUTH.basePath = basePath }
|
||||
|
||||
/**
|
||||
* If session was `null`, there was an attempt to fetch it,
|
||||
* but it failed, but we still treat it as a valid initial value.
|
||||
*/
|
||||
const hasInitialSession = options.session !== undefined
|
||||
|
||||
/** If session was passed, initialize as already synced */
|
||||
__NEXTAUTH._lastSync = hasInitialSession ? now() : 0
|
||||
|
||||
if (hasInitialSession) { __NEXTAUTH._session = options.session }
|
||||
|
||||
const session = ref(options.session)
|
||||
|
||||
/** If session was passed, initialize as not loading */
|
||||
const loading = ref(!hasInitialSession)
|
||||
|
||||
__NEXTAUTH._getSession = async ({ event } = {}) => {
|
||||
try {
|
||||
const storageEvent = event === 'storage'
|
||||
// We should always update if we don't have a client session yet
|
||||
// or if there are events from other tabs/windows
|
||||
if (storageEvent || __NEXTAUTH._session === undefined) {
|
||||
__NEXTAUTH._lastSync = now()
|
||||
__NEXTAUTH._session = await getSession({
|
||||
broadcast: !storageEvent
|
||||
})
|
||||
session.value = __NEXTAUTH._session
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
// If there is no time defined for when a session should be considered
|
||||
// stale, then it's okay to use the value we have until an event is
|
||||
// triggered which updates it
|
||||
!event ||
|
||||
// If the client doesn't have a session then we don't need to call
|
||||
// the server to check if it does (if they have signed in via another
|
||||
// tab or window that will come through as a "stroage" event
|
||||
// event anyway)
|
||||
__NEXTAUTH._session === null ||
|
||||
// Bail out early if the client session is not stale yet
|
||||
now() < __NEXTAUTH._lastSync
|
||||
) { return }
|
||||
|
||||
// An event or session staleness occurred, update the client session.
|
||||
__NEXTAUTH._lastSync = now()
|
||||
__NEXTAUTH._session = await getSession()
|
||||
session.value = __NEXTAUTH._session
|
||||
} catch (error) {
|
||||
logger.error('CLIENT_SESSION_ERROR', error as Error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
__NEXTAUTH._getSession()
|
||||
|
||||
const { refetchOnWindowFocus = true } = options
|
||||
|
||||
// Listen for when the page is visible, if the user switches tabs
|
||||
// and makes our tab visible again, re-fetch the session, but only if
|
||||
// this feature is not disabled.
|
||||
const visibilityHandler = () => {
|
||||
if (refetchOnWindowFocus && document.visibilityState === 'visible') { __NEXTAUTH._getSession({ event: 'visibilitychange' }) }
|
||||
}
|
||||
|
||||
document.addEventListener('visibilitychange', visibilityHandler, false)
|
||||
|
||||
const unsubscribeFromBroadcast = broadcast.receive(() =>
|
||||
__NEXTAUTH._getSession({ event: 'storage' })
|
||||
)
|
||||
|
||||
const { refetchInterval } = options
|
||||
let refetchIntervalTimer: NodeJS.Timer
|
||||
|
||||
if (refetchInterval) {
|
||||
refetchIntervalTimer = setInterval(() => {
|
||||
if (__NEXTAUTH._session) { __NEXTAUTH._getSession({ event: 'poll' }) }
|
||||
}, refetchInterval * 1000)
|
||||
}
|
||||
|
||||
const originalUnmount = app.unmount
|
||||
app.unmount = function nextAuthUnmount () {
|
||||
document.removeEventListener('visibilitychange', visibilityHandler, false)
|
||||
unsubscribeFromBroadcast?.()
|
||||
clearInterval(refetchIntervalTimer)
|
||||
__NEXTAUTH._lastSync = 0
|
||||
__NEXTAUTH._session = undefined
|
||||
__NEXTAUTH._getSession = () => {}
|
||||
originalUnmount()
|
||||
}
|
||||
|
||||
const status = computed(() => loading.value ? 'loading' : session.value ? 'authenticated' : 'unauthenticated')
|
||||
const value = reactive({
|
||||
data: session,
|
||||
status
|
||||
})
|
||||
|
||||
app.provide('SessionKey', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vue Composable that gives you access
|
||||
* to the logged in user's session data.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/getting-started/client#usesession)
|
||||
*/
|
||||
export function useSession (): {
|
||||
data: Ref<SessionProviderProps['session']>;
|
||||
status: Ref<string>;
|
||||
} {
|
||||
if (typeof window === 'undefined') {
|
||||
return {
|
||||
data: ref(null),
|
||||
status: ref('loading')
|
||||
}
|
||||
}
|
||||
|
||||
const value = inject<{
|
||||
data: SessionProviderProps['session']
|
||||
status: string
|
||||
}>('SessionKey')
|
||||
if (!value) {
|
||||
throw new Error('Could not resolve provided session value')
|
||||
}
|
||||
const { data, status } = toRefs(value)
|
||||
|
||||
return {
|
||||
data,
|
||||
status
|
||||
}
|
||||
}
|
||||
115
apps/playground-nuxt/src/runtime/lib/errors.ts
Normal file
115
apps/playground-nuxt/src/runtime/lib/errors.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { Adapter } from 'next-auth/adapters'
|
||||
import type { EventCallbacks, LoggerInstance } from 'next-auth'
|
||||
|
||||
/**
|
||||
* Same as the default `Error`, but it is JSON serializable.
|
||||
* @source https://iaincollins.medium.com/error-handling-in-javascript-a6172ccdf9af
|
||||
*/
|
||||
export class UnknownError extends Error {
|
||||
code: string
|
||||
constructor (error: Error | string) {
|
||||
super((error as Error)?.message ?? error)
|
||||
this.name = 'UnknownError'
|
||||
this.code = (error as any).code
|
||||
if (error instanceof Error) { this.stack = error.stack }
|
||||
}
|
||||
|
||||
toJSON () {
|
||||
return {
|
||||
name: this.name,
|
||||
message: this.message,
|
||||
stack: this.stack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class OAuthCallbackError extends UnknownError {
|
||||
name = 'OAuthCallbackError'
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when an Email address is already associated with an account
|
||||
* but the user is trying an OAuth account that is not linked to it.
|
||||
*/
|
||||
export class AccountNotLinkedError extends UnknownError {
|
||||
name = 'AccountNotLinkedError'
|
||||
}
|
||||
|
||||
export class MissingAPIRoute extends UnknownError {
|
||||
name = 'MissingAPIRouteError'
|
||||
code = 'MISSING_NEXTAUTH_API_ROUTE_ERROR'
|
||||
}
|
||||
|
||||
export class MissingSecret extends UnknownError {
|
||||
name = 'MissingSecretError'
|
||||
code = 'NO_SECRET'
|
||||
}
|
||||
|
||||
export class MissingAuthorize extends UnknownError {
|
||||
name = 'MissingAuthorizeError'
|
||||
code = 'CALLBACK_CREDENTIALS_HANDLER_ERROR'
|
||||
}
|
||||
|
||||
export class MissingAdapter extends UnknownError {
|
||||
name = 'MissingAdapterError'
|
||||
code = 'EMAIL_REQUIRES_ADAPTER_ERROR'
|
||||
}
|
||||
|
||||
export class UnsupportedStrategy extends UnknownError {
|
||||
name = 'UnsupportedStrategyError'
|
||||
code = 'CALLBACK_CREDENTIALS_JWT_ERROR'
|
||||
}
|
||||
|
||||
type Method = (...args: any[]) => Promise<any>
|
||||
|
||||
export function upperSnake (s: string) {
|
||||
return s.replace(/([A-Z])/g, '_$1').toUpperCase()
|
||||
}
|
||||
|
||||
export function capitalize (s: string) {
|
||||
return `${s[0].toUpperCase()}${s.slice(1)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps an object of methods and adds error handling.
|
||||
*/
|
||||
export function eventsErrorHandler (
|
||||
methods: Partial<EventCallbacks>,
|
||||
logger: LoggerInstance
|
||||
): Partial<EventCallbacks> {
|
||||
return Object.keys(methods).reduce<any>((acc, name) => {
|
||||
acc[name] = async (...args: any[]) => {
|
||||
try {
|
||||
const method: Method = methods[name as keyof Method]
|
||||
return await method(...args)
|
||||
} catch (e) {
|
||||
logger.error(`${upperSnake(name)}_EVENT_ERROR`, e as Error)
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
/** Handles adapter induced errors. */
|
||||
export function adapterErrorHandler (
|
||||
adapter: Adapter | undefined,
|
||||
logger: LoggerInstance
|
||||
): Adapter | undefined {
|
||||
if (!adapter) { return }
|
||||
|
||||
return Object.keys(adapter).reduce<any>((acc, name) => {
|
||||
acc[name] = async (...args: any[]) => {
|
||||
try {
|
||||
logger.debug(`adapter_${name}`, { args })
|
||||
const method: Method = adapter[name as keyof Method]
|
||||
return await method(...args)
|
||||
} catch (error) {
|
||||
logger.error(`adapter_error_${name}`, error as Error)
|
||||
const e = new UnknownError(error as Error)
|
||||
e.name = `${capitalize(name)}Error`
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
113
apps/playground-nuxt/src/runtime/lib/logger.ts
Normal file
113
apps/playground-nuxt/src/runtime/lib/logger.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { UnknownError } from './errors'
|
||||
|
||||
// TODO: better typing
|
||||
/** Makes sure that error is always serializable */
|
||||
function formatError (o: unknown): unknown {
|
||||
if (o instanceof Error && !(o instanceof UnknownError)) { return { message: o.message, stack: o.stack, name: o.name } }
|
||||
|
||||
if (hasErrorProperty(o)) {
|
||||
o.error = formatError(o.error) as Error
|
||||
o.message = o.message ?? o.error.message
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
function hasErrorProperty (
|
||||
x: unknown
|
||||
): x is { error: Error; [key: string]: unknown } {
|
||||
return !!(x as any)?.error
|
||||
}
|
||||
|
||||
export type WarningCode =
|
||||
| 'NEXTAUTH_URL'
|
||||
| 'NO_SECRET'
|
||||
| 'TWITTER_OAUTH_2_BETA'
|
||||
| 'DEBUG_ENABLED'
|
||||
|
||||
/**
|
||||
* Override any of the methods, and the rest will use the default logger.
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/configuration/options#logger)
|
||||
*/
|
||||
export interface LoggerInstance extends Record<string, Function> {
|
||||
warn: (code: WarningCode) => void
|
||||
error: (
|
||||
code: string,
|
||||
/**
|
||||
* Either an instance of (JSON serializable) Error
|
||||
* or an object that contains some debug information.
|
||||
* (Error is still available through `metadata.error`)
|
||||
*/
|
||||
metadata: Error | { error: Error; [key: string]: unknown }
|
||||
) => void
|
||||
debug: (code: string, metadata: unknown) => void
|
||||
}
|
||||
|
||||
const _logger: LoggerInstance = {
|
||||
error (code, metadata) {
|
||||
metadata = formatError(metadata) as Error
|
||||
console.error(
|
||||
`[next-auth][error][${code}]`,
|
||||
`\nhttps://next-auth.js.org/errors#${code.toLowerCase()}`,
|
||||
metadata.message,
|
||||
metadata
|
||||
)
|
||||
},
|
||||
warn (code) {
|
||||
console.warn(
|
||||
`[next-auth][warn][${code}]`,
|
||||
`\nhttps://next-auth.js.org/warnings#${code.toLowerCase()}`
|
||||
)
|
||||
},
|
||||
debug (code, metadata) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`[next-auth][debug][${code}]`, metadata)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the built-in logger with user's implementation.
|
||||
* Any `undefined` level will use the default logger.
|
||||
*/
|
||||
export function setLogger (
|
||||
newLogger: Partial<LoggerInstance> = {},
|
||||
debug?: boolean
|
||||
) {
|
||||
// Turn off debug logging if `debug` isn't set to `true`
|
||||
if (!debug) { _logger.debug = () => {} }
|
||||
|
||||
if (newLogger.error) { _logger.error = newLogger.error }
|
||||
if (newLogger.warn) { _logger.warn = newLogger.warn }
|
||||
if (newLogger.debug) { _logger.debug = newLogger.debug }
|
||||
}
|
||||
|
||||
export default _logger
|
||||
|
||||
/** Serializes client-side log messages and sends them to the server */
|
||||
export function proxyLogger (
|
||||
logger: LoggerInstance = _logger,
|
||||
basePath?: string
|
||||
): LoggerInstance {
|
||||
try {
|
||||
if (typeof window === 'undefined') { return logger }
|
||||
|
||||
const clientLogger: Record<string, unknown> = {}
|
||||
for (const level in logger) {
|
||||
clientLogger[level] = (code: string, metadata: Error) => {
|
||||
_logger[level](code, metadata) // Logs to console
|
||||
|
||||
if (level === 'error') {
|
||||
metadata = formatError(metadata) as Error
|
||||
}(metadata as any).client = true
|
||||
const url = `${basePath}/_log`
|
||||
const body = new URLSearchParams({ level, code, ...(metadata as any) })
|
||||
if (navigator.sendBeacon) { return navigator.sendBeacon(url, body) }
|
||||
|
||||
return fetch(url, { method: 'POST', body, keepalive: true })
|
||||
}
|
||||
}
|
||||
return clientLogger as unknown as LoggerInstance
|
||||
} catch {
|
||||
return _logger
|
||||
}
|
||||
}
|
||||
34
apps/playground-nuxt/src/runtime/lib/parse-url.ts
Normal file
34
apps/playground-nuxt/src/runtime/lib/parse-url.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
export interface InternalUrl {
|
||||
/** @default "http://localhost:3000" */
|
||||
origin: string
|
||||
/** @default "localhost:3000" */
|
||||
host: string
|
||||
/** @default "/api/auth" */
|
||||
path: string
|
||||
/** @default "http://localhost:3000/api/auth" */
|
||||
base: string
|
||||
/** @default "http://localhost:3000/api/auth" */
|
||||
toString: () => string
|
||||
}
|
||||
|
||||
/** Returns an `URL` like object to make requests/redirects from server-side */
|
||||
export default function parseUrl (url?: string): InternalUrl {
|
||||
const defaultUrl = new URL('http://localhost:3000/api/auth')
|
||||
|
||||
if (url && !url.startsWith('http')) { url = `https://${url}` }
|
||||
|
||||
const _url = new URL(url ?? defaultUrl)
|
||||
const path = (_url.pathname === '/' ? defaultUrl.pathname : _url.pathname)
|
||||
// Remove trailing slash
|
||||
.replace(/\/$/, '')
|
||||
|
||||
const base = `${_url.origin}${path}`
|
||||
|
||||
return {
|
||||
origin: _url.origin,
|
||||
host: _url.host,
|
||||
path,
|
||||
base,
|
||||
toString: () => base
|
||||
}
|
||||
}
|
||||
7
apps/playground-nuxt/src/runtime/plugin.client.ts
Normal file
7
apps/playground-nuxt/src/runtime/plugin.client.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// @ts-expect-error: Nuxt auto-import
|
||||
import { defineNuxtPlugin } from '#app'
|
||||
import { SessionProviderPlugin } from './client'
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
nuxtApp.vueApp.use(SessionProviderPlugin({}))
|
||||
})
|
||||
93
apps/playground-nuxt/src/runtime/server/handler.ts
Normal file
93
apps/playground-nuxt/src/runtime/server/handler.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import type { NextAuthAction, NextAuthOptions, Session } from 'next-auth'
|
||||
import type { RequestInternal } from 'next-auth/core'
|
||||
import { NextAuthHandler } from 'next-auth/core'
|
||||
import {
|
||||
appendHeader,
|
||||
defineEventHandler,
|
||||
isMethod,
|
||||
sendRedirect,
|
||||
setCookie,
|
||||
readBody,
|
||||
parseCookies,
|
||||
getQuery
|
||||
} from 'h3'
|
||||
import type { H3Event } from 'h3'
|
||||
|
||||
export function NextAuthNuxtHandler (options: NextAuthOptions) {
|
||||
return defineEventHandler(async (event) => {
|
||||
// Catch-all route params in Nuxt goes to the underscore property
|
||||
const nextauth = event.context.params._.split('/')
|
||||
|
||||
const req: RequestInternal | Request = {
|
||||
host: process.env.NEXTAUTH_URL,
|
||||
body: undefined,
|
||||
query: getQuery(event),
|
||||
headers: event.req.headers,
|
||||
method: event.req.method,
|
||||
cookies: parseCookies(event),
|
||||
action: nextauth[0] as NextAuthAction,
|
||||
providerId: nextauth[1],
|
||||
error: nextauth[1]
|
||||
}
|
||||
|
||||
if (isMethod(event, 'POST')) {
|
||||
req.body = await readBody(event)
|
||||
}
|
||||
|
||||
const response = await NextAuthHandler({
|
||||
req,
|
||||
options
|
||||
})
|
||||
|
||||
const { headers, cookies, body, redirect, status = 200 } = response
|
||||
event.res.statusCode = status
|
||||
|
||||
headers?.forEach((header) => {
|
||||
appendHeader(event, header.key, header.value)
|
||||
})
|
||||
|
||||
cookies?.forEach((cookie) => {
|
||||
setCookie(event, cookie.name, cookie.value, cookie.options)
|
||||
})
|
||||
|
||||
if (redirect) {
|
||||
if (isMethod(event, 'POST')) {
|
||||
const body = await readBody(event)
|
||||
if (body?.json !== 'true') { await sendRedirect(event, redirect, 302) }
|
||||
|
||||
return {
|
||||
url: redirect
|
||||
}
|
||||
} else {
|
||||
await sendRedirect(event, redirect, 302)
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
})
|
||||
}
|
||||
|
||||
export async function getServerSession (
|
||||
event: H3Event,
|
||||
options: NextAuthOptions
|
||||
): Promise<Session | null> {
|
||||
options.secret = process.env.NEXTAUTH_SECRET
|
||||
|
||||
const session = await NextAuthHandler<Session>({
|
||||
req: {
|
||||
host: process.env.NEXTAUTH_URL,
|
||||
action: 'session',
|
||||
method: 'GET',
|
||||
cookies: parseCookies(event),
|
||||
headers: event.req.headers
|
||||
},
|
||||
options
|
||||
})
|
||||
|
||||
const { body } = session
|
||||
|
||||
if (body && Object.keys(body).length) {
|
||||
return body
|
||||
}
|
||||
return null
|
||||
}
|
||||
78
apps/playground-nuxt/src/runtime/types.ts
Normal file
78
apps/playground-nuxt/src/runtime/types.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { Session } from 'next-auth'
|
||||
import type { BuiltInProviderType, ProviderType } from 'next-auth/providers'
|
||||
|
||||
export interface UseSessionOptions<R extends boolean> {
|
||||
required: R
|
||||
/** Defaults to `signIn` */
|
||||
onUnauthenticated?: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Util type that matches some strings literally, but allows any other string as well.
|
||||
* @source https://github.com/microsoft/TypeScript/issues/29729#issuecomment-832522611
|
||||
*/
|
||||
export type LiteralUnion<T extends U, U = string> =
|
||||
| T
|
||||
| (U & Record<never, never>)
|
||||
|
||||
export interface ClientSafeProvider {
|
||||
id: LiteralUnion<BuiltInProviderType>
|
||||
name: string
|
||||
type: ProviderType
|
||||
signinUrl: string
|
||||
callbackUrl: string
|
||||
}
|
||||
|
||||
export interface SignInOptions extends Record<string, unknown> {
|
||||
/**
|
||||
* Defaults to the current URL.
|
||||
* @docs https://next-auth.js.org/getting-started/client#specifying-a-callbackurl
|
||||
*/
|
||||
callbackUrl?: string
|
||||
/** @docs https://next-auth.js.org/getting-started/client#using-the-redirect-false-option */
|
||||
redirect?: boolean
|
||||
}
|
||||
|
||||
export interface SignInResponse {
|
||||
error: string | undefined
|
||||
status: number
|
||||
ok: boolean
|
||||
url: string | null
|
||||
}
|
||||
|
||||
/** Match `inputType` of `new URLSearchParams(inputType)` */
|
||||
export type SignInAuthorizationParams =
|
||||
| string
|
||||
| string[][]
|
||||
| Record<string, string>
|
||||
| URLSearchParams
|
||||
|
||||
/** @docs https://next-auth.js.org/getting-started/client#using-the-redirect-false-option-1 */
|
||||
export interface SignOutResponse {
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface SignOutParams<R extends boolean = true> {
|
||||
/** @docs https://next-auth.js.org/getting-started/client#specifying-a-callbackurl-1 */
|
||||
callbackUrl?: string
|
||||
/** @docs https://next-auth.js.org/getting-started/client#using-the-redirect-false-option-1 */
|
||||
redirect?: R
|
||||
}
|
||||
|
||||
/** @docs: https://next-auth.js.org/getting-started/client#options */
|
||||
export interface SessionProviderProps {
|
||||
// children: React.ReactNode
|
||||
session?: Session | null
|
||||
baseUrl?: string
|
||||
basePath?: string
|
||||
/**
|
||||
* A time interval (in seconds) after which the session will be re-fetched.
|
||||
* If set to `0` (default), the session is not polled.
|
||||
*/
|
||||
refetchInterval?: number
|
||||
/**
|
||||
* `SessionProvider` automatically refetches the session when the user switches between windows.
|
||||
* This option activates this behaviour if set to `true` (default).
|
||||
*/
|
||||
refetchOnWindowFocus?: boolean
|
||||
}
|
||||
4
apps/playground-nuxt/tsconfig.json
Normal file
4
apps/playground-nuxt/tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://v3.nuxtjs.org/concepts/typescript
|
||||
"extends": "./playground/.nuxt/tsconfig.json"
|
||||
}
|
||||
@@ -7,7 +7,7 @@ module.exports = {
|
||||
"prettier",
|
||||
],
|
||||
plugins: ["svelte3", "@typescript-eslint"],
|
||||
ignorePatterns: ["*.cjs"],
|
||||
ignorePatterns: ["*.cjs", "build/**/*"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
settings: {
|
||||
"svelte3/typescript": () => require("typescript"),
|
||||
|
||||
@@ -4,6 +4,15 @@ NextAuth.js is committed to bringing easy authentication to other frameworks. ht
|
||||
|
||||
SvelteKit support with NextAuth.js is currently experimental. This directory contains a minimal, proof-of-concept application. Parts of this is expected to be abstracted away into a package like `@next-auth/sveltekit`
|
||||
|
||||
## Running this Demo
|
||||
|
||||
- Copy `.env.example` to `.env`
|
||||
- In `.env`, set `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`
|
||||
- See [https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app))
|
||||
- When creating the OAuth app, set "Homepage URL" to `http://localhost:5173` and Authorization callack URL to `http://localhost:5173/api/auth/callback/github`
|
||||
- In `.env`, set `NEXTAUTH_SECRET` to any random string
|
||||
- Build and run the application: `yarn build && yarn start`
|
||||
|
||||
## Existing Project
|
||||
|
||||
### Add API Route
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"start": "HOST=127.0.0.1 PORT=5173 ORIGIN=http://localhost:5173 node ./build",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "1.0.0-next.66",
|
||||
"@sveltejs/kit": "1.0.0-next.443",
|
||||
"@sveltejs/adapter-auto": "^1.0.0-next.80",
|
||||
"@sveltejs/adapter-node": "1.0.0-next.96",
|
||||
"@sveltejs/kit": "1.0.0-next.511",
|
||||
"@types/cookie": "^0.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.35.1",
|
||||
"@typescript-eslint/parser": "^5.35.1",
|
||||
@@ -27,7 +29,7 @@
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "~4.8.2",
|
||||
"vite": "^2.9.13"
|
||||
"vite": "^3.1.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,7 +6,9 @@ export const handle: Handle = async function handle({
|
||||
resolve,
|
||||
}): Promise<Response> {
|
||||
const session = await getServerSession(event.request, nextAuthOptions)
|
||||
event.locals.session = session
|
||||
if (session) {
|
||||
event.locals.session = session
|
||||
}
|
||||
|
||||
return resolve(event)
|
||||
}
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
NEXTAUTH_SECRET,
|
||||
} from "$env/static/private"
|
||||
import { PUBLIC_NEXTAUTH_URL } from "$env/static/public"
|
||||
import getFormBody from "./utils/get-form-body"
|
||||
|
||||
// @ts-expect-error import is exported on .default during SSR
|
||||
const github = GithubProvider?.default || GithubProvider
|
||||
|
||||
export const options: NextAuthOptions = {
|
||||
@@ -24,9 +24,11 @@ export const options: NextAuthOptions = {
|
||||
],
|
||||
}
|
||||
|
||||
const toSvelteKitResponse = async (
|
||||
const toSvelteKitResponse = async <
|
||||
T extends string | any[] | Record<string, any>
|
||||
>(
|
||||
request: Request,
|
||||
nextAuthResponse: NextAuthResponse<unknown>
|
||||
nextAuthResponse: NextAuthResponse<T>
|
||||
): Promise<Response> => {
|
||||
const { cookies, redirect } = nextAuthResponse
|
||||
|
||||
@@ -50,14 +52,14 @@ const toSvelteKitResponse = async (
|
||||
let status = nextAuthResponse.status || 200
|
||||
|
||||
if (redirect) {
|
||||
let formData = null
|
||||
let formData: FormData | null = null
|
||||
try {
|
||||
formData = await request.formData()
|
||||
formData = getFormBody(formData)
|
||||
} catch {
|
||||
// no formData passed
|
||||
}
|
||||
if (formData?.json !== "true") {
|
||||
const { json } = Object.fromEntries(formData ?? [])
|
||||
if (json !== "true") {
|
||||
status = 302
|
||||
headers.set("Location", redirect)
|
||||
} else {
|
||||
@@ -79,17 +81,16 @@ const SKNextAuthHandler = async (
|
||||
options: NextAuthOptions
|
||||
): Promise<Response> => {
|
||||
const [action, provider] = params.nextauth!.split("/")
|
||||
let body = undefined
|
||||
let body: FormData | undefined
|
||||
try {
|
||||
body = await request.formData()
|
||||
body = getFormBody(body)
|
||||
} catch {
|
||||
// no formData passed
|
||||
}
|
||||
options.secret = NEXTAUTH_SECRET
|
||||
const req: RequestInternal = {
|
||||
host: PUBLIC_NEXTAUTH_URL,
|
||||
body,
|
||||
body: Object.fromEntries(body ?? []),
|
||||
query: Object.fromEntries(url.searchParams),
|
||||
headers: request.headers,
|
||||
method: request.method,
|
||||
@@ -135,8 +136,8 @@ export const getServerSession = async (
|
||||
export const NextAuth = (
|
||||
options: NextAuthOptions
|
||||
): {
|
||||
GET: (event) => Promise<unknown>
|
||||
POST: (event) => Promise<unknown>
|
||||
GET: (event: ServerLoadEvent) => Promise<unknown>
|
||||
POST: (event: ServerLoadEvent) => Promise<unknown>
|
||||
} => ({
|
||||
GET: (event) => SKNextAuthHandler(event, options),
|
||||
POST: (event) => SKNextAuthHandler(event, options),
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// https://dev.to/danawoodman/getting-form-body-data-in-your-sveltekit-endpoints-4a85
|
||||
export default function getFormBody(
|
||||
body: FormData | null
|
||||
): Record<string, any> {
|
||||
if (!body) return {}
|
||||
|
||||
// @ts-expect-error: Entries property type missing
|
||||
return [...body.entries()].reduce((data, [k, v]) => {
|
||||
const value = v
|
||||
if (k in data)
|
||||
data[k] = Array.isArray(data[k]) ? [...data[k], value] : [data[k], value]
|
||||
else data[k] = value
|
||||
return data
|
||||
}, {})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import adapter from "@sveltejs/adapter-auto"
|
||||
import adapter from "@sveltejs/adapter-node" // or use https://github.com/sveltejs/kit/tree/master/packages/adapter-auto
|
||||
import preprocess from "svelte-preprocess"
|
||||
|
||||
/** @type {import('@sveltejs/kit').Config} */
|
||||
@@ -6,14 +6,8 @@ const config = {
|
||||
// Consult https://github.com/sveltejs/svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: preprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
||||
// Override http methods in the Todo forms
|
||||
methodOverride: {
|
||||
allowed: ["PATCH", "DELETE"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,19 @@
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@cloudflare/workers-types@^3.14.0":
|
||||
version "3.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-3.15.0.tgz#b8b17f923181c61220880aaa8ef30d75d59a1219"
|
||||
integrity sha512-meL/Afy5qdIsgfdnlbVfcYUh/YjHk23EWUvgmULf6iDrDbrBcd+fse2os3CC7rxSfScdP1OqJVTHgRSEjUm/Pw==
|
||||
version "3.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@cloudflare/workers-types/-/workers-types-3.16.0.tgz#011658ca3f9810373e0eb4a2b5d6cabe4848d8d6"
|
||||
integrity sha512-gaBUSaKS65mN3iKZEgichbXYEmAa/pXkc5Gbt+1BptYphdGkj09ggdsiE4w8g0F/uI1g36QaTKrzVnBAWMipvQ==
|
||||
|
||||
"@esbuild/linux-loong64@0.14.54":
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028"
|
||||
integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==
|
||||
"@esbuild/android-arm@0.15.10":
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.10.tgz#a5f9432eb221afc243c321058ef25fe899886892"
|
||||
integrity sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==
|
||||
|
||||
"@esbuild/linux-loong64@0.15.10":
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz#78a42897c2cf8db9fd5f1811f7590393b77774c7"
|
||||
integrity sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==
|
||||
|
||||
"@eslint/eslintrc@^1.3.1":
|
||||
version "1.3.1"
|
||||
@@ -82,9 +87,9 @@
|
||||
"@jridgewell/sourcemap-codec" "^1.4.10"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.5":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc"
|
||||
integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c"
|
||||
integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==
|
||||
dependencies:
|
||||
detect-libc "^2.0.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
@@ -127,6 +132,47 @@
|
||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
|
||||
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
|
||||
|
||||
"@rollup/plugin-commonjs@^22.0.1":
|
||||
version "22.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.2.tgz#ee8ca8415cda30d383b4096aad5222435b4b69b6"
|
||||
integrity sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
commondir "^1.0.1"
|
||||
estree-walker "^2.0.1"
|
||||
glob "^7.1.6"
|
||||
is-reference "^1.2.1"
|
||||
magic-string "^0.25.7"
|
||||
resolve "^1.17.0"
|
||||
|
||||
"@rollup/plugin-json@^4.1.0":
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-json/-/plugin-json-4.1.0.tgz#54e09867ae6963c593844d8bd7a9c718294496f3"
|
||||
integrity sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.0.8"
|
||||
|
||||
"@rollup/plugin-node-resolve@^14.1.0":
|
||||
version "14.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-14.1.0.tgz#f2fa475405cd7fed6420bf438fe393f988a9bc96"
|
||||
integrity sha512-5G2niJroNCz/1zqwXtk0t9+twOSDlG00k1Wfd7bkbbXmwg8H8dvgHdIWAun53Ps/rckfvOC7scDBjuGFg5OaWw==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
"@types/resolve" "1.17.1"
|
||||
deepmerge "^4.2.2"
|
||||
is-builtin-module "^3.1.0"
|
||||
is-module "^1.0.0"
|
||||
resolve "^1.19.0"
|
||||
|
||||
"@rollup/pluginutils@^3.0.8", "@rollup/pluginutils@^3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
|
||||
integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
|
||||
dependencies:
|
||||
"@types/estree" "0.0.39"
|
||||
estree-walker "^1.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@rollup/pluginutils@^4.2.1":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||
@@ -135,77 +181,96 @@
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@sveltejs/adapter-auto@1.0.0-next.66":
|
||||
version "1.0.0-next.66"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-1.0.0-next.66.tgz#93a6de02a7a4ebef11160bf8d012ef349839656e"
|
||||
integrity sha512-p78AQaSDHkLS5EFGqCF2xrLHMjKxx6wTLUvnP26cu2llh/VV4NihQ0rheVNgPWL+tGZpVznhrUG8fWmJxPciug==
|
||||
"@sveltejs/adapter-auto@^1.0.0-next.80":
|
||||
version "1.0.0-next.80"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-1.0.0-next.80.tgz#15d331bbfca89cb39b719c3086d134cc1a7227b1"
|
||||
integrity sha512-352WoZr9fQgxJqgNENvxRr2gsA+wTF6V9AVaQaaatDYd3RVEBaXTYOOalFaRLSa25mRUJaLYP2aaliqczMl23g==
|
||||
dependencies:
|
||||
"@sveltejs/adapter-cloudflare" "1.0.0-next.32"
|
||||
"@sveltejs/adapter-netlify" "1.0.0-next.72"
|
||||
"@sveltejs/adapter-vercel" "1.0.0-next.68"
|
||||
"@sveltejs/adapter-cloudflare" "1.0.0-next.38"
|
||||
"@sveltejs/adapter-netlify" "1.0.0-next.78"
|
||||
"@sveltejs/adapter-vercel" "1.0.0-next.77"
|
||||
|
||||
"@sveltejs/adapter-cloudflare@1.0.0-next.32":
|
||||
version "1.0.0-next.32"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-1.0.0-next.32.tgz#2e164e50786cf50d907f79a1d9ec8e0ab72a99df"
|
||||
integrity sha512-tzkUsdQlBk9xUjcGUOBYos4HKaeaXvz9v4TQ1QS2yIHEtL5xvMEDPZ94/DB2gPL4LZCnYbdY2lsy5HCsoN0hkQ==
|
||||
"@sveltejs/adapter-cloudflare@1.0.0-next.38":
|
||||
version "1.0.0-next.38"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-1.0.0-next.38.tgz#b4c6e7314de79f2a3ab1d8e2f88274a8c224e325"
|
||||
integrity sha512-N6jdTomRZkdKlcNoguwYD7lpdXSt0beIyUJsp0MS/YLm/4gI83y698zFYInFKJ9t5e6DAnuEBSAXcg568z2oFA==
|
||||
dependencies:
|
||||
"@cloudflare/workers-types" "^3.14.0"
|
||||
esbuild "^0.14.48"
|
||||
esbuild "^0.15.7"
|
||||
worktop "0.8.0-next.14"
|
||||
|
||||
"@sveltejs/adapter-netlify@1.0.0-next.72":
|
||||
version "1.0.0-next.72"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-netlify/-/adapter-netlify-1.0.0-next.72.tgz#5fe42a4944de476baa089cdc7f525ae6037585c9"
|
||||
integrity sha512-g570hYAMkgrJfo/TRg3DZFmlR7bNFHECFPOMgc8R+f28ROap/nXA8ICbiSBF7+zJ5JXvJbqHGjERSsyhEq+59g==
|
||||
"@sveltejs/adapter-netlify@1.0.0-next.78":
|
||||
version "1.0.0-next.78"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-netlify/-/adapter-netlify-1.0.0-next.78.tgz#a18e750ac9d146afb308c527649f24c40b746d59"
|
||||
integrity sha512-Yyn/j/0QcLK3Db442ducLUZmyvkO74j7Gdcwu9xN0fQN3kBlCJP9Itx5o4SySrPFGc4Q8cLJ5ELNg+mWduLBAA==
|
||||
dependencies:
|
||||
"@iarna/toml" "^2.2.5"
|
||||
esbuild "^0.14.48"
|
||||
esbuild "^0.15.7"
|
||||
set-cookie-parser "^2.4.8"
|
||||
tiny-glob "^0.2.9"
|
||||
|
||||
"@sveltejs/adapter-vercel@1.0.0-next.68":
|
||||
version "1.0.0-next.68"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-vercel/-/adapter-vercel-1.0.0-next.68.tgz#ccd0707f02d8aff9185b373a484366d961f58753"
|
||||
integrity sha512-ImM+fDwGkVaf920Wzh284nfAfu/WoPXCpMwog0kveIODVgCozbpJY55fO860LccqdS0YDyeFqOUrZJCqcYNx4w==
|
||||
"@sveltejs/adapter-node@1.0.0-next.96":
|
||||
version "1.0.0-next.96"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-node/-/adapter-node-1.0.0-next.96.tgz#3f071a0677f787f9e8b2157b087b5403c4df4b6c"
|
||||
integrity sha512-tIHaRolUYy2PiHl4RUWaOsYxEjK5lN9501qzCzFbYr/uoLnZcnPGSXNJICwX0AX9AUkV6cvkZey6bLbUQcwH0Q==
|
||||
dependencies:
|
||||
"@vercel/nft" "^0.21.0"
|
||||
esbuild "^0.14.48"
|
||||
"@rollup/plugin-commonjs" "^22.0.1"
|
||||
"@rollup/plugin-json" "^4.1.0"
|
||||
"@rollup/plugin-node-resolve" "^14.1.0"
|
||||
rollup "^2.78.1"
|
||||
|
||||
"@sveltejs/kit@1.0.0-next.443":
|
||||
version "1.0.0-next.443"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-1.0.0-next.443.tgz#5797a3c21d839562b3e96d19151beefa957dbf37"
|
||||
integrity sha512-Stdjwj6iL/u40O/+20UKTWtCBYxYaKwX2nRV5devrGk5hvq6/FbAqw+azwoWKvNoz3PGtrSmHIyeLcAx8iKQcw==
|
||||
"@sveltejs/adapter-vercel@1.0.0-next.77":
|
||||
version "1.0.0-next.77"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/adapter-vercel/-/adapter-vercel-1.0.0-next.77.tgz#be9bfa2b46fd63723893d37ecdacbb1d735515c3"
|
||||
integrity sha512-r4MqtP+lzx83HfcvI8PU0Yxzmxt6WQq9nzZETLboJouJzhSBUFIN5RmNZfEn6nNIlUwZbGQUEK/FxsRnnxI/Ig==
|
||||
dependencies:
|
||||
"@sveltejs/vite-plugin-svelte" "^1.0.1"
|
||||
"@vercel/nft" "^0.22.0"
|
||||
esbuild "^0.15.7"
|
||||
|
||||
"@sveltejs/kit@1.0.0-next.511":
|
||||
version "1.0.0-next.511"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-1.0.0-next.511.tgz#d045d0737ec93d21de5a27b6ca619daf79f8e4f7"
|
||||
integrity sha512-A/fxd4qHWDD07Mjo6qEEEfsBEkoj5C4/dPSzx6xPUoWmPvRPhU8t+P0oMc8BOn5YHOhPDq3coH8bmafbh73zKg==
|
||||
dependencies:
|
||||
"@sveltejs/vite-plugin-svelte" "^1.0.5"
|
||||
"@types/cookie" "^0.5.1"
|
||||
cookie "^0.5.0"
|
||||
devalue "^2.0.1"
|
||||
devalue "^4.0.0"
|
||||
kleur "^4.1.4"
|
||||
magic-string "^0.26.2"
|
||||
mime "^3.0.0"
|
||||
node-fetch "^3.2.4"
|
||||
sade "^1.8.1"
|
||||
set-cookie-parser "^2.4.8"
|
||||
sirv "^2.0.2"
|
||||
tiny-glob "^0.2.9"
|
||||
undici "^5.8.1"
|
||||
undici "^5.11.0"
|
||||
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.1":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.3.tgz#f760677e03074b9f42335dbde33ba988c95d1e67"
|
||||
integrity sha512-0Qu51m2W9RBlxWPp8i31KJpnqmjWMOne8vAzgmOX6ZM9uX+/RAv6BNhEMcNoP5MsyLjyW1ZTCiJoaZZ5EeqpFg==
|
||||
"@sveltejs/vite-plugin-svelte@^1.0.5":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.0.9.tgz#b19bde0ba1929a06205888e94475595e3ac0c258"
|
||||
integrity sha512-+SDrAnT7TDi8sdj4OfD2SC4s9DNrpNVBrue8fT2PmKks9Ddu0JIfSeX91wXZb/1xHz4EkGb+rli8GTRI0yGOjg==
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^4.2.1"
|
||||
debug "^4.3.4"
|
||||
deepmerge "^4.2.2"
|
||||
kleur "^4.1.5"
|
||||
magic-string "^0.26.2"
|
||||
svelte-hmr "^0.14.12"
|
||||
magic-string "^0.26.5"
|
||||
svelte-hmr "^0.15.0"
|
||||
|
||||
"@types/cookie@^0.5.1":
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.5.1.tgz#b29aa1f91a59f35e29ff8f7cb24faf1a3a750554"
|
||||
integrity sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==
|
||||
|
||||
"@types/estree@*":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
|
||||
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
|
||||
|
||||
"@types/estree@0.0.39":
|
||||
version "0.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
|
||||
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
|
||||
|
||||
"@types/json-schema@^7.0.9":
|
||||
version "7.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
|
||||
@@ -221,6 +286,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.6.tgz#f830323c88172e66826d0bde413498b61054b5a6"
|
||||
integrity sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==
|
||||
|
||||
"@types/resolve@1.17.1":
|
||||
version "1.17.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
|
||||
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/sass@^1.16.0":
|
||||
version "1.43.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/sass/-/sass-1.43.1.tgz#86bb0168e9e881d7dade6eba16c9ed6d25dc2f68"
|
||||
@@ -309,10 +381,10 @@
|
||||
"@typescript-eslint/types" "5.36.1"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@vercel/nft@^0.21.0":
|
||||
version "0.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.21.0.tgz#e0715b1997cd7021a7c7c48b584ef2295fd4b810"
|
||||
integrity sha512-hFCAETfI5cG8l5iAiLhMC2bReC5K7SIybzrxGorv+eGspIbIFsVw7Vg85GovXm/LxA08pIDrAlrhR6GN36XB/Q==
|
||||
"@vercel/nft@^0.22.0":
|
||||
version "0.22.1"
|
||||
resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.22.1.tgz#0d91d2a21e3a7f0b23ce1550da9870eac4942828"
|
||||
integrity sha512-lYYZIoxRurqDOSoVIdBicGnpUIpfyaS5qVjdPq+EfI285WqtZK3NK/dyCkiyBul+X2U2OEhRyeMdXPCHGJbohw==
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
||||
acorn "^8.6.0"
|
||||
@@ -443,6 +515,18 @@ buffer-crc32@^0.2.5:
|
||||
resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
|
||||
integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||
|
||||
builtin-modules@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
|
||||
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
|
||||
|
||||
busboy@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
|
||||
dependencies:
|
||||
streamsearch "^1.1.0"
|
||||
|
||||
callsites@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
@@ -493,6 +577,11 @@ color-support@^1.1.2:
|
||||
resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
|
||||
integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
|
||||
integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
@@ -522,11 +611,6 @@ cross-spawn@^7.0.2:
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
data-uri-to-buffer@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
|
||||
integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==
|
||||
|
||||
debug@4, debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
@@ -566,10 +650,10 @@ detect-libc@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
|
||||
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
|
||||
|
||||
devalue@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/devalue/-/devalue-2.0.1.tgz#5d368f9adc0928e47b77eea53ca60d2f346f9762"
|
||||
integrity sha512-I2TiqT5iWBEyB8GRfTDP0hiLZ0YeDJZ+upDxjBfOC2lebO5LezQMv7QvIUTzdb64jQyAKLf1AHADtGN+jw6v8Q==
|
||||
devalue@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/devalue/-/devalue-4.0.0.tgz#efeadbc922894d468ad903029d4a7e65e37f4952"
|
||||
integrity sha512-w25siwXyuMUqMr7jPlEjyNCp1vn0Jzj/fNg3qVt/r/Dpe8HjESh2V92L0jmh3uq4iJt0BvjH+Azk1pQzkcnDWA==
|
||||
|
||||
dir-glob@^3.0.1:
|
||||
version "3.0.1"
|
||||
@@ -595,132 +679,133 @@ es6-promise@^3.1.2:
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
|
||||
integrity sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=
|
||||
|
||||
esbuild-android-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be"
|
||||
integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==
|
||||
esbuild-android-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz#8a59a84acbf2eca96996cadc35642cf055c494f0"
|
||||
integrity sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==
|
||||
|
||||
esbuild-android-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771"
|
||||
integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==
|
||||
esbuild-android-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz#f453851dc1d8c5409a38cf7613a33852faf4915d"
|
||||
integrity sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==
|
||||
|
||||
esbuild-darwin-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25"
|
||||
integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==
|
||||
esbuild-darwin-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz#778bd29c8186ff47b176c8af58c08cf0fb8e6b86"
|
||||
integrity sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==
|
||||
|
||||
esbuild-darwin-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73"
|
||||
integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==
|
||||
esbuild-darwin-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz#b30bbefb46dc3c5d4708b0435e52f6456578d6df"
|
||||
integrity sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==
|
||||
|
||||
esbuild-freebsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d"
|
||||
integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==
|
||||
esbuild-freebsd-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz#ab301c5f6ded5110dbdd611140bef1a7c2e99236"
|
||||
integrity sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==
|
||||
|
||||
esbuild-freebsd-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48"
|
||||
integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==
|
||||
esbuild-freebsd-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz#a5b09b867a6ff49110f52343b6f12265db63d43f"
|
||||
integrity sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==
|
||||
|
||||
esbuild-linux-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5"
|
||||
integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==
|
||||
esbuild-linux-32@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz#5282fe9915641caf9c8070e4ba2c3e16d358f837"
|
||||
integrity sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==
|
||||
|
||||
esbuild-linux-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz#de5fdba1c95666cf72369f52b40b03be71226652"
|
||||
integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==
|
||||
esbuild-linux-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz#f3726e85a00149580cb19f8abfabcbb96f5d52bb"
|
||||
integrity sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==
|
||||
|
||||
esbuild-linux-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b"
|
||||
integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==
|
||||
esbuild-linux-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz#2f0056e9d5286edb0185b56655caa8c574d8dbe7"
|
||||
integrity sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==
|
||||
|
||||
esbuild-linux-arm@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59"
|
||||
integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==
|
||||
esbuild-linux-arm@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz#40a9270da3c8ffa32cf72e24a79883e323dff08d"
|
||||
integrity sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==
|
||||
|
||||
esbuild-linux-mips64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34"
|
||||
integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==
|
||||
esbuild-linux-mips64le@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz#90ce1c4ee0202edb4ac69807dea77f7e5804abc4"
|
||||
integrity sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==
|
||||
|
||||
esbuild-linux-ppc64le@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e"
|
||||
integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==
|
||||
esbuild-linux-ppc64le@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz#782837ae7bd5b279178106c9dd801755a21fabdf"
|
||||
integrity sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==
|
||||
|
||||
esbuild-linux-riscv64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8"
|
||||
integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==
|
||||
esbuild-linux-riscv64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz#d7420d806ece5174f24f4634303146f915ab4207"
|
||||
integrity sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==
|
||||
|
||||
esbuild-linux-s390x@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6"
|
||||
integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==
|
||||
esbuild-linux-s390x@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz#21fdf0cb3494a7fb520a71934e4dffce67fe47be"
|
||||
integrity sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==
|
||||
|
||||
esbuild-netbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81"
|
||||
integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==
|
||||
esbuild-netbsd-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz#6c06b3107e3df53de381e6299184d4597db0440f"
|
||||
integrity sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==
|
||||
|
||||
esbuild-openbsd-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b"
|
||||
integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==
|
||||
esbuild-openbsd-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz#4daef5f5d8e74bbda53b65160029445d582570cf"
|
||||
integrity sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==
|
||||
|
||||
esbuild-sunos-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da"
|
||||
integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==
|
||||
esbuild-sunos-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz#5fe7bef267a02f322fd249a8214d0274937388a7"
|
||||
integrity sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==
|
||||
|
||||
esbuild-windows-32@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31"
|
||||
integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==
|
||||
esbuild-windows-32@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz#48e3dde25ab0135579a288b30ab6ddef6d1f0b28"
|
||||
integrity sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==
|
||||
|
||||
esbuild-windows-64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4"
|
||||
integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==
|
||||
esbuild-windows-64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz#387a9515bef3fee502d277a5d0a2db49a4ecda05"
|
||||
integrity sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==
|
||||
|
||||
esbuild-windows-arm64@0.14.54:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982"
|
||||
integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==
|
||||
esbuild-windows-arm64@0.15.10:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz#5a6fcf2fa49e895949bf5495cf088ab1b43ae879"
|
||||
integrity sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==
|
||||
|
||||
esbuild@^0.14.27, esbuild@^0.14.48:
|
||||
version "0.14.54"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.54.tgz#8b44dcf2b0f1a66fc22459943dccf477535e9aa2"
|
||||
integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==
|
||||
esbuild@^0.15.7, esbuild@^0.15.9:
|
||||
version "0.15.10"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.10.tgz#85c2f8446e9b1fe04fae68daceacba033eedbd42"
|
||||
integrity sha512-N7wBhfJ/E5fzn/SpNgX+oW2RLRjwaL8Y0ezqNqhjD6w0H2p0rDuEz2FKZqpqLnO8DCaWumKe8dsC/ljvVSSxng==
|
||||
optionalDependencies:
|
||||
"@esbuild/linux-loong64" "0.14.54"
|
||||
esbuild-android-64 "0.14.54"
|
||||
esbuild-android-arm64 "0.14.54"
|
||||
esbuild-darwin-64 "0.14.54"
|
||||
esbuild-darwin-arm64 "0.14.54"
|
||||
esbuild-freebsd-64 "0.14.54"
|
||||
esbuild-freebsd-arm64 "0.14.54"
|
||||
esbuild-linux-32 "0.14.54"
|
||||
esbuild-linux-64 "0.14.54"
|
||||
esbuild-linux-arm "0.14.54"
|
||||
esbuild-linux-arm64 "0.14.54"
|
||||
esbuild-linux-mips64le "0.14.54"
|
||||
esbuild-linux-ppc64le "0.14.54"
|
||||
esbuild-linux-riscv64 "0.14.54"
|
||||
esbuild-linux-s390x "0.14.54"
|
||||
esbuild-netbsd-64 "0.14.54"
|
||||
esbuild-openbsd-64 "0.14.54"
|
||||
esbuild-sunos-64 "0.14.54"
|
||||
esbuild-windows-32 "0.14.54"
|
||||
esbuild-windows-64 "0.14.54"
|
||||
esbuild-windows-arm64 "0.14.54"
|
||||
"@esbuild/android-arm" "0.15.10"
|
||||
"@esbuild/linux-loong64" "0.15.10"
|
||||
esbuild-android-64 "0.15.10"
|
||||
esbuild-android-arm64 "0.15.10"
|
||||
esbuild-darwin-64 "0.15.10"
|
||||
esbuild-darwin-arm64 "0.15.10"
|
||||
esbuild-freebsd-64 "0.15.10"
|
||||
esbuild-freebsd-arm64 "0.15.10"
|
||||
esbuild-linux-32 "0.15.10"
|
||||
esbuild-linux-64 "0.15.10"
|
||||
esbuild-linux-arm "0.15.10"
|
||||
esbuild-linux-arm64 "0.15.10"
|
||||
esbuild-linux-mips64le "0.15.10"
|
||||
esbuild-linux-ppc64le "0.15.10"
|
||||
esbuild-linux-riscv64 "0.15.10"
|
||||
esbuild-linux-s390x "0.15.10"
|
||||
esbuild-netbsd-64 "0.15.10"
|
||||
esbuild-openbsd-64 "0.15.10"
|
||||
esbuild-sunos-64 "0.15.10"
|
||||
esbuild-windows-32 "0.15.10"
|
||||
esbuild-windows-64 "0.15.10"
|
||||
esbuild-windows-arm64 "0.15.10"
|
||||
|
||||
escape-string-regexp@^4.0.0:
|
||||
version "4.0.0"
|
||||
@@ -858,6 +943,11 @@ estree-walker@^0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362"
|
||||
integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==
|
||||
|
||||
estree-walker@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
|
||||
integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
|
||||
@@ -896,14 +986,6 @@ fastq@^1.6.0:
|
||||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
fetch-blob@^3.1.2, fetch-blob@^3.1.4:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9"
|
||||
integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==
|
||||
dependencies:
|
||||
node-domexception "^1.0.0"
|
||||
web-streams-polyfill "^3.0.3"
|
||||
|
||||
file-entry-cache@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
|
||||
@@ -944,13 +1026,6 @@ flatted@^3.1.0:
|
||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
|
||||
integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
|
||||
|
||||
formdata-polyfill@^4.0.10:
|
||||
version "4.0.10"
|
||||
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
|
||||
integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==
|
||||
dependencies:
|
||||
fetch-blob "^3.1.2"
|
||||
|
||||
fs-minipass@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
|
||||
@@ -1019,6 +1094,18 @@ glob@^7.1.3:
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
glob@^7.1.6:
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
|
||||
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.1.1"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
globals@^13.15.0:
|
||||
version "13.17.0"
|
||||
resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
|
||||
@@ -1126,10 +1213,17 @@ is-binary-path@~2.1.0:
|
||||
dependencies:
|
||||
binary-extensions "^2.0.0"
|
||||
|
||||
is-core-module@^2.8.1:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
|
||||
integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
|
||||
is-builtin-module@^3.1.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.0.tgz#bb0310dfe881f144ca83f30100ceb10cf58835e0"
|
||||
integrity sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==
|
||||
dependencies:
|
||||
builtin-modules "^3.3.0"
|
||||
|
||||
is-core-module@^2.9.0:
|
||||
version "2.10.0"
|
||||
resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed"
|
||||
integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==
|
||||
dependencies:
|
||||
has "^1.0.3"
|
||||
|
||||
@@ -1150,11 +1244,23 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
|
||||
integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
|
||||
|
||||
is-number@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
is-reference@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7"
|
||||
integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||
@@ -1233,6 +1339,13 @@ magic-string@^0.26.2:
|
||||
dependencies:
|
||||
sourcemap-codec "^1.4.8"
|
||||
|
||||
magic-string@^0.26.5:
|
||||
version "0.26.6"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.6.tgz#b61e417c9f40b7b53bf7e73c0a803258e20d25ee"
|
||||
integrity sha512-6d+3bFybzyQFJYSoRsl9ZC0wheze8M1LrQC7tNMRqXR4izUTDOLMd9BtSuExK9iAukFh+s5K0WAhc/dlQ+HKYA==
|
||||
dependencies:
|
||||
sourcemap-codec "^1.4.8"
|
||||
|
||||
make-dir@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
|
||||
@@ -1271,7 +1384,7 @@ min-indent@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||
|
||||
minimatch@^3.0.4, minimatch@^3.1.2:
|
||||
minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
|
||||
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
|
||||
@@ -1350,11 +1463,6 @@ next-auth@latest:
|
||||
preact-render-to-string "^5.1.19"
|
||||
uuid "^8.3.2"
|
||||
|
||||
node-domexception@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5"
|
||||
integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
version "2.6.7"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
|
||||
@@ -1362,15 +1470,6 @@ node-fetch@^2.6.7:
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
node-fetch@^3.2.4:
|
||||
version "3.2.10"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.2.10.tgz#e8347f94b54ae18b57c9c049ef641cef398a85c8"
|
||||
integrity sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==
|
||||
dependencies:
|
||||
data-uri-to-buffer "^4.0.0"
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-gyp-build@^4.2.2:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40"
|
||||
@@ -1503,10 +1602,10 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatc
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
postcss@^8.4.13:
|
||||
version "8.4.16"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c"
|
||||
integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==
|
||||
postcss@^8.4.16:
|
||||
version "8.4.17"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.17.tgz#f87863ec7cd353f81f7ab2dec5d67d861bbb1be5"
|
||||
integrity sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==
|
||||
dependencies:
|
||||
nanoid "^3.3.4"
|
||||
picocolors "^1.0.0"
|
||||
@@ -1595,12 +1694,12 @@ resolve-from@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
|
||||
integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
|
||||
|
||||
resolve@^1.22.0:
|
||||
version "1.22.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
|
||||
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
|
||||
resolve@^1.17.0, resolve@^1.19.0, resolve@^1.22.1:
|
||||
version "1.22.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
|
||||
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
|
||||
dependencies:
|
||||
is-core-module "^2.8.1"
|
||||
is-core-module "^2.9.0"
|
||||
path-parse "^1.0.7"
|
||||
supports-preserve-symlinks-flag "^1.0.0"
|
||||
|
||||
@@ -1630,10 +1729,17 @@ rollup-pluginutils@^2.8.2:
|
||||
dependencies:
|
||||
estree-walker "^0.6.1"
|
||||
|
||||
rollup@^2.59.0:
|
||||
version "2.67.3"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.67.3.tgz#3f04391fc296f807d067c9081d173e0a33dbd37e"
|
||||
integrity sha512-G/x1vUwbGtP6O5ZM8/sWr8+p7YfZhI18pPqMRtMYMWSbHjKZ/ajHGiM+GWNTlWyOR0EHIdT8LHU+Z4ciIZ1oBw==
|
||||
rollup@^2.78.1:
|
||||
version "2.79.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
|
||||
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
rollup@~2.78.0:
|
||||
version "2.78.1"
|
||||
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.78.1.tgz#52fe3934d9c83cb4f7c4cb5fb75d88591be8648f"
|
||||
integrity sha512-VeeCgtGi4P+o9hIg+xz4qQpRl6R401LWEXBmxYKOV4zlF82lyhgh2hTZnheFUbANE8l2A41F458iwj2vEYaXJg==
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
@@ -1672,9 +1778,9 @@ semver@^6.0.0:
|
||||
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
|
||||
|
||||
semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
|
||||
version "7.3.8"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
|
||||
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
@@ -1746,6 +1852,11 @@ sourcemap-codec@^1.3.0, sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8:
|
||||
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
|
||||
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
|
||||
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
@@ -1807,10 +1918,10 @@ svelte-check@^2.8.1:
|
||||
svelte-preprocess "^4.0.0"
|
||||
typescript "*"
|
||||
|
||||
svelte-hmr@^0.14.12:
|
||||
version "0.14.12"
|
||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.14.12.tgz#a127aec02f1896500b10148b2d4d21ddde39973f"
|
||||
integrity sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==
|
||||
svelte-hmr@^0.15.0:
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.0.tgz#c8304b5dd33f006415329d91470761d19417a324"
|
||||
integrity sha512-Aw21SsyoohyVn4yiKXWPNCSW2DQNH/76kvUnE9kpt4h9hcg9tfyQc6xshx9hzgMfGF0kVx0EGD8oBMWSnATeOg==
|
||||
|
||||
svelte-preprocess@^4.0.0:
|
||||
version "4.10.3"
|
||||
@@ -1922,10 +2033,12 @@ typescript@~4.8.2:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790"
|
||||
integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==
|
||||
|
||||
undici@^5.8.1:
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/undici/-/undici-5.10.0.tgz#dd9391087a90ccfbd007568db458674232ebf014"
|
||||
integrity sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==
|
||||
undici@^5.11.0:
|
||||
version "5.11.0"
|
||||
resolved "https://registry.yarnpkg.com/undici/-/undici-5.11.0.tgz#1db25f285821828fc09d3804b9e2e934ae86fc13"
|
||||
integrity sha512-oWjWJHzFet0Ow4YZBkyiJwiK5vWqEYoH7BINzJAJOLedZ++JpAlCbUktW2GQ2DS2FpKmxD/JMtWUUWl1BtghGw==
|
||||
dependencies:
|
||||
busboy "^1.6.0"
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
@@ -1944,23 +2057,18 @@ uuid@^8.3.2:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
vite@^2.9.13:
|
||||
version "2.9.13"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.13.tgz#859cb5d4c316c0d8c6ec9866045c0f7858ca6abc"
|
||||
integrity sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==
|
||||
vite@^3.1.0:
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/vite/-/vite-3.1.6.tgz#4c6db3000326342c918204a42a130fb3ffed2414"
|
||||
integrity sha512-qMXIwnehvvcK5XfJiXQUiTxoYAEMKhM+jqCY6ZSTKFBKu1hJnAKEzP3AOcnTerI0cMZYAaJ4wpW1wiXLMDt4mA==
|
||||
dependencies:
|
||||
esbuild "^0.14.27"
|
||||
postcss "^8.4.13"
|
||||
resolve "^1.22.0"
|
||||
rollup "^2.59.0"
|
||||
esbuild "^0.15.9"
|
||||
postcss "^8.4.16"
|
||||
resolve "^1.22.1"
|
||||
rollup "~2.78.0"
|
||||
optionalDependencies:
|
||||
fsevents "~2.3.2"
|
||||
|
||||
web-streams-polyfill@^3.0.3:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6"
|
||||
integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
|
||||
@@ -11,6 +11,7 @@ When using a database, you can still use JWT for session handling for fast acces
|
||||
|
||||
We have a list of official adapters that are distributed as their own packages under the `@next-auth/{name}-adapter` namespace. Their source code is available in their various adapters package directories at [`nextauthjs/next-auth`](https://github.com/nextauthjs/next-auth/tree/main/packages).
|
||||
|
||||
- [`xata`](./xata)
|
||||
- [`prisma`](./prisma)
|
||||
- [`fauna`](./fauna)
|
||||
- [`dynamodb`](./dynamodb)
|
||||
|
||||
242
docs/docs/adapters/xata.md
Normal file
242
docs/docs/adapters/xata.md
Normal file
@@ -0,0 +1,242 @@
|
||||
---
|
||||
id: xata
|
||||
title: Xata
|
||||
---
|
||||
|
||||
# Xata
|
||||
|
||||
This adapter allows using next-auth with Xata as a database to store users, sessions, and more. The preferred way to create a Xata project and use Xata databases is using the [Xata Command Line Interface (CLI)](https://docs.xata.io/cli/getting-started). The CLI allows generating a `XataClient` that will help you work with Xata in a safe way, and that this adapter depends on.
|
||||
|
||||
<!-- @todo add GIFs -->
|
||||
|
||||
## Getting Started
|
||||
|
||||
Let's first make sure we have everything installed and configured. We're going to need:
|
||||
|
||||
- next-auth + adapter
|
||||
- the Xata CLI
|
||||
- to configure the CLI
|
||||
|
||||
We can do this like so:
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
# Install next-auth + adapter
|
||||
npm install next-auth @next-auth/xata-adapter
|
||||
|
||||
# Install the Xata CLI globally if you don't already have it
|
||||
npm install --location=global @xata.io/cli
|
||||
|
||||
# Login
|
||||
xata auth login
|
||||
```
|
||||
|
||||
Now that we're ready, let's create a new Xata project using our next-auth schema that the Xata adapter can work with. To do that, copy and paste this schema file into your project's directory:
|
||||
|
||||
```json title="schema.json"
|
||||
{
|
||||
"formatVersion": "",
|
||||
"tables": [
|
||||
{
|
||||
"name": "nextauth_users",
|
||||
"columns": [
|
||||
{
|
||||
"name": "email",
|
||||
"type": "email"
|
||||
},
|
||||
{
|
||||
"name": "emailVerified",
|
||||
"type": "datetime"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_accounts",
|
||||
"columns": [
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "provider",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "providerAccountId",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "refresh_token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "access_token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "expires_at",
|
||||
"type": "int"
|
||||
},
|
||||
{
|
||||
"name": "token_type",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "scope",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "id_token",
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"name": "session_state",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_verificationTokens",
|
||||
"columns": [
|
||||
{
|
||||
"name": "identifier",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "token",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "expires",
|
||||
"type": "datetime"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_users_accounts",
|
||||
"columns": [
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_accounts"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_users_sessions",
|
||||
"columns": [
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "session",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_sessions"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nextauth_sessions",
|
||||
"columns": [
|
||||
{
|
||||
"name": "sessionToken",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "expires",
|
||||
"type": "datetime"
|
||||
},
|
||||
{
|
||||
"name": "user",
|
||||
"type": "link",
|
||||
"link": {
|
||||
"table": "nextauth_users"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Now, run the following command:
|
||||
|
||||
```bash
|
||||
xata init --schema=./path/to/your/schema.json
|
||||
```
|
||||
|
||||
The CLI will walk you through a setup process where you choose a [workspace](https://docs.xata.io/concepts/workspaces) (kind of like a GitHub org or a Vercel team) and an appropriate database. We recommend using a fresh database for this, as we'll augment it with tables that next-auth needs.
|
||||
|
||||
Once you're done, you can continue using next-auth in your project as expected, like creating a `./pages/api/auth/[...nextauth]` route.
|
||||
|
||||
```typescript title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
|
||||
const client = new XataClient()
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Now to Xata-fy this route, let's add the Xata client and adapter:
|
||||
|
||||
```diff
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
+import { XataAdapter } from "@next-auth/xata-adapter"
|
||||
+import { XataClient } from "../../../xata" // or wherever you've chosen to create the client
|
||||
|
||||
+const client = new XataClient()
|
||||
|
||||
export default NextAuth({
|
||||
+ adapter: XataAdapter(client),
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
This fully sets up your next-auth site to work with Xata.
|
||||
|
||||
## Contributing
|
||||
|
||||
This is an open-source project created by humans, and as such, might have a few issues. If you experience any of these, we recommend [opening issues](https://github.com/nextauthjs/next-auth/issues/new?assignees=&labels=triage&template=1_bug_framework.yml&title=Issue%20on%20Xata%20adapter&description=I%20experienced%20this%20issue:\n##%20Reproduction%20Steps:\n\n-) that can help us solve problems and build reliable software.
|
||||
@@ -24,7 +24,7 @@ export const authOptions: NextAuthOptions = {
|
||||
export default NextAuth(authOptions);
|
||||
```
|
||||
|
||||
In `getServerSideProps`:
|
||||
### In `getServerSideProps`:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
@@ -48,7 +48,8 @@ export async function getServerSideProps(context) {
|
||||
}
|
||||
}
|
||||
```
|
||||
In API routes:
|
||||
|
||||
### In API Routes:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
@@ -68,6 +69,23 @@ export async function handler(req, res) {
|
||||
}
|
||||
```
|
||||
|
||||
### In `app/` directory:
|
||||
|
||||
You can also use `unstable_getServerSession` in Next.js' server components:
|
||||
|
||||
```tsx
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await unstable_getServerSession()
|
||||
return <pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
Currently, the underlying Next.js `cookies()` method does [only provides read access](https://beta.nextjs.org/docs/api-reference/cookies) to the request cookies. This means that the `expires` value is stripped away from `session` in Server Components. Furthermore, there is a hard expiry on sessions, after which the user will be required to sign in again. (The default expiry is 30 days).
|
||||
:::
|
||||
|
||||
## Middleware
|
||||
|
||||
You can use a Next.js Middleware with NextAuth.js to protect your site.
|
||||
|
||||
@@ -13,12 +13,12 @@ When deploying to production, set the `NEXTAUTH_URL` environment variable to the
|
||||
NEXTAUTH_URL=https://example.com
|
||||
```
|
||||
|
||||
If your Next.js application uses a custom base path, specify the route to the API endpoint in full. More informations about the usage of custom base path [here](/getting-started/client#custom-base-path).
|
||||
If your Next.js application uses a custom base path, specify the route to the API endpoint in full. More information about the usage of custom base path [here](/getting-started/client#custom-base-path).
|
||||
|
||||
_e.g. `NEXTAUTH_URL=https://example.com/custom-route/api/auth`_
|
||||
|
||||
:::tip
|
||||
When you're using a custom base path, you will need to pass the `basePath` page prop to the `<SessionProvider>`. More informations [here](/getting-started/client#custom-base-path).
|
||||
When you're using a custom base path, you will need to pass the `basePath` page prop to the `<SessionProvider>`. More information [here](/getting-started/client#custom-base-path).
|
||||
:::
|
||||
|
||||
:::note
|
||||
|
||||
@@ -83,7 +83,7 @@ TWITTER_SECRET=YOUR_TWITTER_CLIENT_SECRET
|
||||
4. Now you can add the provider settings to the NextAuth.js options object. You can add as many OAuth providers as you like, as you can see `providers` is an array.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import TwitterProvider from "next-auth/providers/"
|
||||
import TwitterProvider from "next-auth/providers/twitter"
|
||||
...
|
||||
providers: [
|
||||
TwitterProvider({
|
||||
@@ -173,6 +173,7 @@ interface OAuthConfig {
|
||||
region?: string
|
||||
issuer?: string
|
||||
client?: Partial<ClientMetadata>
|
||||
allowDangerousEmailAccountLinking?: boolean
|
||||
}
|
||||
```
|
||||
|
||||
@@ -278,6 +279,10 @@ If your Provider is OpenID Connect (OIDC) compliant, we recommend using the `wel
|
||||
|
||||
An advanced option, hopefully you won't need it in most cases. `next-auth` uses `openid-client` under the hood, see the docs on this option [here](https://github.com/panva/node-openid-client/blob/main/docs/README.md#new-clientmetadata-jwks-options).
|
||||
|
||||
### `allowDangerousEmailAccountLinking` option
|
||||
|
||||
Normally, when you sign in with an OAuth provider and another account with the same email address already exists, the accounts are not linked automatically. Automatic account linking on sign in is not secure between arbitrary providers and is disabled by default (see our [Security FAQ](https://next-auth.js.org/faq#security)). However, it may be desirable to allow automatic account linking if you trust that the provider involved has securely verified the email address associated with the account. Just set `allowDangerousEmailAccountLinking: true` in your provider configuration to enable automatic account linking.
|
||||
|
||||
## Using a custom provider
|
||||
|
||||
You can use an OAuth provider that isn't built-in by using a custom object.
|
||||
@@ -404,14 +409,27 @@ GoogleProvider({
|
||||
})
|
||||
```
|
||||
|
||||
An example of how to enable automatic account linking:
|
||||
|
||||
```js title=/api/auth/[...nextauth].js
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_CLIENT_ID,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
allowDangerousEmailAccountLinking: true,
|
||||
})
|
||||
```
|
||||
|
||||
### Adding a new built-in provider
|
||||
|
||||
If you think your custom provider might be useful to others, we encourage you to open a PR and add it to the built-in list so others can discover it much more easily!
|
||||
|
||||
You only need to add two changes:
|
||||
You only need to add three changes:
|
||||
|
||||
1. Add your config: [`src/providers/{provider}.ts`](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers)<br />
|
||||
• make sure you use a named default export, like this: `export default function YourProvider`
|
||||
2. Add provider documentation: [`/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/docs/docs/providers)
|
||||
3. Add the new provider name to the `Provider type` dropdown options in [`the provider issue template`](<[http](https://github.com/nextauthjs/next-auth/edit/main/.github/ISSUE_TEMPLATE/2_bug_provider.yml)>)
|
||||
|
||||
That's it! 🎉 Others will be able to discover and use this provider much more easily now!
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function Component() {
|
||||
`useSession()` returns an object containing two values: `data` and `status`:
|
||||
|
||||
- **`data`**: This can be three values: [`Session`](https://github.com/nextauthjs/next-auth/blob/8ff4b260143458c5d8a16b80b11d1b93baa0690f/types/index.d.ts#L437-L444) / `undefined` / `null`.
|
||||
- when the session hasn't been fetched yet, `data` will `undefined`
|
||||
- when the session hasn't been fetched yet, `data` will be `undefined`
|
||||
- in case it failed to retrieve the session, `data` will be `null`
|
||||
- in case of success, `data` will be [`Session`](https://github.com/nextauthjs/next-auth/blob/8ff4b260143458c5d8a16b80b11d1b93baa0690f/types/index.d.ts#L437-L444).
|
||||
- **`status`**: enum mapping to three possible session states: `"loading" | "authenticated" | "unauthenticated"`
|
||||
@@ -290,7 +290,7 @@ export default ({ email }) => (
|
||||
|
||||
### Specifying a `callbackUrl`
|
||||
|
||||
The `callbackUrl` specifies to which URL the user will be redirected after signing in. It defaults to the current URL of a user.
|
||||
The `callbackUrl` specifies to which URL the user will be redirected after signing in. Defaults to the page URL the sign-in is initiated from.
|
||||
|
||||
You can specify a different `callbackUrl` by specifying it as the second argument of `signIn()`. This works for all providers.
|
||||
|
||||
@@ -491,6 +491,8 @@ If set to any value other than zero, it specifies in seconds how often the clien
|
||||
|
||||
The value for `refetchInterval` should always be lower than the value of the session `maxAge` [session option](/configuration/options#session).
|
||||
|
||||
By default, session polling will keep trying, even when the device has no internet access. To circumvent this, you can also set `refetchWhenOffline` to `false`. This will use [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) to only poll when the device is online.
|
||||
|
||||
#### Refetch On Window Focus
|
||||
|
||||
The `refetchOnWindowFocus` option can be used to control whether it automatically updates the session state when you switch a focus on tabs/windows.
|
||||
|
||||
@@ -7,11 +7,8 @@ title: Guides
|
||||
|
||||
We have internal guides in three levels of difficulty.
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<DocCardList items={useCurrentSidebarCategory().items}/>
|
||||
```
|
||||
- [Basics](/guides/basics)
|
||||
- [Fullstack](/guides/fullstack)
|
||||
- [Testing](/guides/testing)
|
||||
|
||||
If you can't find what you're looking for here, maybe take a look at our third-party [tutorials](/tutorials) page.
|
||||
|
||||
@@ -44,8 +44,8 @@ providers: [
|
||||
CredentialsProvider({
|
||||
// The name to display on the sign in form (e.g. "Sign in with...")
|
||||
name: "Credentials",
|
||||
// The credentials is used to generate a suitable form on the sign in page.
|
||||
// You can specify whatever fields you are expecting to be submitted.
|
||||
// `credentials` is used to generate a form on the sign in page.
|
||||
// You can specify which fields should be submitted, by adding keys to the `credentials` object.
|
||||
// e.g. domain, username, password, 2FA token, etc.
|
||||
// You can pass any HTML attribute to the <input> tag through the object.
|
||||
credentials: {
|
||||
@@ -54,7 +54,7 @@ providers: [
|
||||
},
|
||||
async authorize(credentials, req) {
|
||||
// Add logic here to look up the user from the credentials supplied
|
||||
const user = { id: 1, name: "J Smith", email: "jsmith@example.com" }
|
||||
const user = { id: "1", name: "J Smith", email: "jsmith@example.com" }
|
||||
|
||||
if (user) {
|
||||
// Any object returned will be saved in `user` property of the JWT
|
||||
|
||||
@@ -15,6 +15,7 @@ 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.
|
||||
|
||||
|
||||
If someone provides the email address of an _existing account_ when signing in, an email is sent and they are signed into the account associated with that email address when they follow the link in the email.
|
||||
|
||||
:::tip
|
||||
@@ -32,7 +33,7 @@ You can override any of the options to suit your own use case.
|
||||
## Configuration
|
||||
|
||||
1. NextAuth.js does not include `nodemailer` as a dependency, so you'll need to install it yourself if you want to use the Email Provider. Run `npm install nodemailer` or `yarn add nodemailer`.
|
||||
2. You will need an SMTP account; ideally for one of the [services known to work with `nodemailer`](http://nodemailer.com/smtp/well-known/).
|
||||
2. You will need an SMTP account; ideally for one of the [services known to work with `nodemailer`](https://community.nodemailer.com/2-0-0-beta/setup-smtp/well-known-services/).
|
||||
3. There are two ways to configure the SMTP server connection.
|
||||
|
||||
You can either use a connection string or a `nodemailer` configuration object.
|
||||
@@ -250,4 +251,4 @@ By default, NextAuth.js will normalize the email address. It treats values as ca
|
||||
|
||||
:::warning
|
||||
Always make sure this returns a single e-mail address, even if multiple ones were passed in.
|
||||
:::
|
||||
:::
|
||||
|
||||
@@ -30,7 +30,7 @@ providers: [
|
||||
PatreonProvider({
|
||||
clientId: process.env.PATREON_ID,
|
||||
clientSecret: process.env.PATREON_SECRET,
|
||||
}))
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
37
docs/docs/providers/pinterest.md
Normal file
37
docs/docs/providers/pinterest.md
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
id: pinterest
|
||||
title: Pinterest
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
https://developers.pinterest.com/docs/getting-started/authentication/
|
||||
|
||||
## Configuration
|
||||
|
||||
https://developers.pinterest.com/apps/
|
||||
|
||||
## Options
|
||||
|
||||
The **Pinterest Provider** comes with a set of default options:
|
||||
|
||||
- [Pinterest Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/pinterest.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
## Example
|
||||
|
||||
```ts
|
||||
import PinterestProvider from "next-auth/providers/pinterest"
|
||||
...
|
||||
providers: [
|
||||
PinterestProvider({
|
||||
clientId: process.env.PINTEREST_ID,
|
||||
clientSecret: process.env.PINTEREST_SECRET
|
||||
})
|
||||
]
|
||||
...
|
||||
|
||||
:::tip
|
||||
To use in production, make sure the app has standard API access and not trial access
|
||||
:::
|
||||
35
docs/docs/providers/todoist.md
Normal file
35
docs/docs/providers/todoist.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
id: todoist
|
||||
title: Todoist
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
https://developer.todoist.com/guides/#oauth
|
||||
|
||||
## Configuration
|
||||
|
||||
https://developer.todoist.com/appconsole.html
|
||||
|
||||
## Options
|
||||
|
||||
The **Todoist Provider** comes with a set of default options:
|
||||
|
||||
- [Todoist Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/todoist.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import TodoistProvider from "next-auth/providers/todoist";
|
||||
|
||||
...
|
||||
providers: [
|
||||
TodoistProvider({
|
||||
clientId: process.env.TODOIST_ID,
|
||||
clientSecret: process.env.TODOIST_SECRET
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
@@ -3,7 +3,7 @@ id: corporate-proxy
|
||||
title: Add support for HTTP Proxy
|
||||
--
|
||||
|
||||
Using NextAuth.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), uses the built-in Node.js `http` / `https` libraries, which do not support proxys by default. (See: [`http` docs](https://nodejs.org/dist/latest-v16.x/docs/api/http.html), [`https` docs](https://nodejs.org/dist/latest-v16.x/docs/api/https.html)).
|
||||
Using NextAuth.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), uses the built-in Node.js `http` / `https` libraries, which do not support proxys by default. (See: [`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 an additional proxy agent to the http client, such as `https-proxy-agent`. `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).
|
||||
|
||||
|
||||
@@ -62,11 +62,7 @@ export default NextAuth({
|
||||
async session({ session, token }) {
|
||||
return { ...session, user: { username: token.username } }
|
||||
},
|
||||
},
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
jwt: {
|
||||
secret: process.env.JWT_SECRET,
|
||||
},
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -77,7 +73,6 @@ This is then passed back to any API routes and retrieved as such:
|
||||
```js title="/pages/api/doLDAPWork.js"
|
||||
token = await jwt.getToken({
|
||||
req,
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
})
|
||||
const { username, password } = token
|
||||
```
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** @type {import("@docusaurus/types").Config} */
|
||||
module.exports = {
|
||||
title: "NextAuth.js",
|
||||
tagline: "Authentication for Next.js",
|
||||
@@ -6,6 +7,8 @@ module.exports = {
|
||||
favicon: "img/favicon.ico",
|
||||
organizationName: "nextauthjs",
|
||||
projectName: "next-auth",
|
||||
// TODO: remove this once BETA is ready
|
||||
onBrokenLinks: "log",
|
||||
themeConfig: {
|
||||
prism: {
|
||||
theme: require("prism-react-renderer/themes/vsDark"),
|
||||
@@ -30,6 +33,33 @@ module.exports = {
|
||||
src: "img/logo/logo-xs.png",
|
||||
},
|
||||
items: [
|
||||
// TODO: This is the new navigation for the BETA Docs.
|
||||
// Add an env var at build time to switch between this nav
|
||||
// and the old at build time.
|
||||
// {
|
||||
// to: "/beta/getting-started/introduction",
|
||||
// activeBasePath: "/beta/getting-started/",
|
||||
// label: "Getting started",
|
||||
// position: "left",
|
||||
// },
|
||||
// {
|
||||
// to: "/beta/guides/overview",
|
||||
// activeBasePath: "/beta/guides/",
|
||||
// label: "Guides",
|
||||
// position: "left",
|
||||
// },
|
||||
// {
|
||||
// to: "/beta/reference/index",
|
||||
// activeBasePath: "/beta/reference",
|
||||
// label: "Reference",
|
||||
// position: "left",
|
||||
// },
|
||||
// {
|
||||
// to: "/beta/concepts/faq",
|
||||
// activeBasePath: "/beta/concepts",
|
||||
// label: "Concepts",
|
||||
// position: "left",
|
||||
// },
|
||||
{
|
||||
to: "/getting-started/introduction",
|
||||
activeBasePath: "docs",
|
||||
@@ -166,6 +196,10 @@ module.exports = {
|
||||
v3: {
|
||||
label: "v3",
|
||||
},
|
||||
beta: {
|
||||
label: "v4-unreleased",
|
||||
banner: "unreleased",
|
||||
},
|
||||
},
|
||||
},
|
||||
theme: {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "next-auth-docs",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/nextauthjs/docs.git"
|
||||
"url": "git://github.com/nextauthjs/next-auth.git"
|
||||
},
|
||||
"name": "next-auth-docs",
|
||||
"version": "0.2.0",
|
||||
"scripts": {
|
||||
"start": "npm run generate-providers && docusaurus start --no-open --port 8000",
|
||||
"dev": "npm run start",
|
||||
@@ -19,9 +20,6 @@
|
||||
"generate-providers": "node ./scripts/generate-providers.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^2.0.0-beta.21",
|
||||
"@docusaurus/preset-classic": "^2.0.0-beta.21",
|
||||
"@docusaurus/theme-common": "2.0.0-beta.21",
|
||||
"@mdx-js/react": "1.6.22",
|
||||
"@sapphire/docusaurus-plugin-npm2yarn2pnpm": "1.1.3",
|
||||
"classnames": "^2.3.1",
|
||||
@@ -35,8 +33,11 @@
|
||||
"styled-components": "5.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.20",
|
||||
"prettier": "^2.6.2"
|
||||
"@docusaurus/core": "2.1.0",
|
||||
"@docusaurus/module-type-aliases": "2.1.0",
|
||||
"@docusaurus/preset-classic": "2.1.0",
|
||||
"@docusaurus/theme-common": "2.1.0",
|
||||
"@docusaurus/types": "2.1.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -49,9 +50,5 @@
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"singleQuote": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ const ProviderMarquee = React.memo(() => {
|
||||
>
|
||||
{icons.map((icon) => (
|
||||
<Motion
|
||||
key={`marquee-example-company-${icon}`}
|
||||
key={`company-${icon}`}
|
||||
initDeg={randomIntFromInterval(0, 360)}
|
||||
direction={Math.random() > 0.5 ? "clockwise" : "counterclockwise"}
|
||||
velocity={10}
|
||||
|
||||
@@ -16,6 +16,15 @@
|
||||
"value": "1; mode=block"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/beta(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "X-Robots-Tag",
|
||||
"value": "noindex"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"redirects": [
|
||||
|
||||
361
docs/versioned_docs/version-beta/concepts/faq.md
Normal file
361
docs/versioned_docs/version-beta/concepts/faq.md
Normal file
@@ -0,0 +1,361 @@
|
||||
---
|
||||
id: faq
|
||||
title: Frequently Asked Questions
|
||||
---
|
||||
|
||||
## About NextAuth.js
|
||||
|
||||
### Is NextAuth.js commercial software?
|
||||
|
||||
NextAuth.js is an open source project built by individual contributors.
|
||||
|
||||
It is not commercial software and is not associated with a commercial organization.
|
||||
|
||||
---
|
||||
|
||||
## Compatibility
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>What databases does NextAuth.js support?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
You can use NextAuth.js with MySQL, MariaDB, Postgres, MongoDB and SQLite or without a database. (See also: [Databases](/configuration/databases))
|
||||
|
||||
You can use also NextAuth.js with any database using a custom database adapter, or by using a custom credentials authentication provider - e.g. to support signing in with a username and password stored in an existing database.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>What authentication services does NextAuth.js support?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
<p>NextAuth.js includes built-in support for signing in with
|
||||
--------- DISPLAY PROVIDERS HERE ----------
|
||||
(See also: <a href="/configuration/providers/oauth">Providers</a>)
|
||||
</p>
|
||||
|
||||
NextAuth.js also supports email for passwordless sign in, which is useful for account recovery or for people who are not able to use an account with the configured OAuth services (e.g. due to service outage, account suspension or otherwise becoming locked out of an account).
|
||||
|
||||
You can also use a custom based provider to support signing in with a username and password stored in an external database and/or using two factor authentication.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Does NextAuth.js support signing in with a username and password?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js is designed to avoid the need to store passwords for user accounts.
|
||||
|
||||
If you have an existing database of usernames and passwords, you can use a custom credentials provider to allow signing in with a username and password stored in an existing database.
|
||||
|
||||
_If you use a custom credentials provider user accounts will not be persisted in a database by NextAuth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign in without using a session database) must be enabled to use a custom credentials provider._
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Can I use NextAuth.js with a website that does not use Next.js?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js is designed for use with Next.js and Serverless.
|
||||
|
||||
If you are using a different framework for your website, you can create a website that handles sign in with Next.js and then access those sessions on a website that does not use Next.js as long as the websites are on the same domain.
|
||||
|
||||
If you use NextAuth.js on a website with a different subdomain then the rest of your website (e.g. `auth.example.com` vs `www.example.com`) you will need to set a custom cookie domain policy for the Session Token cookie. (See also: [Cookies](/configuration/options#cookies))
|
||||
|
||||
NextAuth.js does not currently support automatically signing into sites on different top level domains (e.g. `www.example.com` vs `www.example.org`) using a single session.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Can I use NextAuth.js with React Native?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js is designed as a secure, confidential client and implements a server side authentication flow.
|
||||
|
||||
It is not intended to be used in native applications on desktop or mobile applications, which typically implement public clients (e.g. with client / secrets embedded in the application).
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Is NextAuth.js supporting TypeScript?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
Yes! Check out the [TypeScript docs](/getting-started/typescript)
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Is NextAuth.js compatible with Next.js 12 Middleware?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
[Next.js Middleware](https://nextjs.org/docs/middleware) is supported. Head over to the [this page](/configuration/nextjs#middleware)
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Databases
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>What databases are supported by NextAuth.js?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js can be used with MySQL, Postgres, MongoDB, SQLite and compatible databases (e.g. MariaDB, Amazon Aurora, Amazon DocumentDB…) or with no database.
|
||||
|
||||
It also provides an Adapter API which allows you to connect it to any database.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>What does NextAuth.js use databases for?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
Databases in NextAuth.js are used for persisting users, OAuth accounts, email sign in tokens and sessions.
|
||||
|
||||
Specifying a database is optional if you don't need to persist user data or support email sign in. If you don't specify a database then JSON Web Tokens will be enabled for session storage and used to store session data.
|
||||
|
||||
If you are using a database with NextAuth.js, you can still explicitly enable JSON Web Tokens for sessions (instead of using database sessions).
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Should I use a database?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
- Using NextAuth.js without a database works well for internal tools - where you need to control who is able to sign in, but when you do not need to create user accounts for them in your application.
|
||||
|
||||
- Using NextAuth.js with a database is usually a better approach for a consumer facing application where you need to persist accounts (e.g. for billing, to contact customers, etc).
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>What database should I use?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
Managed database solutions for MySQL, Postgres and MongoDB (and compatible databases) are well supported from cloud providers such as Amazon, Google, Microsoft and Atlas.
|
||||
|
||||
If you are deploying directly to a particular cloud platform you may also want to consider serverless database offerings they have (e.g. [Amazon Aurora Serverless on AWS](https://aws.amazon.com/rds/aurora/serverless/)).
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
Parts of this section has been moved to its [own page](/security).
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>How do I get Refresh Tokens and Access Tokens for an OAuth account?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js provides a solution for authentication, session management and user account creation.
|
||||
|
||||
NextAuth.js records Refresh Tokens and Access Tokens on sign in (if supplied by the provider) and it will pass them, along with the User ID, Provider and Provider Account ID, to either:
|
||||
|
||||
1. A database - if a database connection string is provided
|
||||
2. The JSON Web Token callback - if JWT sessions are enabled (e.g. if no database specified)
|
||||
|
||||
You can then look them up from the database or persist them to the JSON Web Token.
|
||||
|
||||
Note: NextAuth.js does not currently handle Access Token rotation for OAuth providers for you, however you can check out [this tutorial](/tutorials/refresh-token-rotation) if you want to implement it.
|
||||
|
||||
We also have an [example repository](https://github.com/nextauthjs/next-auth-refresh-token-example) / project based upon NextAuth.js v4 where we demonstrate how to use a refresh token to refresh the provided access token.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>When I sign in with another account with the same email address, why are accounts not linked automatically?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
Automatic account linking on sign in is not secure between arbitrary providers - with the exception of allowing users to sign in via an email addresses as a fallback (as they must verify their email address as part of the flow).
|
||||
|
||||
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
|
||||
|
||||
With automatic account linking on sign in, this can be exploited by bad actors to hijack accounts by creating an OAuth account associated with the email address of another user.
|
||||
|
||||
For this reason it is not secure to automatically link accounts between arbitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by NextAuth.js.
|
||||
|
||||
Automatic account linking is seen on some sites, sometimes insecurely. It can be technically possible to do automatic account linking securely if you trust all the providers involved to ensure they have securely verified the email address associated with the account, but requires placing trust (and transferring the risk) to those providers to handle the process securely.
|
||||
|
||||
Examples of scenarios where this is secure include with an OAuth provider you control (e.g. that only authorizes users internal to your organization) or with a provider you explicitly trust to have verified the users email address.
|
||||
|
||||
Automatic account linking is not a planned feature of NextAuth.js, however there is scope to improve the user experience of account linking and of handling this flow, in a secure way. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved on.
|
||||
|
||||
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in already - was originally a feature in v1.x but has not been present since v2.0, is planned to return in a future release.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Feature Requests
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Why doesn't NextAuth.js support [a particular feature]?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js is an open source project built by individual contributors who are volunteers writing code and providing support in their spare time.
|
||||
|
||||
If you would like NextAuth.js to support a particular feature, the best way to help make it happen is to raise a feature request describing the feature and offer to work with other contributors to develop and test it.
|
||||
|
||||
If you are not able to develop a feature yourself, you can offer to sponsor someone to work on it.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>I disagree with a design decision, how can I change your mind?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
Product design decisions on NextAuth.js are made by core team members.
|
||||
|
||||
You can raise suggestions as feature requests / requests for enhancement.
|
||||
|
||||
Requests that provide the detail requested in the template and follow the format requested may be more likely to be supported, as additional detail prompted in the templates often provides important context.
|
||||
|
||||
Ultimately if your request is not accepted or is not actively in development, you are always free to fork the project under the terms of the ISC License.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## JSON Web Tokens
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3>Does NextAuth.js use JSON Web Tokens?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js by default uses JSON Web Tokens for saving the user's session. However, if you use a [database adapter](/adapters/overview), the database will be used to persist the user's session. You can force the usage of JWT when using a database [through the configuration options](/configuration/options#session). Since v4 all our JWT tokens are now encrypted by default with A256GCM.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3>What are the advantages of JSON Web Tokens?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
JSON Web Tokens can be used for session tokens, but are also used for lots of other things, such as sending signed objects between services in authentication flows.
|
||||
|
||||
- Advantages of using a JWT as a session token include that they do not require a database to store sessions, this can be faster and cheaper to run and easier to scale.
|
||||
|
||||
- JSON Web Tokens in NextAuth.js are secured using cryptographic encryption (JWE) to store the included information directly in a JWT session token. You may then use the token to pass information between services and APIs on the same domain without having to contact a database to verify the included information.
|
||||
|
||||
- You can use JWT to securely store information you do not mind the client knowing even without encryption, as the JWT is stored in a server-readable-only cookie so data in the JWT is not accessible to third party JavaScript running on your site.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3>What are the disadvantages of JSON Web Tokens?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
- You cannot as easily expire a JSON Web Token - doing so requires maintaining a server side blocklist of invalid tokens (at least until they expire) and checking every token against the list every time a token is presented.
|
||||
|
||||
Shorter session expiry times are used when using JSON Web Tokens as session tokens to allow sessions to be invalidated sooner and simplify this problem.
|
||||
|
||||
NextAuth.js client includes advanced features to mitigate the downsides of using shorter session expiry times on the user experience, including automatic session token rotation, optionally sending keep alive messages to prevent short lived sessions from expiring if there is an window or tab open, background re-validation, and automatic tab/window syncing that keeps sessions in sync across windows any time session state changes or a window or tab gains or loses focus.
|
||||
|
||||
- As with database session tokens, JSON Web Tokens are limited in the amount of data you can store in them. There is typically a limit of around 4096 bytes per cookie, though the exact limit varies between browsers, proxies and hosting services. If you want to support most browsers, then do not exceed 4096 bytes per cookie. If you want to save more data, you will need to persist your sessions in a database (Source: [browsercookielimits.iain.guru](http://browsercookielimits.iain.guru/))
|
||||
|
||||
The more data you try to store in a token and the more other cookies you set, the closer you will come to this limit. Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing. However since this data needs to be transmitted on every request, if you wish to store more than ~4 KB of data you're probably at the point where you want to store a unique ID in the token and persist the data elsewhere (e.g. in a server-side key/value store).
|
||||
|
||||
- Data stored in an encrypted JSON Web Token (JWE) may be compromised at some point.
|
||||
|
||||
Even if appropriately configured, information stored in an encrypted JWT should not be assumed to be impossible to decrypt at some point - e.g. due to the discovery of a defect or advances in technology.
|
||||
|
||||
Avoid storing any data in a token that might be problematic if it were to be decrypted in the future.
|
||||
|
||||
- If you do not explicitly specify a secret for for NextAuth.js, existing sessions will be invalidated any time your NextAuth.js configuration changes, as NextAuth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
|
||||
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3>Are JSON Web Tokens secure?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
By default tokens are not signed (JWS) but are encrypted (JWE). Since v4 we have implemented cookie chunking so that cookies over the 4kb limit get split and reassembled upon parsing.
|
||||
|
||||
You can specify other valid algorithms - [as specified in RFC 7518](https://tools.ietf.org/html/rfc7517) - with either a secret (for symmetric encryption) or a public/private key pair (for asymmetric encryption).
|
||||
|
||||
NextAuth.js will generate keys for you, but this will generate a warning at start up.
|
||||
|
||||
Using explicit public/private keys for signing is strongly recommended.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3>What signing and encryption standards does NextAuth.js support?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js includes a largely complete implementation of JSON Object Signing and Encryption (JOSE):
|
||||
|
||||
- [RFC 7515 - JSON Web Signature (JWS)](https://tools.ietf.org/html/rfc7515)
|
||||
- [RFC 7516 - JSON Web Encryption (JWE)](https://tools.ietf.org/html/rfc7516)
|
||||
- [RFC 7517 - JSON Web Key (JWK)](https://tools.ietf.org/html/rfc7517)
|
||||
- [RFC 7518 - JSON Web Algorithms (JWA)](https://tools.ietf.org/html/rfc7518)
|
||||
- [RFC 7519 - JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519)
|
||||
|
||||
This incorporates support for:
|
||||
|
||||
- [RFC 7638 - JSON Web Key Thumbprint](https://tools.ietf.org/html/rfc7638)
|
||||
- [RFC 7787 - JSON JWS Unencoded Payload Option](https://tools.ietf.org/html/rfc7797)
|
||||
- [RFC 8037 - CFRG Elliptic Curve ECDH and Signatures](https://tools.ietf.org/html/rfc8037)
|
||||
|
||||
</p>
|
||||
</details>
|
||||
50
docs/versioned_docs/version-beta/concepts/oauth.md
Normal file
50
docs/versioned_docs/version-beta/concepts/oauth.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: How OAuth works
|
||||
---
|
||||
Authentication Providers in **NextAuth.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)
|
||||
|
||||
:::note
|
||||
NextAuth.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.
|
||||
:::
|
||||
|
||||
Without going into too much detail, the OAuth flow generally has 6 parts:
|
||||
|
||||
1. The application requests authorization to access service resources from the user
|
||||
2. If the user authorized the request, the application receives an authorization grant
|
||||
3. The application requests an access token from the authorization server (API) by presenting authentication of its own identity, and the authorization grant
|
||||
4. If the application identity is authenticated and the authorization grant is valid, the authorization server (API) issues an access token to the application. Authorization is complete.
|
||||
5. The application requests the resource from the resource server (API) and presents the access token for authentication
|
||||
6. If the access token is valid, the resource server (API) serves the resource to the application
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Browser
|
||||
participant App Server
|
||||
participant Auth Server (Github)
|
||||
Note left of Browser: User clicks on "Sign in"
|
||||
Browser->>App Server: GET<br/>"api/auth/signin"
|
||||
App Server->>App Server: Computes the available<br/>sign in providers<br/>from the "providers" option
|
||||
App Server->>Browser: Redirects to Sign in page
|
||||
Note left of Browser: Sign in options<br/>are shown the user<br/>(Github, Twitter, etc...)
|
||||
Note left of Browser: User clicks on<br/>"Sign in with Github"
|
||||
Browser->>App Server: POST<br/>"api/auth/signin/github"
|
||||
App Server->>App Server: Computes sign in<br/>options for Github<br/>(scopes, callback URL, etc...)
|
||||
App Server->>Auth Server (Github): GET<br/>"github.com/login/oauth/authorize"
|
||||
Note left of Auth Server (Github): Sign in options<br> are supplied as<br/>query params<br/>(clientId, <br/>scope, etc...)
|
||||
Auth Server (Github)->>Browser: Shows sign in page<br/>in Github.com<br/>to the user
|
||||
Note left of Browser: User inserts their<br/>credentials in Github
|
||||
Browser->>Auth Server (Github): Github validates the inserted credentials
|
||||
Auth Server (Github)->>Auth Server (Github): Generates one time access code<br/>and calls callback<br>URL defined in<br/>App settings
|
||||
Auth Server (Github)->>App Server: GET<br/>"api/auth/github/callback?code=123"
|
||||
App Server->>App Server: Grabs code<br/>to exchange it for<br/>access token
|
||||
App Server->>Auth Server (Github): POST<br/>"github.com/login/oauth/access_token"<br/>{code: 123}
|
||||
Auth Server (Github)->>Auth Server (Github): Verifies code is<br/>valid and generates<br/>access token
|
||||
Auth Server (Github)->>App Server: { access_token: 16C7x... }
|
||||
App Server->>App Server: Generates session token<br/>and stores session
|
||||
App Server->>Browser: You're now logged in!
|
||||
```
|
||||
|
||||
For more details, check out Aaron Parecki's blog post [OAuth2 Simplified](https://aaronparecki.com/oauth-2-simplified/) or Postman's blog post [OAuth 2.0: Implicit Flow is Dead, Try PKCE Instead](https://blog.postman.com/pkce-oauth-how-to/).
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Introduction
|
||||
---
|
||||
|
||||
## About NextAuth.js
|
||||
|
||||
NextAuth.js is a complete open-source authentication solution for [Next.js](http://nextjs.org/) applications.
|
||||
|
||||
It is designed from the ground up to support Next.js and Serverless.
|
||||
|
||||
[Check out the example code](/getting-started/example) to see how easy it is to use NextAuth.js for authentication.
|
||||
|
||||
### Flexible and easy to use
|
||||
|
||||
- Designed to work with any [OAuth service, it supports OAuth 1.0, 1.0A, 2.0 and OpenID Connect](/providers)
|
||||
- Built-in support for [many popular sign-in services](/configuration/providers/oauth)
|
||||
- Supports [email / passwordless authentication](/providers/email)
|
||||
- Supports stateless authentication with [any backend](/adapters/overview) (Active Directory, LDAP, etc)
|
||||
- Supports both JSON Web Tokens and database sessions
|
||||
- Designed for Serverless but runs anywhere (AWS Lambda, Docker, Heroku, etc…)
|
||||
|
||||
### Own your own data
|
||||
|
||||
NextAuth.js can be used with or without a database.
|
||||
|
||||
- An open-source solution that allows you to keep control of your data
|
||||
- Supports Bring Your Own Database (BYOD) and can be used with any database
|
||||
- Built-in support for [MySQL, MariaDB, Postgres, SQL Server, MongoDB and SQLite](/configuration/databases)
|
||||
- Works great with databases from popular hosting providers
|
||||
- Can also be used _without a database_ (e.g. OAuth + JWT)
|
||||
|
||||
_Note: Email sign-in requires a database to be configured to store single-use verification tokens._
|
||||
|
||||
### Secure by default
|
||||
|
||||
- Promotes the use of passwordless sign-in mechanisms
|
||||
- Designed to be secure by default and encourage best practices for safeguarding user data
|
||||
- Uses Cross-Site Request Forgery Tokens on POST routes (sign in, sign out)
|
||||
- Default cookie policy aims for the most restrictive policy appropriate for each cookie
|
||||
- When JSON Web Tokens are enabled, they are encrypted by default (JWE) with A256GCM
|
||||
- Auto-generates symmetric signing and encryption keys for developer convenience
|
||||
- Features tab/window syncing and keepalive messages to support short-lived sessions
|
||||
- Attempts to implement the latest guidance published by [Open Web Application Security Project](https://owasp.org/)
|
||||
|
||||
Advanced options allow you to define your own routines to handle controlling what accounts are allowed to sign in, for encoding and decoding JSON Web Tokens and to set custom cookie security policies and session properties, so you can control who can sign in and how often sessions have to be re-validated.
|
||||
|
||||
## Credits
|
||||
|
||||
NextAuth.js is an open-source project that is only possible [thanks to contributors](/contributors).
|
||||
|
||||
If you would like to financially support the development of NextAuth.js, you can find more information on our [OpenCollective](https://opencollective.com/nextauth) page.
|
||||
|
||||
## Getting Started
|
||||
|
||||
[Check out the example code](/getting-started/example) to see how easy it is to use NextAuth.js for authentication.
|
||||
@@ -0,0 +1,291 @@
|
||||
---
|
||||
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"
|
||||
|
||||
|
||||
We know, authentication is hard. Is a rabbit hole and it's easy to get lost on it. The goal of making NextAuth.js is that you can add authentication easily to your project with just a few lines of code.
|
||||
|
||||
The easiest way is to setup NextAuth.js with an [OAuth](https://en.wikipedia.org/wiki/OAuth) provider. In this tutorial we'll be setting NextAuth.js in a **Next.js app** to be able to login with **Github**.
|
||||
|
||||
:::info
|
||||
NextAuth.js comes with a long list of [built-in providers](/reference/Providers/) (Google, Facebook, Twitter, etc...) you can also integrate it with your own OAuth service easily by [building a custom provider](/beta/guides/oauth/custom-provider). NextAuth.js can integrate as well with other frameworks like SvelteKit and Gatsby.
|
||||
:::
|
||||
|
||||
## 1. Configuring NextAuth.js
|
||||
|
||||
### Creating the server config
|
||||
|
||||
To add NextAuth.js to a [**Next.js**](https://nextjs.org/) project, create the following [API route](https://nextjs.org/docs/api-routes/introduction):
|
||||
|
||||
```
|
||||
pages/api/auth/[...nextauth].ts
|
||||
```
|
||||
|
||||
This route will contain the **dynamic route handler** for NextAuth.js which describes your global auth configuration:
|
||||
|
||||
```ts title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: /* We'll fill this later */,
|
||||
clientSecret: /* We'll fill this later*/,
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Behind the scenes this creates all the relevant OAuth API routes within `/api/auth/*` so that auth API requests to:
|
||||
|
||||
- `/api/auth/callback`
|
||||
- `/api/auth/signIn`
|
||||
- `/api/auth/singOut`
|
||||
- etc...
|
||||
|
||||
can be handled by NextAuth.js. In this way, NextAuth.js stays in charge of handling the whole authentication request/response flow of your application for you.
|
||||
|
||||
You may notice there are some environment variables in the code example above. `GITHUB_ID` and `GITHUB_SECRET` are provided by the OAuth provider (in this case **Github**) see ["Configuring OAuth Provider"](/getting-started/oauth-tutorial#2-configuring-oauth-provider) section on how to get those.
|
||||
|
||||
`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.
|
||||
|
||||
:::info
|
||||
NextAuth.js is extremely customizable, [our guides section](/beta/guides/overview) will teach you how you can set it up to handle auth in different ways. All the possible configuration options are [listed here](/reference/server/configuration).
|
||||
:::
|
||||
|
||||
### Exposing the session via provider
|
||||
|
||||
To be able to use `useSession` first you'll need to expose the session context, [`<SessionProvider />`](/getting-started/client#sessionprovider), at the top level of your application:
|
||||
|
||||
```ts title="pages/_app.ts"
|
||||
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 then have access to the session data and status. The `<SessionProvider />` also takes care of keeping the session updated and synced between browser tabs and windows. 💪🏽
|
||||
|
||||
:::tip
|
||||
Check our [client docs](/reference/client/introduction) to learn all the available options for handling sessions on the browser.
|
||||
:::
|
||||
|
||||
### Consuming the session via hooks
|
||||
|
||||
NextAuth.js exposes a [`useSession()`](/getting-started/client#usesession) React Hook so that you can easily check if someone is signed in:
|
||||
|
||||
```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" />
|
||||
</img>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>Not signed in.</p>
|
||||
<button onClick={() => signIn()}>Sign in</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Protecting API Routes
|
||||
|
||||
Protecting your custom API Routes (.i.e not allowing a resource to be accessed in case the user is not logged in) is easy! You can use [`getSession()`](/getting-started/client#getsession) to know whether a session exists or not:
|
||||
|
||||
```ts title="pages/api/movies/list.ts"
|
||||
import { getSession } from "next-auth/react"
|
||||
|
||||
export default async function listMovies(req, res) {
|
||||
const session = await getSession({ req })
|
||||
|
||||
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.",
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Configuring OAuth Provider
|
||||
|
||||
Ok, we have our Next.js app setup with NextAuth, 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 Next.js 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 into **Github**, go to `Settings / Developers / OAuth Apps` and click on "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:
|
||||
```
|
||||
http://localhost:3000/api/auth/callback/github
|
||||
```
|
||||
|
||||
:::info
|
||||
NextAuth.js will already magically 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 the port `3000`, hence the origin is `http://localhost:3000`.
|
||||
:::
|
||||
|
||||
Next you'll be presented with the following screen which presents all the configuration for your new OAuth app. For now, let's we need two things from it: the **Client ID** and **Client Secret** for our new OAuth app:
|
||||
|
||||
<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 shared with people outside your organization. With tem a malicious actor could hijack your application and cause you and your user serious problems!
|
||||
:::
|
||||
|
||||
Now let's copy both the Client ID and Client Secret and paste them in an environment file in the root of your project like so:
|
||||
```title=".env.local"
|
||||
GITHUB_ID=12345
|
||||
GITHUB_SECRET=67890
|
||||
```
|
||||
|
||||
Cool! We have finished the 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 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 NextAuth.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:
|
||||
|
||||
```ts title="pages/api/auth/[...nextauth].js"
|
||||
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
|
||||
```
|
||||
You should see the following page:
|
||||
|
||||
<img src={startAppAndSignInImg} />
|
||||
|
||||
Click on "Sign in" and then on "Sign in with Github": NextAuth.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 sessions safely in the background:
|
||||
|
||||
<img src={nextAuthUserLoggedIn} />
|
||||
|
||||
Great! We have completed the whole E2E authentication flow setup so that users can login in our application through Github!
|
||||
|
||||
:::info
|
||||
You can create your own Sign In page instead of using the default one from NextAuth.js. You can learn how to do so in our dedicated guide for it.
|
||||
:::
|
||||
|
||||
## 4. Deploying to production
|
||||
|
||||
### Configuring different environments
|
||||
|
||||
It's normal to test your application under different environments. Usually you'll have a development environment (when you run the application locally in your machine), a staging environment (for teams members to try the application) and a production environment.
|
||||
|
||||
For each environment, you're going to 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 again 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 just 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 against.
|
||||
|
||||
### Setting up `NEXTAUTH_URL`
|
||||
|
||||
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](/deployment).
|
||||
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
title: Email authentication
|
||||
---
|
||||
|
||||
import smtpConfig from "./img/dashboard-smtp.png"
|
||||
import startPageImg from "./img/email-tutorial-start.png"
|
||||
import checkPageImg from "./img/email-tutorial-check.png"
|
||||
import mailboxImg from "./img/email-tutorial-mailbox.png"
|
||||
import loggedInImg from "./img/email-tutorial-logged.png"
|
||||
|
||||
Aside from authenticating users in NextAuth.js via [OAuth](/getting-started/oauth-tutorial), you can also enable the option to authenticate them via "magic links". These are links that are sent to the user's email and when clicking on them they'll sign up the user automatically.
|
||||
|
||||
Adding support for signing in via email in addition to one or more OAuth services provides a way for users to sign in if they lose access to their OAuth account (e.g. if it is locked or deleted).
|
||||
|
||||
The Email provider can be used in conjunction with (or instead of) one or more OAuth providers.
|
||||
|
||||
## How it works
|
||||
|
||||
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.
|
||||
|
||||
:::tip
|
||||
The Email Provider can be used with both JSON Web Tokens and database sessions, but you [must configure a database adapter](/beta/guides/adapters/setting-up-a-database-adapter) to use it. It is not possible to enable email sign in without using a database.
|
||||
:::
|
||||
|
||||
## 1. Installing `nodemailer`
|
||||
|
||||
[`nodemailer`](https://www.npmjs.com/package/nodemailer) is a [peer dependency](https://nodejs.org/en/blog/npm/peer-dependencies/) when using the Email Provider. This means we need to install before we can start sending emails:
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install -D nodemailer
|
||||
```
|
||||
|
||||
`nodemailer` will enable us to send emails from NodeJS, which the runtime on which Next.js application operate.
|
||||
|
||||
## 2. Setting up a SMTP service
|
||||
|
||||
Next we need a [SMTP service](https://sendgrid.com/blog/what-is-an-smtp-server/) which will be in charge of sending emails from our application. There's a number of services available for this, however [here are the ones](http://nodemailer.com/smtp/well-known/) known to work with `nodemailer`.
|
||||
|
||||
:::info
|
||||
For this tutorial, we're gonna 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:
|
||||
|
||||
<img src={smtpConfig} />
|
||||
|
||||
Next paste the API in your terminal as so, and run the command:
|
||||
```bash
|
||||
echo -n '<YOUR_API_KEY>' | openssl base64
|
||||
```
|
||||
|
||||
Next, as [per Sendgrid documentation](https://docs.sendgrid.com/for-developers/sending-email/integrating-with-the-smtp-api), let's add the following [environment variables](https://nextjs.org/docs/basic-features/environment-variables) in our Next.js app:
|
||||
|
||||
```bash title=".env.local"
|
||||
SMTP_USER=apikey
|
||||
SMTP_PASSWORD={API_KEY}
|
||||
SMTP_HOST=smtp.sendgrid.net
|
||||
SMTP_PROT=587
|
||||
EMAIL_FROM={SENDER_EMAIL}
|
||||
```
|
||||
|
||||
Note that we're also specifying from which domain email are going to be sent from. You're gonna need to verify [a sender identity](https://docs.sendgrid.com/for-developers/sending-email/sender-identity) so that Sendgrid can send emails from your domain.
|
||||
|
||||
Nice! We're getting there. Now we need to read supply this values as the configuration for our Email Provider. Open `pages/api/auth/[...nextauth].ts` and do the following:
|
||||
|
||||
```ts title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import EmailProvider from "next-auth/providers/email"
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
Email({
|
||||
server: {
|
||||
host: process.env.EMAIL_SERVER_HOST,
|
||||
port: Number(process.env.EMAIL_SERVER_PORT),
|
||||
auth: {
|
||||
user: process.env.EMAIL_SERVER_USER,
|
||||
pass: process.env.EMAIL_SERVER_PASSWORD
|
||||
}
|
||||
},
|
||||
from: process.env.EMAIL_FROM
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## 3. Setting up an adapter
|
||||
|
||||
Finally, we'll need to set up a database adapter to store verification tokens the Email Provider will emit when verifying users.
|
||||
|
||||
An **Adapter** in NextAuth.js connects your application to whatever database or backend system you want to use to store data for users, their accounts, sessions, etc...
|
||||
|
||||
For this tutorial, we're going to use the **MongoDB** adapter, other any of the other adapters will work just fine.
|
||||
|
||||
First, let's start by installing the adapter package:
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install -D @next-auth/mongodb-adapter mongodb
|
||||
```
|
||||
|
||||
and create a simple MongoDB client:
|
||||
|
||||
```ts title="lib/mongodb/client.ts"
|
||||
// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
|
||||
import { MongoClient } from "mongodb"
|
||||
|
||||
const uri = process.env.MONGODB_URI
|
||||
const options = {
|
||||
useUnifiedTopology: true,
|
||||
useNewUrlParser: true,
|
||||
}
|
||||
|
||||
let client
|
||||
let clientPromise
|
||||
|
||||
if (!process.env.MONGODB_URI) {
|
||||
throw new Error("Please add your Mongo URI to .env.local")
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
// In development mode, use a global variable so that the value
|
||||
// is preserved across module reloads caused by HMR (Hot Module Replacement).
|
||||
if (!global._mongoClientPromise) {
|
||||
client = new MongoClient(uri, options)
|
||||
global._mongoClientPromise = client.connect()
|
||||
}
|
||||
clientPromise = global._mongoClientPromise
|
||||
} else {
|
||||
// In production mode, it's best to not use a global variable.
|
||||
client = new MongoClient(uri, options)
|
||||
clientPromise = client.connect()
|
||||
}
|
||||
|
||||
// Export a module-scoped MongoClient promise. By doing this in a
|
||||
// separate module, the client can be shared across functions.
|
||||
export default clientPromise
|
||||
```
|
||||
And now let's reference this new adapter from our NextAuth.js configuration file:
|
||||
|
||||
```diff title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import EmailProvider from "next-auth/providers/email"
|
||||
+ import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
|
||||
+ import clientPromise from "../../../lib/mongodb/client"
|
||||
|
||||
export default NextAuth({
|
||||
secret: process.env.NEXTAUTH_SECRET,
|
||||
providers: [
|
||||
+ adapter: MongoDBAdapter(clientPromise),
|
||||
EmailProvider({
|
||||
server: {
|
||||
host: process.env.EMAIL_SERVER_HOST,
|
||||
port: process.env.EMAIL_SERVER_PORT,
|
||||
auth: {
|
||||
user: process.env.EMAIL_SERVER_USER,
|
||||
pass: process.env.EMAIL_SERVER_PASSWORD
|
||||
}
|
||||
},
|
||||
from: process.env.EMAIL_FROM
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## 4. Wiring all together
|
||||
|
||||
Now that everything is properly configured, let's try to sign in via email on our application.
|
||||
|
||||
Let's start by running a Next.js application with NextAuth, making sure the **EmailProvider** and a Database Adapter are properly configured as per the instructions above.
|
||||
|
||||
For this tutorial we're gonna be using NextAuth example app. Launch the app and click on "Sign in", we're redirected to the Sign In page:
|
||||
|
||||
<img src={startPageImg} alt="Screenshot of sign in page" />
|
||||
|
||||
:::info
|
||||
You can customize the look and feel of your Sign in page pretty easily with NextAuth. Refer to our [pages guide](/beta/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:
|
||||
|
||||
<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):
|
||||
|
||||
<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.
|
||||
|
||||
Click on "Sign in" and a new browser tab will open, you should then land on your application as authenticated!
|
||||
|
||||
<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!
|
||||
|
||||
:::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.
|
||||
:::
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Credentials authentication
|
||||
---
|
||||
|
||||
NextAuth.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.
|
||||
|
||||
In case you already have an authentication service, you can use the Credentials Provider, which will just forward the credentials inserted by the user in the login form to your service.
|
||||
|
||||
For this tutorial, we're going to use [NextAuth.js example app](https://github.com/nextauthjs/next-auth-example) as a base.
|
||||
|
||||
:::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.
|
||||
:::
|
||||
|
||||
Integrating the Credentials Provider is as simple as initializing it in the NextAuth.js configuration file:
|
||||
|
||||
```ts title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
import CredentialsProvider from "next-auth/providers/credentials"
|
||||
|
||||
export default NextAuth({
|
||||
providers: [
|
||||
CredentialsProvider({
|
||||
async authorize(credentials) {
|
||||
const authResponse = await fetch('/users/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(credentials)
|
||||
})
|
||||
|
||||
if (!authResponse.ok) {
|
||||
return null
|
||||
}
|
||||
|
||||
const user = await authResponse.json()
|
||||
|
||||
return user
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
:::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.
|
||||
:::
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
---
|
||||
title: TypeScript
|
||||
---
|
||||
|
||||
NextAuth.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
|
||||
|
||||
---
|
||||
|
||||
## Adapters
|
||||
|
||||
If you're writing your own custom Adapter, you can take advantage of the types to make sure your implementation conforms to what's expected:
|
||||
|
||||
```ts
|
||||
import type { Adapter } from "next-auth/adapters"
|
||||
|
||||
function MyAdapter(): Adapter {
|
||||
return {
|
||||
// your adapter methods here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When writing your own custom Adapter in plain JavaScript, note that you can use **JSDoc** to get helpful editor hints and auto-completion like so:
|
||||
|
||||
```js
|
||||
/** @return { import("next-auth/adapters").Adapter } */
|
||||
function MyAdapter() {
|
||||
return {
|
||||
// your adapter methods here
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::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.
|
||||
:::
|
||||
|
||||
## Module Augmentation
|
||||
|
||||
`next-auth` comes with certain types/interfaces that are shared across submodules. Good examples are `Session` and `JWT`. Ideally, you should only need to create these types at a single place, and TS should pick them up in every location where they are referenced. Luckily, Module Augmentation is exactly that, which can do this for us. Define your shared interfaces in a single place, and get type-safety across your application when using `next-auth` (or one of its submodules).
|
||||
|
||||
### Main module
|
||||
|
||||
Let's look at `Session`:
|
||||
|
||||
```ts title="pages/api/auth/[...nextauth].ts"
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
export default NextAuth({
|
||||
callbacks: {
|
||||
session({ session, token, user }) {
|
||||
return session // The return type will match the one returned in `useSession()`
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
```ts title="pages/index.ts"
|
||||
import { useSession } from "next-auth/react"
|
||||
|
||||
export default function IndexPage() {
|
||||
// `session` will match the returned value of `callbacks.session()` from `NextAuth()`
|
||||
const { data: session } = useSession()
|
||||
|
||||
return (
|
||||
// Your component
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
To extend/augment this type, create a `types/next-auth.d.ts` file in your project:
|
||||
|
||||
```ts title="types/next-auth.d.ts"
|
||||
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 {
|
||||
user: {
|
||||
/** The user's postal address. */
|
||||
address: string
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Extend default interface properties
|
||||
|
||||
By default, TypeScript will merge new interface properties and overwrite existing ones. In this case, the default session user properties will be overwritten, with the new one defined above.
|
||||
|
||||
If you want to keep the default session user properties, you need to add them back into the newly declared interface:
|
||||
|
||||
```ts title="types/next-auth.d.ts"
|
||||
import NextAuth, { DefaultSession } from "next-auth"
|
||||
|
||||
declare module "next-auth" {
|
||||
/**
|
||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||
*/
|
||||
interface Session {
|
||||
user: {
|
||||
/** The user's postal address. */
|
||||
address: string
|
||||
} & DefaultSession["user"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Popular interfaces to augment
|
||||
|
||||
Although you can augment almost anything, here are some of the more common interfaces that you might want to override in the `next-auth` module:
|
||||
|
||||
```ts
|
||||
/**
|
||||
* The shape of the user object returned in the OAuth providers' `profile` callback,
|
||||
* or the second parameter of the `session` callback, when using a database.
|
||||
*/
|
||||
interface User {}
|
||||
/**
|
||||
* Usually contains information about the provider being used
|
||||
* and also extends `TokenSet`, which is different tokens returned by OAuth Providers.
|
||||
*/
|
||||
interface Account {}
|
||||
/** The OAuth profile returned from your provider */
|
||||
interface Profile {}
|
||||
```
|
||||
|
||||
Make sure that the `types` folder is added to [`typeRoots`](https://www.typescriptlang.org/tsconfig/#typeRoots) in your project's `tsconfig.json` file.
|
||||
|
||||
### Submodules
|
||||
|
||||
The `JWT` interface can be found in the `next-auth/jwt` submodule:
|
||||
|
||||
```ts title="types/next-auth.d.ts"
|
||||
import { JWT } from "next-auth/jwt"
|
||||
|
||||
declare module "next-auth/jwt" {
|
||||
/** Returned by the `jwt` callback and `getToken`, when using JWT sessions */
|
||||
interface JWT {
|
||||
/** OpenID ID Token */
|
||||
idToken?: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Useful links
|
||||
|
||||
1. [TypeScript documentation: Module Augmentation](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation)
|
||||
2. [Digital Ocean: Module Augmentation in TypeScript](https://www.digitalocean.com/community/tutorials/typescript-module-augmentation)
|
||||
|
||||
## Contributing
|
||||
|
||||
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!
|
||||
|
||||
:::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.
|
||||
:::
|
||||
@@ -0,0 +1,13 @@
|
||||
# Databases
|
||||
|
||||
NextAuth.js offers multiple database adapters. Check out [the overview](/adapters/overview).
|
||||
|
||||
> As of **v4** NextAuth.js no longer ships with an adapter included by default. If you would like to persist any information, you need to install one of the many available adapters yourself. See the individual adapter documentation pages for more details.
|
||||
|
||||
To learn more about databases in NextAuth.js and how they are used, check out [databases in the FAQ](/faq#databases).
|
||||
|
||||
---
|
||||
|
||||
## How to use a database
|
||||
|
||||
See the [documentation for adapters](/adapters/overview) for more information on advanced configuration, including how to use NextAuth.js with other databases using a [custom adapter](/tutorials/creating-a-database-adapter).
|
||||
@@ -0,0 +1,26 @@
|
||||
# Security
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
NextAuth.js practices responsible disclosure.
|
||||
|
||||
We request that you contact us directly to report serious issues that might impact the security of sites using NextAuth.js.
|
||||
|
||||
If you contact us regarding a serious issue:
|
||||
|
||||
- We will endeavor to get back to you within 72 hours.
|
||||
- We will aim to publish a fix within 30 days.
|
||||
- We will disclose the issue (and credit you, with your consent) once a fix to resolve the issue has been released.
|
||||
- If 90 days has elapsed and we still don't have a fix, we will disclose the issue publicly.
|
||||
|
||||
The best way to report an issue is by contacting us via email at info@balazsorban.com or me@iaincollins.com and yo@ndo.dev, or raise a public issue requesting someone get in touch with you via whatever means you prefer for more details. (Please do not disclose sensitive details publicly at this stage.)
|
||||
|
||||
:::note
|
||||
For less serious issues (e.g. RFC compliance for unsupported flows or potential issues that may cause a problem in the future) it is appropriate to make these public as bug reports or feature requests or to raise a question to open a discussion around them.
|
||||
:::
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Security updates are only released for the current version.
|
||||
|
||||
Old releases are not maintained and do not receive updates.
|
||||
@@ -0,0 +1,612 @@
|
||||
---
|
||||
title: Upgrade Guide (v4)
|
||||
---
|
||||
|
||||
NextAuth.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](https://next-auth.js.org/getting-started/client#options)
|
||||
- `options`: Not exposed anymore, [use `SessionProvider` props](https://next-auth.js.org/getting-started/client#options)
|
||||
- `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](/configuration/providers/oauth#options) 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](https://next-auth.js.org/getting-started/client#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](/configuration/options) 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
|
||||
// [...nextauth.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`](/configuration/providers/email#options-1#:~:text=sendVerificationRequest) 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 [configuration/pages](https://next-auth.js.org/configuration/pages#theming).
|
||||
|
||||
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://next-auth.js.org/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](/tutorials/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 NextAuth.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](/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](/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](/adapters/models).
|
||||
|
||||
### Database migration
|
||||
|
||||
NextAuth.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 NextAuth.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 NextAuth.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 NextAuth.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 NextAuth.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 NextAuth.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 NextAuth.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 NextAuth.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 NextAuth.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`
|
||||
|
||||
NextAuth.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](https://next-auth.js.org/configuration/options#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 NextAuth.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](https://next-auth.js.org/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](https://next-auth.js.org/configuration/options#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.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Contributors
|
||||
|
||||
## Core team
|
||||
|
||||
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)
|
||||
- [Nico Domino](https://github.com/ndom91) - Maintainer (Core, Documentation)
|
||||
- [Lluis Agusti](https://github.com/lluia) - Maintainer (Documentation, Testing, TypeScript)
|
||||
|
||||
## 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 original testing automations.
|
||||
|
||||
- [Lori Karikari](https://github.com/LoriKarikari)
|
||||
- [Fredrik Pettersen](https://github.com/Fumler)
|
||||
- [Gerald Nolan](https://github.com/geraldnolan)
|
||||
- [Jefferson Bledsoe](https://github.com/JeffersonBledsoe)
|
||||
|
||||
## Other contributors
|
||||
|
||||
NextAuth.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 help shaped NextAuth.js.
|
||||
|
||||
## Open Collective
|
||||
|
||||
You can find NextAuth.js on Open Collective. We are very thankful for all of our existing contributors and would be delighted if you or your company would decide to join them.
|
||||
|
||||
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.
|
||||
|
||||
- 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 2021, efforts have started to move NextAuth.js to other frameworks and to support as many databases and providers as possible.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user