mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
118 Commits
next-auth@
...
next-auth@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
777b7b2f23 | ||
|
|
6132c3fa75 | ||
|
|
94beef77e6 | ||
|
|
490d59dd17 | ||
|
|
26a8c5fc6d | ||
|
|
e26ec74720 | ||
|
|
d13997e140 | ||
|
|
d6efda077d | ||
|
|
0a4b99de3b | ||
|
|
2d2dfecc9d | ||
|
|
2a2c3d7a45 | ||
|
|
82786ac440 | ||
|
|
dfe3e02132 | ||
|
|
92b38ed740 | ||
|
|
97feae7916 | ||
|
|
24945895e9 | ||
|
|
6deccf610f | ||
|
|
f770b90219 | ||
|
|
87f4786917 | ||
|
|
191ef06471 | ||
|
|
75e6d8f0aa | ||
|
|
17999edd30 | ||
|
|
54b1845e58 | ||
|
|
879faf9fab | ||
|
|
3e3c36891e | ||
|
|
ac5d8a9795 | ||
|
|
965c6267e2 | ||
|
|
bfc429d20b | ||
|
|
2d8e910a19 | ||
|
|
d16e04848e | ||
|
|
ff3a52895b | ||
|
|
e6e03e8842 | ||
|
|
715aad9474 | ||
|
|
902bf92a85 | ||
|
|
44f2a47e6e | ||
|
|
a3b92dbaec | ||
|
|
bdd3ab2816 | ||
|
|
ba55f06585 | ||
|
|
d2b877fb28 | ||
|
|
658b22d9fb | ||
|
|
a0beb02f77 | ||
|
|
5727c5f4e6 | ||
|
|
8104cb1287 | ||
|
|
44aaa6f1c3 | ||
|
|
ba20974b5f | ||
|
|
14b4ed1d8a | ||
|
|
6b3a82d1f5 | ||
|
|
600aaaa7e6 | ||
|
|
f1d3bc26f9 | ||
|
|
78664aab37 | ||
|
|
aeb3a44b27 | ||
|
|
d3571e01ba | ||
|
|
3b7c9886c3 | ||
|
|
39fec738c6 | ||
|
|
fa58143c6b | ||
|
|
26fb89e3c4 | ||
|
|
a82cbf5ddf | ||
|
|
24db833685 | ||
|
|
c57a810042 | ||
|
|
d980fa986b | ||
|
|
4676352ae0 | ||
|
|
c8780122b3 | ||
|
|
3131971e2c | ||
|
|
448ec1017a | ||
|
|
0e9404ebc1 | ||
|
|
d349ae2b1b | ||
|
|
32f4d5000e | ||
|
|
7f2dbfc65b | ||
|
|
a03657e615 | ||
|
|
3e312d0df1 | ||
|
|
d9167bbffe | ||
|
|
526a6c1adc | ||
|
|
ad03a4efc1 | ||
|
|
424af6cbc5 | ||
|
|
a3c6786f78 | ||
|
|
385037ab33 | ||
|
|
26a03da621 |
40
.eslintrc.js
Normal file
40
.eslintrc.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const path = require("path")
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
overrides: [
|
||||
{
|
||||
files: ["*.ts", "*.tsx"],
|
||||
extends: ["standard-with-typescript", "prettier"],
|
||||
rules: {
|
||||
camelcase: "off",
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
},
|
||||
|
||||
parserOptions: {
|
||||
project: [
|
||||
path.resolve(__dirname, "./packages/**/tsconfig.eslint.json"),
|
||||
path.resolve(__dirname, "./apps/**/tsconfig.json"),
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
extends: ["prettier"],
|
||||
globals: {
|
||||
localStorage: "readonly",
|
||||
location: "readonly",
|
||||
fetch: "readonly",
|
||||
},
|
||||
rules: {
|
||||
camelcase: "off",
|
||||
},
|
||||
plugins: ["jest"],
|
||||
env: {
|
||||
"jest/globals": true,
|
||||
},
|
||||
ignorePatterns: [".eslintrc.js"],
|
||||
}
|
||||
1
.github/ISSUE_TEMPLATE/1_bug_framework.yml
vendored
1
.github/ISSUE_TEMPLATE/1_bug_framework.yml
vendored
@@ -5,6 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thanks for taking the time to fill out this issue after reading/searching through the [documentation](https://next-auth.js.org) first!
|
||||
Is this your first time contributing? Check out this video: https://www.youtube.com/watch?v=cuoNzXFLitc
|
||||
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
2
.github/ISSUE_TEMPLATE/2_bug_provider.yml
vendored
@@ -5,6 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thanks for taking the time to fill out this [Provider](https://next-auth.js.org/providers/overview) related issue!
|
||||
Is this your first time contributing? Check out this video: https://www.youtube.com/watch?v=cuoNzXFLitc
|
||||
|
||||
@@ -67,6 +68,7 @@ body:
|
||||
- "Slack"
|
||||
- "Spotify"
|
||||
- "Strava"
|
||||
- "Todoist"
|
||||
- "Trakt"
|
||||
- "Twitch"
|
||||
- "Twitter"
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
2
.github/ISSUE_TEMPLATE/3_bug_adapter.yml
vendored
@@ -5,6 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thanks for taking the time to fill out this [Adapter](https://next-auth.js.org/adapters/overview) related issue!
|
||||
Is this your first time contributing? Check out this video: https://www.youtube.com/watch?v=cuoNzXFLitc
|
||||
|
||||
@@ -32,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
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
1
.github/ISSUE_TEMPLATE/5_feature_request.yml
vendored
@@ -9,6 +9,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Thank you very much for reaching out to us regarding the awesome feature that you believe should be included in the NextAuth.js library.
|
||||
|
||||
_NOTE: Feature requests are converted to [discussions (Ideas 💡)](https://github.com/nextauthjs/next-auth/discussions/categories/ideas). Make sure your idea hasn't been asked yet, and upvote the existing one before opening a new instead._
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/6_typescript.yml
vendored
1
.github/ISSUE_TEMPLATE/6_typescript.yml
vendored
@@ -17,6 +17,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
Make sure you [link]() to external documentation if necessary and provide inline code examples like so:
|
||||
|
||||
```js
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/7_question.yml
vendored
1
.github/ISSUE_TEMPLATE/7_question.yml
vendored
@@ -9,6 +9,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
**NOTE:** Issues that are potentially security related should be reported to us by following the [Security guidelines](https://next-auth.js.org/security) rather than on GitHub.
|
||||
We are glad that you have a question about this library. Please provide the following information:
|
||||
|
||||
- type: textarea
|
||||
|
||||
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -5,9 +5,14 @@ Please fill out the information below to expedite the review and (hopefully)
|
||||
merge of your pull request!
|
||||
-->
|
||||
|
||||
> _NOTE_:
|
||||
>
|
||||
> - It's a good idea to open an issue first to discuss potential changes.
|
||||
> - Please make sure that you are _NOT_ opening a PR to fix a potential security vulnerability. Instead, please follow the [Security guidelines](../Security.md) to disclose the issue to us confidentially.
|
||||
|
||||
## ☕️ Reasoning
|
||||
|
||||
What changes are being made? What feature/bug is being fixed here?
|
||||
<!-- What changes are being made? What feature/bug is being fixed here? -->
|
||||
|
||||
## 🧢 Checklist
|
||||
|
||||
@@ -23,6 +28,7 @@ Fixes: INSERT_ISSUE_LINK_HERE
|
||||
|
||||
## 📌 Resources
|
||||
|
||||
- [Contributing guidelines](./CONTRIBUTING.md)
|
||||
- [Code of conduct](./CODE_OF_CONDUCT.md)
|
||||
- [Security guidelines](../Security.md)
|
||||
- [Contributing guidelines](../CONTRIBUTING.md)
|
||||
- [Code of conduct](../CODE_OF_CONDUCT.md)
|
||||
- [Contributing to Open Source](https://kcd.im/pull-request)
|
||||
|
||||
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/version-pr/action.yml
vendored
2
.github/version-pr/action.yml
vendored
@@ -4,5 +4,5 @@ outputs:
|
||||
version:
|
||||
description: "npm package version"
|
||||
runs:
|
||||
using: "node16"
|
||||
using: "node18"
|
||||
main: "index.js"
|
||||
|
||||
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
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,6 +35,7 @@ packages/next-auth/core
|
||||
packages/next-auth/jwt
|
||||
packages/next-auth/react
|
||||
packages/next-auth/adapters.d.ts
|
||||
packages/next-auth/adapters.js
|
||||
packages/next-auth/index.d.ts
|
||||
packages/next-auth/index.js
|
||||
packages/next-auth/next
|
||||
|
||||
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting info@balazsorban.com, yo@ndo.dev, thvu@hey.com and me@iaincollins.com.
|
||||
reported by contacting hi@thvu.dev, info@balazsorban.com, yo@ndo.dev and me@iaincollins.com.
|
||||
All complaints will be reviewed and investigated and will result in a response
|
||||
that is deemed necessary and appropriate to the circumstances. The project team
|
||||
is obligated to maintain confidentiality with regard to the reporter of an
|
||||
|
||||
@@ -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! 🎉
|
||||
|
||||
@@ -13,9 +13,9 @@ If you contact us regarding a serious issue:
|
||||
- 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, yo@ndo.dev, thvu@hey.com and me@iaincollins.com, 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.)
|
||||
The best way to report an issue is by contacting us via email at hi@thvu.dev, info@balazsorban.com, yo@ndo.dev and me@iaincollins.com, 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.)
|
||||
|
||||
> 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 submit these these publically as bug reports or feature requests or to raise a question to open a discussion around them.
|
||||
> 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 submit these publicly as bug reports or feature requests or to raise a question to open a discussion around them.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
|
||||
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>
|
||||
)
|
||||
}
|
||||
7
apps/dev/app/server-component/page.tsx
Normal file
7
apps/dev/app/server-component/page.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "pages/api/auth/[...nextauth]"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await unstable_getServerSession(authOptions)
|
||||
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,6 +4,6 @@ module.exports = {
|
||||
config.experiments = { ...config.experiments, topLevelAwait: true }
|
||||
return config
|
||||
},
|
||||
experimental: { appDir: true },
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
experimental: { externalDir: true },
|
||||
}
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rm -rf .next",
|
||||
"copy:css": "cpx \"../../packages/next-auth/css/**/*\" src/css --watch",
|
||||
"watch:css": "cd ../../packages/next-auth && pnpm watch:css",
|
||||
"dev": "concurrently \"pnpm dev:next\" \"pnpm watch:css\" \"pnpm copy:css\"",
|
||||
"dev:next": "next dev",
|
||||
"dev": "next dev",
|
||||
"lint": "next lint",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"email": "fake-smtp-server",
|
||||
@@ -21,7 +19,8 @@
|
||||
"@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",
|
||||
"react-dom": "^18"
|
||||
@@ -29,8 +28,6 @@
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"concurrently": "^7",
|
||||
"cpx": "^1.5.0",
|
||||
"fake-smtp-server": "^0.8.0",
|
||||
"pg": "^8.7.3",
|
||||
"prisma": "^3",
|
||||
|
||||
@@ -18,6 +18,7 @@ import Freshbooks from "next-auth/providers/freshbooks"
|
||||
import GitHub from "next-auth/providers/github"
|
||||
import Gitlab from "next-auth/providers/gitlab"
|
||||
import Google from "next-auth/providers/google"
|
||||
import Hubspot from "next-auth/providers/hubspot"
|
||||
import IDS4 from "next-auth/providers/identity-server4"
|
||||
import Instagram from "next-auth/providers/instagram"
|
||||
import Keycloak from "next-auth/providers/keycloak"
|
||||
@@ -29,53 +30,44 @@ 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"
|
||||
import Vk from "next-auth/providers/vk"
|
||||
import Wikimedia from "next-auth/providers/wikimedia"
|
||||
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",
|
||||
@@ -102,6 +94,7 @@ export const authOptions: NextAuthOptions = {
|
||||
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
||||
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
||||
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
|
||||
Hubspot({ clientId: process.env.HUBSPOT_ID, clientSecret: process.env.HUBSPOT_SECRET }),
|
||||
IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
|
||||
Instagram({ clientId: process.env.INSTAGRAM_ID, clientSecret: process.env.INSTAGRAM_SECRET }),
|
||||
Keycloak({ clientId: process.env.KEYCLOAK_ID, clientSecret: process.env.KEYCLOAK_SECRET, issuer: process.env.KEYCLOAK_ISSUER }),
|
||||
@@ -113,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 }),
|
||||
@@ -120,6 +114,7 @@ export const authOptions: NextAuthOptions = {
|
||||
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
||||
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
||||
Zitadel({ issuer: process.env.ZITADEL_ISSUER, clientId: process.env.ZITADEL_CLIENT_ID, clientSecret: process.env.ZITADEL_CLIENT_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))
|
||||
const session = await unstable_getServerSession(authOptions)
|
||||
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,11 +19,20 @@
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"next-auth": ["../../packages/next-auth/src"],
|
||||
"next-auth/*": ["../../packages/next-auth/src/*"]
|
||||
}
|
||||
"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 />
|
||||
|
||||
@@ -2,12 +2,16 @@ import { SessionProvider } from "next-auth/react"
|
||||
import "./styles.css"
|
||||
|
||||
import type { AppProps } from "next/app"
|
||||
import type { Session } from "next-auth"
|
||||
|
||||
// Use of the <SessionProvider> is mandatory to allow components that call
|
||||
// `useSession()` anywhere in your application to access the `session` object.
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
export default function App({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}: AppProps<{ session: Session }>) {
|
||||
return (
|
||||
<SessionProvider session={pageProps.session} refetchInterval={0}>
|
||||
<SessionProvider session={session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
)
|
||||
|
||||
@@ -4,8 +4,7 @@ import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
|
||||
export default function ProtectedPage() {
|
||||
const { data: session, status } = useSession()
|
||||
const loading = status === "loading"
|
||||
const { data: session } = useSession()
|
||||
const [content, setContent] = useState()
|
||||
|
||||
// Fetch content from protected route
|
||||
@@ -19,9 +18,7 @@ export default function ProtectedPage() {
|
||||
}
|
||||
fetchData()
|
||||
}, [session])
|
||||
|
||||
// When rendering client side don't display anything until loading is complete
|
||||
if (typeof window !== "undefined" && loading) return null
|
||||
|
||||
|
||||
// If no session exists, display access denied message
|
||||
if (!session) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
VITE_GITHUB_CLIENT_ID=
|
||||
VITE_GITHUB_CLIENT_SECRET=
|
||||
VITE_NEXTAUTH_URL=
|
||||
VITE_NEXTAUTH_SECRET=
|
||||
GITHUB_CLIENT_ID=
|
||||
GITHUB_CLIENT_SECRET=
|
||||
NEXTAUTH_SECRET=
|
||||
PUBLIC_NEXTAUTH_URL=http://localhost:5173
|
||||
@@ -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,84 +4,71 @@ 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
|
||||
### Add API Route
|
||||
|
||||
To add NextAuth.js to a project create a file called `[...nextauth].js` in routes/api/auth. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
|
||||
To add NextAuth.js to a project create a file called `[...nextauth]/+server.js` in routes/api/auth. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
|
||||
|
||||
```ts
|
||||
import NextAuth from "$lib"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
import { NextAuth, options } from "$lib/next-auth"
|
||||
|
||||
const nextAuthOptions = {
|
||||
// Configure one or more authentication providers
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: import.meta.env.VITE_GITHUB_CLIENT_ID,
|
||||
clientSecret: import.meta.env.VITE_GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
// ...add more providers here
|
||||
],
|
||||
}
|
||||
|
||||
export const { get, post } = NextAuth(nextAuthOptions)
|
||||
export const { GET, POST } = NextAuth(options)
|
||||
```
|
||||
|
||||
### Add [hook](https://kit.svelte.dev/docs/hooks)
|
||||
|
||||
```ts
|
||||
import { getServerSession } from "$lib"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
import type { Handle } from "@sveltejs/kit"
|
||||
import { getServerSession, options as nextAuthOptions } from "$lib/next-auth"
|
||||
|
||||
const nextAuthOptions = {
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: import.meta.env.VITE_GITHUB_CLIENT_ID,
|
||||
clientSecret: import.meta.env.VITE_GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
export async function handle({ event, resolve }) {
|
||||
export const handle: Handle = async function handle({
|
||||
event,
|
||||
resolve,
|
||||
}): Promise<Response> {
|
||||
const session = await getServerSession(event.request, nextAuthOptions)
|
||||
event.locals.session = session
|
||||
|
||||
return resolve(event)
|
||||
}
|
||||
```
|
||||
|
||||
export function getSession(event) {
|
||||
return event.locals.session || {}
|
||||
### Load Session from Primary Layout
|
||||
|
||||
```ts
|
||||
// src/lib/routes/+layout.server.ts
|
||||
import type { LayoutServerLoad } from "./$types"
|
||||
|
||||
export const load: LayoutServerLoad = ({ locals }) => {
|
||||
return {
|
||||
session: locals.session,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Protecting a route
|
||||
### Protecting a Route
|
||||
|
||||
```html
|
||||
<script context="module">
|
||||
export async function load({ session }) {
|
||||
const { user } = session
|
||||
```ts
|
||||
// src/lib/routes/protected/+page.ts
|
||||
import { redirect } from "@sveltejs/kit"
|
||||
import type { PageLoad } from "./$types"
|
||||
|
||||
if (!user) {
|
||||
return {
|
||||
status: 302,
|
||||
redirect: "/",
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
},
|
||||
}
|
||||
export const load: PageLoad = async ({ parent }) => {
|
||||
const { session } = await parent()
|
||||
if (!session?.user) {
|
||||
throw redirect(302, "/")
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export let session
|
||||
</script>
|
||||
|
||||
<p>Session expiry: {session.expires}</p>
|
||||
return {}
|
||||
}
|
||||
```
|
||||
|
||||
## Packaging lib
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
{
|
||||
"name": "sveltekit-nextauth",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "svelte-kit dev",
|
||||
"build": "svelte-kit build",
|
||||
"preview": "svelte-kit preview",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
|
||||
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
|
||||
"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": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.1",
|
||||
"@typescript-eslint/parser": "^5.10.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-svelte3": "^3.2.1",
|
||||
"prettier": "^2.5.1",
|
||||
"prettier-plugin-svelte": "^2.5.0",
|
||||
"@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",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier-plugin-svelte": "^2.7.0",
|
||||
"svelte": "^3.49.0",
|
||||
"svelte-check": "^2.2.6",
|
||||
"svelte-preprocess": "^4.10.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "~4.5.4"
|
||||
"svelte-check": "^2.8.1",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "~4.8.2",
|
||||
"vite": "^3.1.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"cookie": "0.4.1",
|
||||
"next-auth": "workspace:*"
|
||||
"cookie": "0.5.0",
|
||||
"next-auth": "latest"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
|
||||
27
apps/playground-sveltekit/src/app.d.ts
vendored
27
apps/playground-sveltekit/src/app.d.ts
vendored
@@ -1,13 +1,30 @@
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
import type {
|
||||
User as NextAuthUser,
|
||||
Session as NextAuthSession,
|
||||
} from "next-auth"
|
||||
|
||||
// optionally extend the `user`
|
||||
interface User extends NextAuthUser {
|
||||
// add custom fields here
|
||||
}
|
||||
|
||||
interface AppSession extends NextAuthSession {
|
||||
user: User
|
||||
}
|
||||
|
||||
// See https://kit.svelte.dev/docs/typescript
|
||||
// for information about these interfaces
|
||||
declare namespace App {
|
||||
interface Locals {}
|
||||
declare global {
|
||||
declare namespace App {
|
||||
interface Locals {
|
||||
session: AppSession
|
||||
}
|
||||
|
||||
interface Platform {}
|
||||
interface Platform {}
|
||||
|
||||
interface Session {}
|
||||
interface Session extends AppSession {}
|
||||
|
||||
interface Stuff {}
|
||||
interface Stuff {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="" />
|
||||
<link rel="icon" href="%svelte.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%svelte.head%
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%svelte.body%</div>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
8
apps/playground-sveltekit/src/global.d.ts
vendored
8
apps/playground-sveltekit/src/global.d.ts
vendored
@@ -1,8 +0,0 @@
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
VITE_GITHUB_CLIENT_ID: string
|
||||
VITE_GITHUB_CLIENT_SECRET: string
|
||||
VITE_NEXTAUTH_URL: string
|
||||
VITE_NEXTAUTH_SECRET: string
|
||||
}
|
||||
14
apps/playground-sveltekit/src/hooks.server.ts
Normal file
14
apps/playground-sveltekit/src/hooks.server.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { Handle } from "@sveltejs/kit"
|
||||
import { getServerSession, options as nextAuthOptions } from "$lib/next-auth"
|
||||
|
||||
export const handle: Handle = async function handle({
|
||||
event,
|
||||
resolve,
|
||||
}): Promise<Response> {
|
||||
const session = await getServerSession(event.request, nextAuthOptions)
|
||||
if (session) {
|
||||
event.locals.session = session
|
||||
}
|
||||
|
||||
return resolve(event)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { getServerSession } from "$lib"
|
||||
import type { Session } from "next-auth"
|
||||
import type { NextAuthOptions } from "next-auth"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
|
||||
const nextAuthOptions: NextAuthOptions = {
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: import.meta.env.VITE_GITHUB_CLIENT_ID,
|
||||
clientSecret: import.meta.env.VITE_GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
export async function handle({ event, resolve }): Promise<Response> {
|
||||
const session = await getServerSession(event.request, nextAuthOptions)
|
||||
event.locals.session = session
|
||||
|
||||
return resolve(event)
|
||||
}
|
||||
|
||||
export function getSession(event): Session {
|
||||
return event.locals.session || {}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import NextAuth, { getServerSession } from "./next-auth"
|
||||
|
||||
export default NextAuth
|
||||
export { getServerSession }
|
||||
@@ -1,74 +1,103 @@
|
||||
import type { RequestEvent } from "@sveltejs/kit"
|
||||
import type { IncomingRequest, NextAuthOptions, Session } from "next-auth"
|
||||
import type { NextAuthAction } from "next-auth/lib/types"
|
||||
import type { OutgoingResponse } from "next-auth/core"
|
||||
import type { ServerLoadEvent } from "@sveltejs/kit"
|
||||
import type { RequestInternal } from "next-auth"
|
||||
import type { NextAuthAction, NextAuthOptions } from "next-auth/core/types"
|
||||
import type { OutgoingResponse as NextAuthResponse } from "next-auth/core"
|
||||
import { NextAuthHandler } from "next-auth/core"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
import cookie from "cookie"
|
||||
import getFormBody from "./utils/get-form-body"
|
||||
import {
|
||||
GITHUB_CLIENT_ID,
|
||||
GITHUB_CLIENT_SECRET,
|
||||
NEXTAUTH_SECRET,
|
||||
} from "$env/static/private"
|
||||
import { PUBLIC_NEXTAUTH_URL } from "$env/static/public"
|
||||
|
||||
async function toSvelteKitResponse(
|
||||
// @ts-expect-error import is exported on .default during SSR
|
||||
const github = GithubProvider?.default || GithubProvider
|
||||
|
||||
export const options: NextAuthOptions = {
|
||||
providers: [
|
||||
github({
|
||||
clientId: GITHUB_CLIENT_ID,
|
||||
clientSecret: GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
const toSvelteKitResponse = async <
|
||||
T extends string | any[] | Record<string, any>
|
||||
>(
|
||||
request: Request,
|
||||
nextAuthResponse: OutgoingResponse<unknown>
|
||||
) {
|
||||
const { headers, cookies, body, redirect, status = 200 } = nextAuthResponse
|
||||
nextAuthResponse: NextAuthResponse<T>
|
||||
): Promise<Response> => {
|
||||
const { cookies, redirect } = nextAuthResponse
|
||||
|
||||
const response = {
|
||||
status,
|
||||
headers: {},
|
||||
const headers = new Headers()
|
||||
for (const header of nextAuthResponse?.headers || []) {
|
||||
// pass headers along from next-auth
|
||||
headers.set(header.key, header.value)
|
||||
}
|
||||
|
||||
headers?.forEach((header) => {
|
||||
response.headers[header.key] = header.value
|
||||
})
|
||||
// set-cookie header
|
||||
if (cookies?.length) {
|
||||
headers.set(
|
||||
"set-cookie",
|
||||
cookies
|
||||
?.map((item) => cookie.serialize(item.name, item.value, item.options))
|
||||
.join(",") as string
|
||||
)
|
||||
}
|
||||
|
||||
response.headers["set-cookie"] = cookies?.map((item) => {
|
||||
return cookie.serialize(item.name, item.value, item.options)
|
||||
})
|
||||
let body = undefined
|
||||
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") {
|
||||
response.status = 302
|
||||
response.headers["Location"] = redirect
|
||||
const { json } = Object.fromEntries(formData ?? [])
|
||||
if (json !== "true") {
|
||||
status = 302
|
||||
headers.set("Location", redirect)
|
||||
} else {
|
||||
response["body"] = { url: redirect }
|
||||
body = { url: redirect }
|
||||
}
|
||||
} else {
|
||||
response["body"] = body
|
||||
body = nextAuthResponse.body
|
||||
}
|
||||
|
||||
return response
|
||||
// @ts-expect-error - body is a known HTML document or JSON object
|
||||
return new Response(body, {
|
||||
status,
|
||||
headers,
|
||||
})
|
||||
}
|
||||
|
||||
async function SKNextAuthHandler(
|
||||
{ request, url, params }: RequestEvent,
|
||||
const SKNextAuthHandler = async (
|
||||
{ request, url, params }: ServerLoadEvent,
|
||||
options: NextAuthOptions
|
||||
) {
|
||||
const nextauth = params.nextauth.split("/")
|
||||
let body = null
|
||||
): Promise<Response> => {
|
||||
const [action, provider] = params.nextauth!.split("/")
|
||||
let body: FormData | undefined
|
||||
try {
|
||||
body = await request.formData()
|
||||
body = getFormBody(body)
|
||||
} catch {
|
||||
// no formData passed
|
||||
}
|
||||
options.secret = import.meta.env.VITE_NEXTAUTH_SECRET
|
||||
const req: IncomingRequest = {
|
||||
host: import.meta.env.VITE_NEXTAUTH_URL,
|
||||
body,
|
||||
options.secret = NEXTAUTH_SECRET
|
||||
const req: RequestInternal = {
|
||||
host: PUBLIC_NEXTAUTH_URL,
|
||||
body: Object.fromEntries(body ?? []),
|
||||
query: Object.fromEntries(url.searchParams),
|
||||
headers: request.headers,
|
||||
method: request.method,
|
||||
cookies: cookie.parse(request.headers.get("cookie") ?? ""),
|
||||
action: nextauth[0] as NextAuthAction,
|
||||
providerId: nextauth[1],
|
||||
error: nextauth[1],
|
||||
cookies: cookie.parse(request.headers.get("cookie") || ""),
|
||||
action: action as NextAuthAction,
|
||||
providerId: provider,
|
||||
error: provider,
|
||||
}
|
||||
|
||||
const response = await NextAuthHandler({
|
||||
@@ -79,19 +108,18 @@ async function SKNextAuthHandler(
|
||||
return toSvelteKitResponse(request, response)
|
||||
}
|
||||
|
||||
export async function getServerSession(
|
||||
export const getServerSession = async (
|
||||
request: Request,
|
||||
options: NextAuthOptions
|
||||
): Promise<Session | null> {
|
||||
|
||||
options.secret = import.meta.env.VITE_NEXTAUTH_SECRET
|
||||
|
||||
const session = await NextAuthHandler<Session>({
|
||||
): Promise<App.Session | null> => {
|
||||
options.secret = NEXTAUTH_SECRET
|
||||
|
||||
const session = await NextAuthHandler<App.Session>({
|
||||
req: {
|
||||
host: import.meta.env.VITE_NEXTAUTH_URL,
|
||||
host: PUBLIC_NEXTAUTH_URL,
|
||||
action: "session",
|
||||
method: "GET",
|
||||
cookies: cookie.parse(request.headers.get("cookie") ?? ""),
|
||||
cookies: cookie.parse(request.headers.get("cookie") || ""),
|
||||
headers: request.headers,
|
||||
},
|
||||
options,
|
||||
@@ -99,16 +127,18 @@ export async function getServerSession(
|
||||
|
||||
const { body } = session
|
||||
|
||||
if (body && Object.keys(body).length) return body as Session
|
||||
if (body && Object.keys(body).length) {
|
||||
return body as App.Session
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export default (
|
||||
export const NextAuth = (
|
||||
options: NextAuthOptions
|
||||
): {
|
||||
get: (req: RequestEvent) => Promise<unknown>
|
||||
post: (req: RequestEvent) => Promise<unknown>
|
||||
GET: (event: ServerLoadEvent) => Promise<unknown>
|
||||
POST: (event: ServerLoadEvent) => Promise<unknown>
|
||||
} => ({
|
||||
get: (req) => SKNextAuthHandler(req, options),
|
||||
post: (req) => SKNextAuthHandler(req, options),
|
||||
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
|
||||
}, {})
|
||||
}
|
||||
7
apps/playground-sveltekit/src/routes/+layout.server.ts
Normal file
7
apps/playground-sveltekit/src/routes/+layout.server.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { LayoutServerLoad } from "./$types"
|
||||
|
||||
export const load: LayoutServerLoad = ({ locals }) => {
|
||||
return {
|
||||
session: locals.session,
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { session } from "$app/stores"
|
||||
import { page } from "$app/stores"
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<header>
|
||||
<div class="signedInStatus">
|
||||
<p class="nojs-show loaded">
|
||||
{#if Object.keys($session).length}
|
||||
{#if $session.user.image}
|
||||
{#if Object.keys($page.data.session || {}).length}
|
||||
{#if $page.data.session.user.image}
|
||||
<span
|
||||
style="background-image: url('{$session.user.image}')"
|
||||
style="background-image: url('{$page.data.session.user.image}')"
|
||||
class="avatar"
|
||||
/>
|
||||
{/if}
|
||||
<span class="signedInText">
|
||||
<small>Signed in as</small><br />
|
||||
<strong>{$session.user.email || $session.user.name}</strong>
|
||||
<strong
|
||||
>{$page.data.session.user.email ||
|
||||
$page.data.session.user.name}</strong
|
||||
>
|
||||
</span>
|
||||
<a href="/api/auth/signout" class="button">Sign out</a>
|
||||
{:else}
|
||||
@@ -38,7 +41,8 @@
|
||||
:global(body) {
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
|
||||
"Noto Color Emoji";
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
max-width: 680px;
|
||||
margin: 0 auto;
|
||||
@@ -1,11 +0,0 @@
|
||||
import NextAuth from "$lib"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
|
||||
export const { get, post } = NextAuth({
|
||||
providers: [
|
||||
GithubProvider({
|
||||
clientId: import.meta.env.VITE_GITHUB_CLIENT_ID,
|
||||
clientSecret: import.meta.env.VITE_GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
import { NextAuth, options } from "$lib/next-auth"
|
||||
|
||||
export const { GET, POST } = NextAuth(options)
|
||||
@@ -1,27 +0,0 @@
|
||||
<script context="module" lang="ts">
|
||||
export async function load({ session }) {
|
||||
const { user } = session
|
||||
if (!user) {
|
||||
return {
|
||||
status: 302,
|
||||
redirect: "/",
|
||||
}
|
||||
}
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export let session
|
||||
</script>
|
||||
|
||||
<h1>Protected page</h1>
|
||||
<p>
|
||||
This is a protected content. You can access this content because you are
|
||||
signed in.
|
||||
</p>
|
||||
<p>Session expiry: {session.expires}</p>
|
||||
10
apps/playground-sveltekit/src/routes/protected/+page.svelte
Normal file
10
apps/playground-sveltekit/src/routes/protected/+page.svelte
Normal file
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { page } from "$app/stores"
|
||||
</script>
|
||||
|
||||
<h1>Protected page</h1>
|
||||
<p>
|
||||
This is a protected content. You can access this content because you are
|
||||
signed in.
|
||||
</p>
|
||||
<p>Session expiry: {$page.data.session.expires}</p>
|
||||
10
apps/playground-sveltekit/src/routes/protected/+page.ts
Normal file
10
apps/playground-sveltekit/src/routes/protected/+page.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { redirect } from "@sveltejs/kit"
|
||||
import type { PageLoad } from "./$types"
|
||||
|
||||
export const load: PageLoad = async ({ parent }) => {
|
||||
const { session } = await parent()
|
||||
if (!session?.user) {
|
||||
throw redirect(302, "/")
|
||||
}
|
||||
return {}
|
||||
}
|
||||
@@ -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,7 +6,6 @@ const config = {
|
||||
// Consult https://github.com/sveltejs/svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: preprocess(),
|
||||
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
},
|
||||
|
||||
@@ -1,36 +1,17 @@
|
||||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"module": "es2020",
|
||||
"lib": ["es2020", "DOM"],
|
||||
"target": "es2020",
|
||||
/**
|
||||
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
|
||||
to enforce using \`import type\` instead of \`import\` for Types.
|
||||
*/
|
||||
"importsNotUsedAsValues": "error",
|
||||
/**
|
||||
TypeScript doesn't know about import usages in the template because it only sees the
|
||||
script of a Svelte file. Therefore preserve all value imports. Requires TS 4.5 or higher.
|
||||
*/
|
||||
"preserveValueImports": true,
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
/**
|
||||
To have warnings/errors of the Svelte compiler at the correct position,
|
||||
enable source maps by default.
|
||||
*/
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"paths": {
|
||||
"$lib": ["src/lib"],
|
||||
"$lib/*": ["src/lib/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.ts", "src/**/*.svelte"]
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true
|
||||
}
|
||||
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||
//
|
||||
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||
}
|
||||
|
||||
8
apps/playground-sveltekit/vite.config.ts
Normal file
8
apps/playground-sveltekit/vite.config.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { sveltekit } from "@sveltejs/kit/vite"
|
||||
import type { UserConfig } from "vite"
|
||||
|
||||
const config: UserConfig = {
|
||||
plugins: [sveltekit()],
|
||||
}
|
||||
|
||||
export default config
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ This is the Dgraph Adapter for [`next-auth`](https://next-auth.js.org).
|
||||
npm install next-auth @next-auth/dgraph-adapter
|
||||
```
|
||||
|
||||
2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
|
||||
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
@@ -17,7 +17,7 @@ You can find the Fauna schema and seed information in the docs at [next-auth.js.
|
||||
npm install next-auth @next-auth/fauna-adapter faunadb
|
||||
```
|
||||
|
||||
2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
|
||||
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
@@ -25,7 +25,7 @@ import { FirestoreAdapter } from "@next-auth/firebase-adapter"
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
export default NextAuth({
|
||||
// https://next-auth.js.org/providers/overview
|
||||
// https://next-auth.js.org/providers
|
||||
providers: [
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_ID,
|
||||
|
||||
@@ -53,12 +53,12 @@ if (process.env.NODE_ENV === "development") {
|
||||
export default clientPromise
|
||||
```
|
||||
|
||||
3. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
|
||||
3. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||
|
||||
```js
|
||||
import NextAuth from "next-auth"
|
||||
import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
|
||||
import clientPromise from "lib/mongodb"
|
||||
import clientPromise from "../../../lib/mongodb"
|
||||
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
|
||||
@@ -15,7 +15,7 @@ This is the Neo4j Adapter for [`next-auth`](https://next-auth.js.org). This pack
|
||||
npm install next-auth @next-auth/neo4j-adapter neo4j-driver
|
||||
```
|
||||
|
||||
2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
|
||||
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
import neo4j from "neo4j-driver"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -12,15 +12,28 @@ npm install next-auth @prisma/client @next-auth/prisma-adapter
|
||||
npm install prisma --save-dev
|
||||
```
|
||||
|
||||
Create a file with your Prisma Client:
|
||||
|
||||
```typescript title="lib/prismadb.ts"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
declare global {
|
||||
var prisma: PrismaClient | undefined
|
||||
}
|
||||
|
||||
const client = globalThis.prisma || new PrismaClient()
|
||||
if (process.env.NODE_ENV !== "production") globalThis.prisma = client
|
||||
|
||||
export default client
|
||||
```
|
||||
|
||||
Configure your NextAuth.js to use the Prisma Adapter:
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
import prisma from "../../../lib/prismadb"
|
||||
|
||||
export default NextAuth({
|
||||
adapter: PrismaAdapter(prisma),
|
||||
@@ -107,6 +120,8 @@ When using the MySQL connector for Prisma, the [Prisma `String` type](https://ww
|
||||
|
||||
### Create the database schema with Prisma Migrate
|
||||
|
||||
**Warning:** Make sure to back up your database before running using Prisma Migrate.
|
||||
|
||||
```
|
||||
npx prisma migrate dev
|
||||
```
|
||||
|
||||
@@ -19,7 +19,7 @@ npm install next-auth @next-auth/sequelize-adapter sequelize
|
||||
You'll also have to manually install [the driver for your database](https://sequelize.org/master/manual/getting-started.html) of choice.
|
||||
:::
|
||||
|
||||
2. Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object.
|
||||
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
|
||||
@@ -17,12 +17,12 @@ Configure your NextAuth.js to use the Upstash Redis Adapter:
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import { UpstashRedisAdapter } from "@next-auth/upstash-redis-adapter"
|
||||
import upstashRedisClient from "@upstash/redis"
|
||||
import { Redis } from "@upstash/redis"
|
||||
|
||||
const redis = upstashRedisClient(
|
||||
process.env.UPSTASH_REDIS_URL,
|
||||
process.env.UPSTASH_REDIS_TOKEN
|
||||
)
|
||||
const redis = new Redis({
|
||||
url: process.env.UPSTASH_REDIS_URL,
|
||||
token: process.env.UPSTASH_REDIS_TOKEN
|
||||
})
|
||||
|
||||
export default NextAuth({
|
||||
adapter: UpstashRedisAdapter(redis),
|
||||
|
||||
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.
|
||||
@@ -112,15 +112,16 @@ Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`,
|
||||
- As with database persisted session expiry times, token expiry time is extended whenever a session is active.
|
||||
- The arguments _user_, _account_, _profile_ and _isNewUser_ are only passed the first time this callback is called on a new session, after the user signs in. In subsequent calls, only `token` will be available.
|
||||
|
||||
The contents _user_, _account_, _profile_ and _isNewUser_ will vary depending on the provider and on if you are using a database or not. You can persist data such as User ID, OAuth Access Token in this token. To make it available in the browser, check out the [`session()` callback](#session-callback) as well.
|
||||
The contents _user_, _account_, _profile_ and _isNewUser_ will vary depending on the provider and if you are using a database. You can persist data such as User ID, OAuth Access Token in this token, see the example below for `access_token` and `user.id`. To expose it on the client side, check out the [`session()` callback](#session-callback) as well.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
...
|
||||
callbacks: {
|
||||
async jwt({ token, account }) {
|
||||
// Persist the OAuth access_token to the token right after signin
|
||||
async jwt({ token, account, profile }) {
|
||||
// Persist the OAuth access_token and or the user id to the token right after signin
|
||||
if (account) {
|
||||
token.accessToken = account.access_token
|
||||
token.id = profile.id
|
||||
}
|
||||
return token
|
||||
}
|
||||
@@ -134,7 +135,7 @@ Use an if branch to check for the existence of parameters (apart from `token`).
|
||||
|
||||
## Session callback
|
||||
|
||||
The session callback is called whenever a session is checked. By default, only a subset of the token is returned for increased security. If you want to make something available you added to the token through the `jwt()` callback, you have to explicitly forward it here to make it available to the client.
|
||||
The session callback is called whenever a session is checked. By default, **only a subset of the token is returned for increased security**. If you want to make something available you added to the token (like `access_token` and `user.id` from above) via the `jwt()` callback, you have to explicitly forward it here to make it available to the client.
|
||||
|
||||
e.g. `getSession()`, `useSession()`, `/api/auth/session`
|
||||
|
||||
@@ -145,8 +146,10 @@ e.g. `getSession()`, `useSession()`, `/api/auth/session`
|
||||
...
|
||||
callbacks: {
|
||||
async session({ session, token, user }) {
|
||||
// Send properties to the client, like an access_token from a provider.
|
||||
// Send properties to the client, like an access_token and user id from a provider.
|
||||
session.accessToken = token.accessToken
|
||||
session.user.id = token.id
|
||||
|
||||
return session
|
||||
}
|
||||
}
|
||||
@@ -155,7 +158,7 @@ callbacks: {
|
||||
|
||||
:::tip
|
||||
When using JSON Web Tokens the `jwt()` callback is invoked before the `session()` callback, so anything you add to the
|
||||
JSON Web Token will be immediately available in the session callback, like for example an `access_token` from a provider.
|
||||
JSON Web Token will be immediately available in the session callback, like for example an `access_token` or `id` from a provider.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
|
||||
@@ -12,11 +12,11 @@ Otherwise, if you only want to get the session token, see [`getToken`](/tutorial
|
||||
|
||||
`unstable_getServerSession` requires passing the same object you would pass to `NextAuth` when initializing NextAuth.js. To do so, you can export your NextAuth.js options in the following way:
|
||||
|
||||
In `[...nextauth.js]`:
|
||||
In `[...nextauth].ts`:
|
||||
```ts
|
||||
import { NextAuth } from 'next-auth'
|
||||
import type { NextAuthOptions } from 'next-auth'
|
||||
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// your configs
|
||||
}
|
||||
@@ -24,9 +24,9 @@ export const authOptions: NextAuthOptions = {
|
||||
export default NextAuth(authOptions);
|
||||
```
|
||||
|
||||
In `getServerSideProps`:
|
||||
### In `getServerSideProps`:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/[...nextauth]'
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
@@ -48,9 +48,10 @@ export async function getServerSideProps(context) {
|
||||
}
|
||||
}
|
||||
```
|
||||
In API routes:
|
||||
|
||||
### In API Routes:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/[...nextauth]'
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
|
||||
@@ -68,6 +69,24 @@ 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"
|
||||
import { authOptions } from "pages/api/auth/[...nextauth]"
|
||||
|
||||
export default async function Page() {
|
||||
const session = await unstable_getServerSession(authOptions)
|
||||
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.
|
||||
@@ -145,8 +164,8 @@ This should match the `pages` configuration that's found in `[...nextauth].ts`.
|
||||
|
||||
```js
|
||||
pages: {
|
||||
signIn: '/auth/signin',
|
||||
error: '/auth/error',
|
||||
signIn: '/api/auth/signin',
|
||||
error: '/api/auth/error',
|
||||
}
|
||||
```
|
||||
|
||||
@@ -160,7 +179,7 @@ See the documentation for the [pages option](/configuration/pages) for more info
|
||||
|
||||
#### Description
|
||||
|
||||
The same `secret` used in the [NextAuth config](/configuration/options#options).
|
||||
The same `secret` used in the [NextAuth.js config](/configuration/options#options).
|
||||
|
||||
#### Example (default value)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -68,7 +68,7 @@ A random string is used to hash tokens, sign/encrypt cookies and generate crypto
|
||||
|
||||
If you set [`NEXTAUTH_SECRET`](#nextauth_secret) as an environment variable, you don't have to define this option.
|
||||
|
||||
If no value specified specified in development (and there is no `NEXTAUTH_SECRET` variable either), it uses a hash for all configuration options, including OAuth Client ID / Secrets for entropy.
|
||||
If no value is specified in development (and there is no `NEXTAUTH_SECRET` variable either), it uses a hash for all configuration options, including OAuth Client ID / Secrets for entropy.
|
||||
|
||||
:::warning
|
||||
Not providing any `secret` or `NEXTAUTH_SECRET` will throw [an error](/errors#no_secret) in production.
|
||||
@@ -114,6 +114,12 @@ session: {
|
||||
// Use it to limit write operations. Set to 0 to always update the database.
|
||||
// Note: This option is ignored if using JSON Web Tokens
|
||||
updateAge: 24 * 60 * 60, // 24 hours
|
||||
|
||||
// The session token is usually either a random UUID or string, however if you
|
||||
// need a more customized session token string, you can define your own generate function.
|
||||
generateSessionToken: () => {
|
||||
return randomUUID?.() ?? randomBytes(32).toString("hex")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -326,7 +332,7 @@ Set debug to `true` to enable debug messages for authentication and database ope
|
||||
|
||||
#### Description
|
||||
|
||||
Override any of the logger levels (`undefined` levels will use the built-in logger), and intercept logs in NextAuth. You can use this to send NextAuth logs to a third-party logging service.
|
||||
Override any of the logger levels (`undefined` levels will use the built-in logger), and intercept logs in NextAuth.js. You can use this to send NextAuth.js logs to a third-party logging service.
|
||||
|
||||
The `code` parameter for `error` and `warn` are explained in the [Warnings](/warnings) and [Errors](/errors) pages respectively.
|
||||
|
||||
@@ -478,6 +484,15 @@ cookies: {
|
||||
secure: useSecureCookies,
|
||||
},
|
||||
},
|
||||
nonce: {
|
||||
name: `${cookiePrefix}next-auth.nonce`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
secure: useSecureCookies,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -80,10 +80,10 @@ TWITTER_ID=YOUR_TWITTER_CLIENT_ID
|
||||
TWITTER_SECRET=YOUR_TWITTER_CLIENT_SECRET
|
||||
```
|
||||
|
||||
4. Now you can add the provider settings to the NextAuth options object. You can add as many OAuth providers as you like, as you can see `providers` is an array.
|
||||
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({
|
||||
@@ -156,7 +156,7 @@ interface OAuthConfig {
|
||||
*/
|
||||
id: string
|
||||
version: string
|
||||
profile(profile: P, tokens: TokenSet): Awaitable<User & { id: string }>
|
||||
profile(profile: P, tokens: TokenSet): Awaitable<User>
|
||||
checks?: ChecksType | ChecksType[]
|
||||
clientId: string
|
||||
clientSecret: string
|
||||
@@ -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!
|
||||
|
||||
@@ -76,7 +76,11 @@ Please check your OAuth provider and make sure your URLs and other options are
|
||||
|
||||
If you are using an OAuth v1 provider, check your OAuth v1 provider settings, especially the OAuth token and OAuth token secret.
|
||||
|
||||
#### CALLBACK_OAUTH_ERROR
|
||||
3. `openid-client` version mismatch
|
||||
|
||||
If you are seeing `expected 200 OK with body but no body was returned`, it might have happened due to `openid-client` (which is peer dependency) node version mismatch. For instance, `openid-client` requires `>=14.2.0` for `lts/fermium` and has similar limits for the other versions. For the full list of the compatible node versions please see [package.json](https://github.com/panva/node-openid-client/blob/2a84e46992e1ebeaf685c3f87b65663d126e81aa/package.json#L78).
|
||||
|
||||
#### OAUTH_CALLBACK_ERROR
|
||||
|
||||
This can occur during the handling of the callback if the `code_verifier` cookie was not found or an invalid state was returned from the OAuth provider.
|
||||
|
||||
@@ -132,7 +136,7 @@ The `callbackUrl` provided was either invalid or not defined. See [specifying a
|
||||
|
||||
#### JWT_SESSION_ERROR
|
||||
|
||||
JWKKeySupport: the key does not support HS512 verify algorithm
|
||||
JWTKeySupport: the key does not support HS512 verify algorithm
|
||||
|
||||
The algorithm used for generating your key isn't listed as supported. You can generate a HS512 key using
|
||||
|
||||
@@ -179,8 +183,3 @@ Useful links:
|
||||
- https://next-auth.js.org/configuration/pages
|
||||
- https://nextjs.org/docs/advanced-features/middleware#matcher
|
||||
|
||||
### Other
|
||||
|
||||
#### oauth_callback_error expected 200 OK with body but no body was returned
|
||||
|
||||
This error might happen with some of the providers. It happens due to `openid-client`(which is peer dependency) node version mismatch. For instance, `openid-client` requires `>=14.2.0` for `lts/fermium` and has similar limits for the other versions. For the full list of the compatible node versions please see [package.json](https://github.com/panva/node-openid-client/blob/2a84e46992e1ebeaf685c3f87b65663d126e81aa/package.json#L78)
|
||||
|
||||
@@ -83,7 +83,7 @@ NextAuth.js was originally designed for use with Next.js and Serverless. However
|
||||
**Same root domain, different subdomains**: If you use NextAuth.js on a website with a different subdomain than 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)).
|
||||
|
||||
:::warning
|
||||
Changing the default cookies domain policy is advanced and can lead to security issues if done correctly. Make sure you're aware of the security implication before proceeding.
|
||||
Changing the default cookies domain policy can lead to security issues if done incorrectly. Make sure you're aware of the implications before proceeding.
|
||||
:::
|
||||
|
||||
A working example can be found at <a href="https://github.com/vercel/examples/tree/main/solutions/subdomain-auth" target="_blank">this example repo</a>.
|
||||
@@ -236,6 +236,10 @@ Automatic account linking is not a planned feature of NextAuth.js, however there
|
||||
|
||||
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.
|
||||
|
||||
:::note
|
||||
If the user first signs in using Email and then tries to sign in again using an OAuth provider, NextAuth.js default behavior is to allow account linking even if the OAuth account's email address does not match the previous email address of the user.
|
||||
:::
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
|
||||
@@ -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"`
|
||||
@@ -67,7 +67,7 @@ export default function Component() {
|
||||
|
||||
Due to the way how Next.js handles `getServerSideProps` and `getInitialProps`, every protected page load has to make a server-side request to check if the session is valid and then generate the requested page (SSR). This increases server load, and if you are good with making the requests from the client, there is an alternative. You can use `useSession` in a way that makes sure you always have a valid session. If after the initial loading state there was no session found, you can define the appropriate action to respond.
|
||||
|
||||
The default behavior is to redirect the user to the sign-in page, from where - after a successful login - they will be sent back to the page they started on. You can also define an `onFail()` callback, if you would like to do something else:
|
||||
The default behavior is to redirect the user to the sign-in page, from where - after a successful login - they will be sent back to the page they started on. You can also define an `onUnauthenticated()` callback, if you would like to do something else:
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -11,6 +11,17 @@ The easiest way to get started is to clone the [example app](https://github.com/
|
||||
|
||||
## Existing Project
|
||||
|
||||
### Install NextAuth
|
||||
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth
|
||||
```
|
||||
|
||||
:::info
|
||||
If you are using TypeScript, NextAuth.js comes with its types definitions within the package. To learn more about TypeScript for `next-auth`, check out the [TypeScript documentation](/getting-started/typescript)
|
||||
:::
|
||||
|
||||
|
||||
### Add API route
|
||||
|
||||
To add NextAuth.js to a project create a file called `[...nextauth].js` in `pages/api/auth`. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
|
||||
@@ -19,7 +30,7 @@ To add NextAuth.js to a project create a file called `[...nextauth].js` in `page
|
||||
import NextAuth from "next-auth"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
|
||||
export default NextAuth({
|
||||
export const authOptions = {
|
||||
// Configure one or more authentication providers
|
||||
providers: [
|
||||
GithubProvider({
|
||||
@@ -28,7 +39,9 @@ export default NextAuth({
|
||||
}),
|
||||
// ...add more providers here
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
```
|
||||
|
||||
All requests to `/api/auth/*` (`signIn`, `callback`, `signOut`, etc.) will automatically be handled by NextAuth.js.
|
||||
@@ -97,7 +110,7 @@ To protect an API Route, you can use the [`unstable_getServerSession()`](/config
|
||||
|
||||
```javascript title="pages/api/restricted.js" showLineNumbers
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import { authOptions } from "./auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
@@ -109,7 +122,7 @@ export default async (req, res) => {
|
||||
})
|
||||
} else {
|
||||
res.send({
|
||||
error: "You must be sign in to view the protected content on this page.",
|
||||
error: "You must be signed in to view the protected content on this page.",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ Introduced in https://github.com/nextauthjs/next-auth/releases/tag/v4.0.0-next.8
|
||||
|
||||
**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).
|
||||
The Adapter API has been rewritten and significantly simplified in NextAuth.js 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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -24,7 +24,11 @@ providers: [
|
||||
AtlassianProvider({
|
||||
clientId: process.env.ATLASSIAN_CLIENT_ID,
|
||||
clientSecret: process.env.ATLASSIAN_CLIENT_SECRET,
|
||||
scope: "write:jira-work read:jira-work read:jira-user offline_access read:me"
|
||||
authorization: {
|
||||
params: {
|
||||
scope: "write:jira-work read:jira-work read:jira-user offline_access read:me"
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
...
|
||||
|
||||
@@ -44,17 +44,17 @@ 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: {
|
||||
username: { label: "Username", type: "text", placeholder: "jsmith" },
|
||||
password: { label: "Password", type: "password" }
|
||||
password: { label: "Password", type: "password" }
|
||||
},
|
||||
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.
|
||||
@@ -71,7 +72,7 @@ EMAIL_SERVER_PORT=587
|
||||
EMAIL_FROM=noreply@example.com
|
||||
```
|
||||
|
||||
Now you can add the provider settings to the NextAuth options object in the Email Provider.
|
||||
Now you can add the provider settings to the NextAuth.js options object in the Email Provider.
|
||||
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import EmailProvider from "next-auth/providers/email";
|
||||
@@ -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.
|
||||
:::
|
||||
:::
|
||||
|
||||
43
docs/docs/providers/hubspot.md
Normal file
43
docs/docs/providers/hubspot.md
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: hubspot
|
||||
title: HubSpot
|
||||
---
|
||||
|
||||
:::note
|
||||
HubSpot returns a limited amount of information on the token holder (see [docs](https://legacydocs.hubspot.com/docs/methods/oauth2/get-access-token-information)). One other issue is that the name and profile photo cannot be fetched through API as discussed [here](https://community.hubspot.com/t5/APIs-Integrations/Profile-photo-is-not-retrieved-with-User-API/m-p/325521).
|
||||
:::
|
||||
|
||||
## Documentation
|
||||
|
||||
https://developers.hubspot.com/docs/api/oauth-quickstart-guide
|
||||
|
||||
## Configuration
|
||||
|
||||
You need to have an APP in your Developer Account as described at https://developers.hubspot.com/docs/api/developer-tools-overview
|
||||
|
||||
## Options
|
||||
|
||||
The **HubSpot Provider** comes with a set of default options:
|
||||
|
||||
- [HubSpot Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/hubspot.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import HubspotProvider from "next-auth/providers/hubspot";
|
||||
...
|
||||
providers: [
|
||||
HubspotProvider({
|
||||
clientId: process.env.HUBSPOT_CLIENT_ID,
|
||||
clientSecret: process.env.HUBSPOT_CLIENT_SECRET
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
:::warning
|
||||
The **Redirect URL** under the **Auth** tab on the HubSpot App Settings page must match the callback url which would be http://localhost:3000/api/auth/callback/hubspot for local development. Only one callback URL per Client ID and Client Secret pair is allowed, so it might be easier to create a new app for local development then fiddle with the url changes.
|
||||
:::
|
||||
|
||||
@@ -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
|
||||
:::
|
||||
@@ -7,9 +7,16 @@ title: Reddit
|
||||
|
||||
https://www.reddit.com/dev/api/
|
||||
|
||||
## Configuration
|
||||
## App Configuration
|
||||
|
||||
https://www.reddit.com/prefs/apps/
|
||||
1. Visit https://www.reddit.com/prefs/apps/ and create a new web app
|
||||
2. Provide a name for your web app
|
||||
3. Provide a redirect uri ending with `/api/auth/callback/reddit`:
|
||||
|
||||

|
||||
|
||||
4. All other fields are optional
|
||||
5. Click the "create app" button
|
||||
|
||||
## Options
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ The **Strava Provider** comes with a set of default options:
|
||||
|
||||
- [Strava Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/strava.js)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
You can override any of the options to suit your own use case. Ensure the redirect_uri configuration fits your needs accordingly.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
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
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
87
docs/docs/providers/zitadel.md
Normal file
87
docs/docs/providers/zitadel.md
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
id: zitadel
|
||||
title: Zitadel
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
https://docs.zitadel.com/docs/apis/openidoauth/endpoints
|
||||
|
||||
## Configuration
|
||||
|
||||
https://docs.zitadel.com/docs/guides/integrate/oauth-recommended-flows
|
||||
|
||||
The Redirect URIs used when creating the credentials must include your full domain and end in the callback path. For example:
|
||||
|
||||
- For production: `https://{YOUR_DOMAIN}/api/auth/callback/zitadel`
|
||||
- For development: `http://localhost:3000/api/auth/callback/zitadel`
|
||||
|
||||
Make sure to enable **dev mode** in ZITADEL console to allow redirects for local development.
|
||||
|
||||
## Options
|
||||
|
||||
The **ZITADEL Provider** comes with a set of default options:
|
||||
|
||||
- [ZITADEL Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/zitadel.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import ZitadelProvider from "next-auth/providers/zitadel";
|
||||
...
|
||||
providers: [
|
||||
ZitadelProvider({
|
||||
issuer: process.env.ZITADEL_ISSUER,
|
||||
clientId: process.env.ZITADEL_CLIENT_ID,
|
||||
clientSecret: process.env.ZITADEL_CLIENT_SECRET,
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
If you need access to ZITADEL APIs or need additional information, make sure to add the corresponding scopes.
|
||||
|
||||
To get the full list of supported claims take a look [here](https://docs.zitadel.com/docs/apis/openidoauth/endpoints).
|
||||
|
||||
```js
|
||||
const options = {
|
||||
...
|
||||
providers: [
|
||||
ZitadelProvider({
|
||||
clientId: process.env.ZITADEL_CLIENT_ID,
|
||||
authorization: {
|
||||
params: {
|
||||
scope: `openid email profile urn:zitadel:iam:org:project:id:${process.env.ZITADEL_PROJECT_ID}:aud`
|
||||
}
|
||||
}
|
||||
})
|
||||
],
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
ZITADEL also returns a `email_verified` boolean property in the profile.
|
||||
|
||||
You can use this property to restrict access to people with verified accounts.
|
||||
|
||||
```js
|
||||
const options = {
|
||||
...
|
||||
callbacks: {
|
||||
async signIn({ account, profile }) {
|
||||
if (account.provider === "zitadel") {
|
||||
return profile.email_verified;
|
||||
}
|
||||
return true; // Do different verification for other providers that don't have `email_verified`
|
||||
},
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
@@ -16,7 +16,7 @@ If you contact us regarding a serious issue:
|
||||
- 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, yo@ndo.dev, thvu@hey.com and me@iaincollins.com, 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.)
|
||||
The best way to report an issue is by contacting us via email at hi@thvu.dev, info@balazsorban.com, yo@ndo.dev and me@iaincollins.com, 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 submit these these publically as bug reports or feature requests or to raise a question to open a discussion around them.
|
||||
|
||||
@@ -105,6 +105,11 @@ This tutorial covers:
|
||||
|
||||
## Database
|
||||
|
||||
#### [Create a NextAuth.js Custom Adapter with HarperDB & Next.js](https://spacejelly.dev/posts/how-to-create-a-nextauth-js-custom-adapter-with-harperdb-next-js/) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
|
||||
|
||||
- Use a custom database in a Custom Adapter for persisted NextAuth.js sessions using HarperDB as an example.
|
||||
- Video tutorial also available: <https://www.youtube.com/watch?v=pu7xBv7sZ8s>
|
||||
|
||||
#### [Using NextAuth.js with Prisma and PlanetScale serverless databases](https://github.com/planetscale/nextjs-planetscale-starter) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
|
||||
|
||||
- How to set up a PlanetScale database to fetch and store user / account data with the Prisma adapter.
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ Using a [JWT callback](https://next-auth.js.org/configuration/callbacks#jwt-call
|
||||
|
||||
Below is a sample implementation using Google's Identity Provider. Please note that the OAuth 2.0 request in the `refreshAccessToken()` function will vary between different providers, but the core logic should remain similar.
|
||||
|
||||
```js title="pages/auth/[...nextauth.js]"
|
||||
```js title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ callbacks: {
|
||||
async session({ session, token, user }) {
|
||||
session.user.role = user.role; // Add role value to user object so it is passed along with session
|
||||
return session;
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
@@ -42,18 +42,30 @@ export default function Page() {
|
||||
|
||||
### Next.js (Middleware)
|
||||
|
||||
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `_middleware.js` file in your root `pages` directory which looks like this.
|
||||
With NextAuth.js 4.2.0 and Next.js 12, you can now protect your pages via the middleware pattern more easily. If you would like to protect all pages, you can create a `middleware.js` file in your root `pages` directory which looks like this:
|
||||
|
||||
```js title="/middleware.js"
|
||||
export { default } from "next-auth/middleware"
|
||||
```
|
||||
|
||||
Otherwise, if you only want to protect a subset of pages, you could put it in a subdirectory as well, for example in `/pages/admin/_middleware.js` would protect all pages under `/admin`.
|
||||
If you only want to secure certain pages, export a `config` object with a `matcher`:
|
||||
|
||||
```js
|
||||
export { default } from "next-auth/middleware"
|
||||
|
||||
export const config = { matcher: ["/dashboard"] }
|
||||
```
|
||||
|
||||
For the time being, the `withAuth` middleware only supports `"jwt"` as [session strategy](https://next-auth.js.org/configuration/options#session).
|
||||
|
||||
More details can be found [here](https://next-auth.js.org/configuration/nextjs#middleware).
|
||||
|
||||
:::tip
|
||||
To inclue all `dashboard` nested routes (sub pages like `/dashboard/settings`, `/dashboard/profile`) you can pass `matcher: "/dashboard/:path*"` to `config`.
|
||||
|
||||
For other patterns check out the [Next.js Middleware documentation](https://nextjs.org/docs/advanced-features/middleware#matcher).
|
||||
:::
|
||||
|
||||
### Server Side
|
||||
|
||||
You can protect server side rendered pages using the `unstable_getServerSession` method. This is different from the old `getSession()` method, in that it does not do an extra fetch out over the internet to confirm data from itself, increasing performance significantly.
|
||||
@@ -122,7 +134,7 @@ You can protect API routes using the `unstable_getServerSession()` method.
|
||||
|
||||
```js title="pages/api/get-session-example.js"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import { authOptions } from "./auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
@@ -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}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user