mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
199 Commits
next-auth@
...
@next-auth
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
afb1fcdae3 | ||
|
|
a21db8950f | ||
|
|
e8371ab23a | ||
|
|
9cdeb2ce7d | ||
|
|
89829d8a88 | ||
|
|
aedabc8d3f | ||
|
|
9f2cdad457 | ||
|
|
b107ca4946 | ||
|
|
6590993fdc | ||
|
|
0ea96796b2 | ||
|
|
8ec940bd6a | ||
|
|
e3bcdf83f1 | ||
|
|
4084297334 | ||
|
|
c9827960b1 | ||
|
|
946a825865 | ||
|
|
c57d8c997e | ||
|
|
e2b92bf04f | ||
|
|
8bff050e4e | ||
|
|
1a79a1a612 | ||
|
|
b7065a602f | ||
|
|
61b92ec1b6 | ||
|
|
282f7ab340 | ||
|
|
4f56e414b0 | ||
|
|
2725d07eb7 | ||
|
|
5a8b029523 | ||
|
|
f62a985848 | ||
|
|
edd6fb5989 | ||
|
|
fb60554a62 | ||
|
|
9784dfb631 | ||
|
|
4ff836a8cf | ||
|
|
042955eaaa | ||
|
|
82e107c0e7 | ||
|
|
f7050347e8 | ||
|
|
c56abbd745 | ||
|
|
3f6d99e8df | ||
|
|
46eedee3c8 | ||
|
|
bb664a27da | ||
|
|
a14fbea0b5 | ||
|
|
4705632c6b | ||
|
|
2296471f02 | ||
|
|
8853000fd5 | ||
|
|
70ffa6592f | ||
|
|
3666e438a3 | ||
|
|
cdf467eba1 | ||
|
|
374dc30f9f | ||
|
|
d9534d807d | ||
|
|
f4c7401a5d | ||
|
|
2baa0c30c1 | ||
|
|
839b9108ea | ||
|
|
0bf955a63d | ||
|
|
83a974d455 | ||
|
|
8f54b8f729 | ||
|
|
1b91282402 | ||
|
|
c2a9ab3023 | ||
|
|
5bd00f6ff1 | ||
|
|
af3c2dd33d | ||
|
|
709edc5153 | ||
|
|
fa3ea37ebc | ||
|
|
6a364f0353 | ||
|
|
c22d613774 | ||
|
|
9efafcd36c | ||
|
|
e317b16cd2 | ||
|
|
2edc79ed2b | ||
|
|
637dda9966 | ||
|
|
10bb32c479 | ||
|
|
89e25568b1 | ||
|
|
88ad25a16b | ||
|
|
c1f7ce3436 | ||
|
|
c59a4e04d1 | ||
|
|
3c210d961b | ||
|
|
9457593038 | ||
|
|
5081d25f5c | ||
|
|
384edbab3b | ||
|
|
2adfadefdc | ||
|
|
32fa01f939 | ||
|
|
ae834f1e08 | ||
|
|
4d4c276627 | ||
|
|
f4c0d5ab5d | ||
|
|
01cd6b0f7b | ||
|
|
993c0f46b0 | ||
|
|
163d8c66e2 | ||
|
|
5319dca583 | ||
|
|
cd6ccfde89 | ||
|
|
89d91ea282 | ||
|
|
ca3165bd5a | ||
|
|
aa527b37bf | ||
|
|
f3233641d0 | ||
|
|
4bee970775 | ||
|
|
80a4f50be2 | ||
|
|
1f4ffbaefe | ||
|
|
a911b4a40b | ||
|
|
cb0f3e1ae2 | ||
|
|
c194261617 | ||
|
|
5fdd8483d8 | ||
|
|
99f5b9616f | ||
|
|
d8d9ab94cb | ||
|
|
e8827cbf45 | ||
|
|
37c4a813e3 | ||
|
|
6a23ff7126 | ||
|
|
23db0e68dd | ||
|
|
e03e234b86 | ||
|
|
66fb914a31 | ||
|
|
8ce728197f | ||
|
|
87d1a7af6d | ||
|
|
172813f987 | ||
|
|
cc934fceec | ||
|
|
46e467a7cb | ||
|
|
73d489beac | ||
|
|
e498483b23 | ||
|
|
7cf49566a6 | ||
|
|
2469e44572 | ||
|
|
408b6b175f | ||
|
|
92dfc3c8b0 | ||
|
|
8c5d9faad6 | ||
|
|
49a8d51f79 | ||
|
|
c0d251731d | ||
|
|
76560aed5a | ||
|
|
25517b7315 | ||
|
|
4daa63d5e1 | ||
|
|
81afeef194 | ||
|
|
008f29e6f8 | ||
|
|
e4ee520b4a | ||
|
|
358b80d4ce | ||
|
|
0a7a916228 | ||
|
|
612c35e8c2 | ||
|
|
9f6949816c | ||
|
|
46089eb5ae | ||
|
|
7d8cc70faf | ||
|
|
75602a3f04 | ||
|
|
5b8a619cd0 | ||
|
|
16622f6428 | ||
|
|
e203801f30 | ||
|
|
cfc0a55080 | ||
|
|
dda4e0a7d8 | ||
|
|
374f886e84 | ||
|
|
db188b872f | ||
|
|
2838dd7e0f | ||
|
|
08f6b31e41 | ||
|
|
602668f93c | ||
|
|
641d917175 | ||
|
|
70d59bb6e7 | ||
|
|
0c86d5a370 | ||
|
|
0ac8773c2b | ||
|
|
714579e8d6 | ||
|
|
8b6d2e3972 | ||
|
|
4f29d39521 | ||
|
|
042ed82ca0 | ||
|
|
a6901db11b | ||
|
|
0b953bd047 | ||
|
|
268c0636d7 |
27
.eslintrc.js
Normal file
27
.eslintrc.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const path = require("path")
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
project: [path.resolve(__dirname, "./packages/**/tsconfig.eslint.json")],
|
||||
},
|
||||
extends: ["standard-with-typescript", "prettier"],
|
||||
globals: {
|
||||
localStorage: "readonly",
|
||||
location: "readonly",
|
||||
fetch: "readonly",
|
||||
},
|
||||
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",
|
||||
},
|
||||
plugins: ["jest"],
|
||||
env: {
|
||||
"jest/globals": true,
|
||||
},
|
||||
ignorePatterns: [".eslintrc.js"],
|
||||
}
|
||||
15
.github/CODEOWNERS
vendored
15
.github/CODEOWNERS
vendored
@@ -1,4 +1,11 @@
|
||||
/types/ @balazsorban44 @lluia
|
||||
/docs/ @balazsorban44 @ndom91
|
||||
/adapters/ @balazsorban44 @ndom91
|
||||
/__tests__/ @lluia
|
||||
# Learn how to add code owners here:
|
||||
# https://help.github.com/en/articles/about-code-owners
|
||||
|
||||
* @balazsorban44
|
||||
.github @ThangHuuVu
|
||||
/apps/ @lluia @ndom91 @ThangHuuVu
|
||||
/docs/ @lluia @ndom91
|
||||
/packages/ @ThangHuuVu
|
||||
/packages/adapter-*/ @ndom91
|
||||
/**/*test* @lluia
|
||||
/**/*type* @lluia
|
||||
38
.github/PULL_REQUEST_TEMPLATE.md
vendored
38
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,48 +1,28 @@
|
||||
<!--
|
||||
Thanks for your interest in the project. Bugs filed and PRs submitted are appreciated!
|
||||
|
||||
Please make sure that you are familiar with and follow the Code of Conduct for
|
||||
this project (found in the CODE_OF_CONDUCT.md file).
|
||||
|
||||
Also, please make sure you're familiar with and follow the instructions in the
|
||||
contributing guidelines (found in the CONTRIBUTING.md file).
|
||||
|
||||
If you're new to contributing to open source projects, you might find this free
|
||||
video course helpful: https://kcd.im/pull-request
|
||||
|
||||
Please fill out the information below to expedite the review and (hopefully)
|
||||
merge of your pull request!
|
||||
-->
|
||||
|
||||
<!-- What changes are being made? (What feature/bug is being fixed here?) -->
|
||||
## ☕️ Reasoning
|
||||
|
||||
## 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 🧢
|
||||
|
||||
<!-- Feel free cross items ( like this `~[] item~` ) if they're irrelevant to your changes.
|
||||
|
||||
To check an item, place an `x` in the box like so: `- [x] Documentation`. -->
|
||||
## 🧢 Checklist
|
||||
|
||||
- [ ] Documentation
|
||||
- [ ] Tests
|
||||
- [ ] Ready to be merged
|
||||
|
||||
<!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
|
||||
## 🎫 Affected issues
|
||||
|
||||
## Affected issues 🎟
|
||||
|
||||
<!--
|
||||
Please [scout and link issues](https://github.com/nextauthjs/next-auth/issues) that might be solved by this PR.
|
||||
|
||||
If you write `"Fixes"` or `"Closes"` before the issue link like so:
|
||||
Fixes: INSERT_ISSUE_LINK_HERE
|
||||
|
||||
```
|
||||
Fixes #359
|
||||
```
|
||||
## 📌 Resources
|
||||
|
||||
the connected issue will be automatically closed once the PR is merged and hence help with maintenance of the library 😊
|
||||
|
||||
-->
|
||||
- [Contributing guidelines](./CONTRIBUTING.md)
|
||||
- [Code of conduct](./CODE_OF_CONDUCT.md)
|
||||
- [Contributing to Open Source](https://kcd.im/pull-request)
|
||||
|
||||
2
.github/pr-labeler.yml
vendored
2
.github/pr-labeler.yml
vendored
@@ -10,7 +10,7 @@ providers:
|
||||
|
||||
adapters:
|
||||
- packages/next-auth/src/adapters.ts
|
||||
- packages/*-adapter/**
|
||||
- packages/adapter-*/**
|
||||
|
||||
dgraph:
|
||||
- packages/adapter-dgraph/**
|
||||
|
||||
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: "node12"
|
||||
using: "node16"
|
||||
main: "index.js"
|
||||
|
||||
78
.github/workflows/release.yml
vendored
78
.github/workflows/release.yml
vendored
@@ -16,26 +16,23 @@ jobs:
|
||||
steps:
|
||||
- name: Init
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
with:
|
||||
version: 7.5.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: "yarn"
|
||||
- name: Cache Node Modules
|
||||
id: cache-node
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-${{ github.run_id }}
|
||||
cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: yarn --prefer-offline --frozen-lockfile
|
||||
run: pnpm install
|
||||
- name: Build
|
||||
run: yarn build
|
||||
run: pnpm build
|
||||
- name: Run tests
|
||||
run: yarn test
|
||||
run: pnpm test
|
||||
env:
|
||||
UPSTASH_REDIS_URL: ${{ secrets.UPSTASH_REDIS_URL }}
|
||||
UPSTASH_REDIS_KEY: ${{ secrets.UPSTASH_REDIS_KEY }}
|
||||
@@ -55,29 +52,25 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
with:
|
||||
version: 7.5.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: "yarn"
|
||||
- name: Cache Node Modules
|
||||
id: cache-node
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-${{ github.run_id }}
|
||||
cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: yarn --prefer-offline --frozen-lockfile
|
||||
run: pnpm install
|
||||
- name: Publish to npm and GitHub
|
||||
run: |
|
||||
git config --global user.email "balazsorban44@users.noreply.github.com"
|
||||
git config --global user.name "Balázs Orbán"
|
||||
yarn release
|
||||
pnpm release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
NPM_TOKEN_PKG: ${{ secrets.NPM_TOKEN_PKG }}
|
||||
NPM_TOKEN_ORG: ${{ secrets.NPM_TOKEN_ORG }}
|
||||
release-pr:
|
||||
@@ -89,22 +82,17 @@ jobs:
|
||||
steps:
|
||||
- name: Init
|
||||
uses: actions/checkout@v2
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
with:
|
||||
version: 7.5.1
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: "yarn"
|
||||
- name: Cache Node Modules
|
||||
id: cache-node
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: "**/node_modules"
|
||||
key: cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-${{ github.run_id }}
|
||||
cache-node_modules-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }}-
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: yarn --prefer-offline --frozen-lockfile
|
||||
run: pnpm install
|
||||
- name: Determine version
|
||||
uses: ./.github/version-pr
|
||||
id: determine-version
|
||||
@@ -114,13 +102,17 @@ jobs:
|
||||
run: |
|
||||
cd packages/next-auth
|
||||
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> .npmrc
|
||||
npm publish --access public --tag experimental
|
||||
pnpm publish --no-git-checks --access public --tag experimental
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN_PKG }}
|
||||
- name: Comment version on PR
|
||||
uses: NejcZdovc/comment-pr@v1
|
||||
with:
|
||||
message: "🎉 Experimental release [published on npm](https://www.npmjs.com/package/next-auth/v/${{ env.VERSION }})!\n\n```sh\nnpm i next-auth@${{ env.VERSION }}\n```\n```sh\nyarn add next-auth@${{ env.VERSION }}\n```"
|
||||
message:
|
||||
"🎉 Experimental release [published 📦️ on npm](https://npmjs.com/package/next-auth/v/${{ env.VERSION }})!\n \
|
||||
```sh\npnpm add next-auth@${{ env.VERSION }}\n```\n \
|
||||
```sh\nyarn add next-auth@${{ env.VERSION }}\n```\n \
|
||||
```sh\nnpm i next-auth@${{ env.VERSION }}\n```"
|
||||
env:
|
||||
VERSION: ${{ steps.determine-version.outputs.version }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -12,6 +12,7 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
firebase-debug.log
|
||||
.pnpm-debug.log
|
||||
|
||||
|
||||
# Dependencies
|
||||
@@ -29,11 +30,12 @@ packages/next-auth/providers
|
||||
packages/next-auth/src/providers/oauth-types.ts
|
||||
packages/next-auth/client
|
||||
packages/next-auth/css
|
||||
packages/next-auth/lib
|
||||
packages/next-auth/utils
|
||||
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
|
||||
@@ -43,6 +45,7 @@ packages/next-auth/middleware.js
|
||||
# Development app
|
||||
apps/dev/src/css
|
||||
apps/dev/prisma/migrations
|
||||
apps/dev/typeorm
|
||||
|
||||
# VS
|
||||
/.vs/slnx.sqlite-journal
|
||||
|
||||
@@ -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 me@iaincollins.com or info@balazsorban.com and yo@ndo.dev.
|
||||
reported by contacting info@balazsorban.com, yo@ndo.dev, thvu@hey.com 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
|
||||
|
||||
@@ -17,7 +17,7 @@ Anyone can be a contributor. Either you found a typo, or you have an awesome fea
|
||||
- The latest changes are always in `main`, so please make your Pull Request against that branch.
|
||||
- Pull Requests should be raised for any change
|
||||
- Pull Requests need approval of a [core contributor](https://next-auth.js.org/contributors#core-team) before merging
|
||||
- We use ESLint/Prettier for linting/formatting, so please run `yarn lint:fix` before committing to make resolving conflicts easier (VSCode users, check out [this ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [this Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to fix lint and formatting issues in development)
|
||||
- We use ESLint/Prettier for linting/formatting, so please run `pnpm lint:fix` before committing to make resolving conflicts easier (VSCode users, check out [this ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) and [this Prettier extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) to fix lint and formatting issues in development)
|
||||
- We encourage you to test your changes, and if you have the opportunity, please make those tests part of the Pull Request
|
||||
- If you add new functionality, please provide the corresponding documentation as well and make it part of the Pull Request
|
||||
|
||||
@@ -37,7 +37,7 @@ cd next-auth
|
||||
1. Install packages. Developing requires Node.js v16:
|
||||
|
||||
```sh
|
||||
yarn
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Populate `.env.local`:
|
||||
@@ -55,7 +55,7 @@ cp .env.local.example .env.local
|
||||
4. Start the developer application/server:
|
||||
|
||||
```sh
|
||||
yarn dev:app
|
||||
pnpm dev
|
||||
```
|
||||
Your developer application will be available on `http://localhost:3000`
|
||||
|
||||
@@ -65,7 +65,7 @@ If you need an example project to link to, you can use [next-auth-example](https
|
||||
|
||||
#### Hot reloading
|
||||
|
||||
When running `yarn dev:app`, you start a Next.js developer server on `http://localhost:3000`, which includes hot reloading out of the box. Make changes on any of the files in `src` and see the changes immediately.
|
||||
When running `pnpm dev`, you start a Next.js developer server on `http://localhost:3000`, which includes hot reloading out-of-the-box. Make changes on any of the files in `src` and see the changes immediately.
|
||||
|
||||
> NOTE: When working on CSS, you will have to manually refresh the page after changes. The reason for this is our pages using CSS are server-side rendered (using API routes). (Improving this through a PR is very welcome!)
|
||||
|
||||
@@ -75,7 +75,7 @@ When running `yarn dev:app`, you start a Next.js developer server on `http://loc
|
||||
|
||||
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:
|
||||
|
||||
1. Add your config: [`src/providers/{provider}.js`](https://github.com/nextauthjs/next-auth/tree/main/src/providers) (Make sure you use a named default export, like `export default function YourProvider`!)
|
||||
1. Add your config: [`src/providers/{provider}.js`](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers) (Make sure you use a named default export, like `export default function YourProvider`!)
|
||||
2. Add provider documentation: [`www/docs/providers/{provider}.md`](https://github.com/nextauthjs/next-auth/tree/main/www/docs/providers)
|
||||
|
||||
That's it! 🎉 Others will be able to discover this provider much more easily now!
|
||||
@@ -88,13 +88,13 @@ If you would like to contribute to an existing database adapter or help create a
|
||||
|
||||
#### Testing
|
||||
|
||||
Tests can be run with `yarn test`.
|
||||
Tests can be run with `pnpm test`.
|
||||
|
||||
Automated tests are currently crude and limited in functionality, but improvements are in development.
|
||||
|
||||
## For maintainers
|
||||
|
||||
We use [a custom script](https://github.com/nextauthjs/next-auth/tree/main/scripts/index.ts) together with [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0) to automate releases. This makes the maintenance process easier and less error-prone. Please study the "Conventional Commits" site to understand how to write a good commit message.
|
||||
We use [a custom script](https://github.com/nextauthjs/next-auth/blob/main/scripts/release/index.ts) together with [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0) to automate releases. This makes the maintenance process easier and less error-prone. Please study the "Conventional Commits" site to understand how to write a good commit message.
|
||||
|
||||
When accepting Pull Requests, make sure the following:
|
||||
|
||||
@@ -103,9 +103,9 @@ When accepting Pull Requests, make sure the following:
|
||||
- Rewrite the commit message to conform to the `Conventional Commits` style.
|
||||
- Using `fix` releases a patch (x.x.1)
|
||||
- Using `feat` releases a minor (x.1.x)
|
||||
- Using `feat` when `BREAKING CHANGE` is present in the commit messgae releases a major (1.x.x)
|
||||
- Using `feat` when `BREAKING CHANGE` is present in the commit message releases a major (1.x.x)
|
||||
- Optionally link issues the PR will resolve (You can add "close" in front of the issue numbers to close the issues automatically, when the PR is merged. `semantic-release` will also comment back to connected issues and PRs, notifying the users that a feature is added/bug fixed, etc.)
|
||||
|
||||
### Skipping a release
|
||||
|
||||
If a commit contains `[skip release]` in their message will be excluded from the commit analysis and won't participate in the release type determination. This is useful, if the PR being merged should not trigger a new `npm` release.
|
||||
If a commit contains `[skip release]` in their message, it will be excluded from the commit analysis and won't participate in the release type determination. This is useful, if the PR being merged should not trigger a new `npm` release.
|
||||
@@ -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 or me@iaincollins.com and yo@ndo.dev, or raise a public issue requesting someone get in touch with you via whatever means you prefer for more details. (Please do not disclose sensitive details publicly at this stage.)
|
||||
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.)
|
||||
|
||||
> 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
|
||||
|
||||
|
||||
@@ -47,6 +47,5 @@ EMAIL_FROM=user@gmail.com
|
||||
# MongoDB: DATABASE_URL=mongodb://nextauth:password@127.0.0.1:27017/nextauth?synchronize=true
|
||||
DATABASE_URL=
|
||||
|
||||
BOXYHQSAML_ISSUER="https://jackson-demo.boxyhq.com"
|
||||
BOXYHQSAML_ID="tenant=boxyhq.com&product=saml-demo.boxyhq.com"
|
||||
BOXYHQSAML_SECRET="dummy"
|
||||
WIKIMEDIA_ID=
|
||||
WIKIMEDIA_SECRET=
|
||||
@@ -1,5 +1,7 @@
|
||||
export { default } from "next-auth/middleware"
|
||||
|
||||
export const config = { matcher: ["/middleware-protected"] }
|
||||
|
||||
// Other ways to use this middleware
|
||||
|
||||
// import withAuth from "next-auth/middleware"
|
||||
@@ -28,12 +30,11 @@ export { default } from "next-auth/middleware"
|
||||
// export default withAuth(
|
||||
// function middleware(req, ev) {
|
||||
// console.log(req, ev)
|
||||
// return undefined // NOTE: `NextMiddleware` should allow returning `void`
|
||||
// },
|
||||
// {
|
||||
// callbacks: {
|
||||
// authorized: ({ token }) => token.name === "Balázs Orbán",
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
// )
|
||||
|
||||
@@ -5,5 +5,4 @@ module.exports = {
|
||||
return config
|
||||
},
|
||||
typescript: { ignoreBuildErrors: true },
|
||||
experimental: { externalDir: true },
|
||||
}
|
||||
|
||||
@@ -5,30 +5,32 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"clean": "rm -rf .next",
|
||||
"copy:css": "cpx \"../../packages/next-auth/css/**/*\" src/css --watch",
|
||||
"watch:css": "cd ../../packages/next-auth && npm run watch:css",
|
||||
"dev": "npm-run-all --parallel dev:next watch:css copy:css",
|
||||
"dev:next": "npx next dev",
|
||||
"build": "npx next build",
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"email": "npx fake-smtp-server",
|
||||
"start:email": "npm run email"
|
||||
"email": "fake-smtp-server",
|
||||
"start:email": "pnpm email"
|
||||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@next-auth/fauna-adapter": "^1.0.1",
|
||||
"@next-auth/prisma-adapter": "^1.0.1",
|
||||
"@prisma/client": "^3.10.0",
|
||||
"fake-smtp-server": "^0.8.0",
|
||||
"faunadb": "^4.4.1",
|
||||
"next": "^12.1.0",
|
||||
"nodemailer": "^6.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"@next-auth/fauna-adapter": "workspace:*",
|
||||
"@next-auth/prisma-adapter": "workspace:*",
|
||||
"@next-auth/typeorm-legacy-adapter": "workspace:*",
|
||||
"@prisma/client": "^3",
|
||||
"faunadb": "^4",
|
||||
"next": "12.2.0",
|
||||
"next-auth": "workspace:*",
|
||||
"nodemailer": "^6",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"prisma": "^3.10.0"
|
||||
"@types/react": "^18.0.15",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"fake-smtp-server": "^0.8.0",
|
||||
"pg": "^8.7.3",
|
||||
"prisma": "^3",
|
||||
"sqlite3": "^5.0.8",
|
||||
"typeorm": "0.3.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,218 +1,134 @@
|
||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||
// import EmailProvider from "next-auth/providers/email"
|
||||
import GitHubProvider from "next-auth/providers/github"
|
||||
import Auth0Provider from "next-auth/providers/auth0"
|
||||
import KeycloakProvider from "next-auth/providers/keycloak"
|
||||
import TwitterProvider, {
|
||||
TwitterLegacy as TwitterLegacyProvider,
|
||||
} from "next-auth/providers/twitter"
|
||||
import CredentialsProvider from "next-auth/providers/credentials"
|
||||
import IDS4Provider from "next-auth/providers/identity-server4"
|
||||
import Twitch from "next-auth/providers/twitch"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import FacebookProvider from "next-auth/providers/facebook"
|
||||
import FoursquareProvider from "next-auth/providers/foursquare"
|
||||
// import FreshbooksProvider from "next-auth/providers/freshbooks"
|
||||
import GitlabProvider from "next-auth/providers/gitlab"
|
||||
import InstagramProvider from "next-auth/providers/instagram"
|
||||
import LineProvider from "next-auth/providers/line"
|
||||
import LinkedInProvider from "next-auth/providers/linkedin"
|
||||
import MailchimpProvider from "next-auth/providers/mailchimp"
|
||||
import DiscordProvider from "next-auth/providers/discord"
|
||||
import AzureADProvider from "next-auth/providers/azure-ad"
|
||||
import SpotifyProvider from "next-auth/providers/spotify"
|
||||
import CognitoProvider from "next-auth/providers/cognito"
|
||||
import SlackProvider from "next-auth/providers/slack"
|
||||
import Okta from "next-auth/providers/okta"
|
||||
import NextAuth from "next-auth"
|
||||
import type { NextAuthOptions } from "next-auth"
|
||||
|
||||
// Providers
|
||||
import Apple from "next-auth/providers/apple"
|
||||
import Auth0 from "next-auth/providers/auth0"
|
||||
import AzureAD from "next-auth/providers/azure-ad"
|
||||
import AzureB2C from "next-auth/providers/azure-ad-b2c"
|
||||
import OsuProvider from "next-auth/providers/osu"
|
||||
import AppleProvider from "next-auth/providers/apple"
|
||||
import PatreonProvider from "next-auth/providers/patreon"
|
||||
import TraktProvider from "next-auth/providers/trakt"
|
||||
import WorkOSProvider from "next-auth/providers/workos"
|
||||
import BoxyHQSAMLProvider from "next-auth/providers/boxyhq-saml"
|
||||
import BoxyHQSAML from "next-auth/providers/boxyhq-saml"
|
||||
import Cognito from "next-auth/providers/cognito"
|
||||
import Credentials from "next-auth/providers/credentials"
|
||||
import Discord from "next-auth/providers/discord"
|
||||
import DuendeIDS6 from "next-auth/providers/duende-identity-server6"
|
||||
import Email from "next-auth/providers/email"
|
||||
import Facebook from "next-auth/providers/facebook"
|
||||
import Foursquare from "next-auth/providers/foursquare"
|
||||
import Freshbooks from "next-auth/providers/freshbooks"
|
||||
import GitHub from "next-auth/providers/github"
|
||||
import Gitlab from "next-auth/providers/gitlab"
|
||||
import Google from "next-auth/providers/google"
|
||||
import IDS4 from "next-auth/providers/identity-server4"
|
||||
import Instagram from "next-auth/providers/instagram"
|
||||
import Keycloak from "next-auth/providers/keycloak"
|
||||
import Line from "next-auth/providers/line"
|
||||
import LinkedIn from "next-auth/providers/linkedin"
|
||||
import Mailchimp from "next-auth/providers/mailchimp"
|
||||
import Okta from "next-auth/providers/okta"
|
||||
import Osu from "next-auth/providers/osu"
|
||||
import Patreon from "next-auth/providers/patreon"
|
||||
import Slack from "next-auth/providers/slack"
|
||||
import Spotify from "next-auth/providers/spotify"
|
||||
import Trakt from "next-auth/providers/trakt"
|
||||
import Twitch from "next-auth/providers/twitch"
|
||||
import Twitter, { 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 { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||
// import { PrismaClient } from "@prisma/client"
|
||||
// const prisma = new PrismaClient()
|
||||
// const adapter = PrismaAdapter(prisma)
|
||||
// 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"
|
||||
|
||||
// import { Client as FaunaClient } from "faunadb"
|
||||
// import { FaunaAdapter } from "@next-auth/fauna-adapter"
|
||||
|
||||
// const client = new FaunaClient({
|
||||
// secret: process.env.FAUNA_SECRET,
|
||||
// domain: process.env.FAUNA_DOMAIN,
|
||||
// })
|
||||
// const adapter = FaunaAdapter(client)
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// adapter,
|
||||
providers: [
|
||||
// E-mail
|
||||
// Start fake e-mail server with `npm run start:email`
|
||||
// EmailProvider({
|
||||
// server: {
|
||||
// host: "127.0.0.1",
|
||||
// auth: null,
|
||||
// secure: false,
|
||||
// port: 1025,
|
||||
// tls: { rejectUnauthorized: false },
|
||||
// },
|
||||
// }),
|
||||
// Credentials
|
||||
CredentialsProvider({
|
||||
name: "Credentials",
|
||||
credentials: {
|
||||
password: { label: "Password", type: "password" },
|
||||
},
|
||||
async authorize(credentials) {
|
||||
if (credentials.password === "pw") {
|
||||
return {
|
||||
name: "Fill Murray",
|
||||
email: "bill@fillmurray.com",
|
||||
image: "https://www.fillmurray.com/64/64",
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
}),
|
||||
// OAuth 1
|
||||
// TwitterLegacyProvider({
|
||||
// clientId: process.env.TWITTER_LEGACY_ID,
|
||||
// clientSecret: process.env.TWITTER_LEGACY_SECRET,
|
||||
// }),
|
||||
// OAuth 2 / OIDC
|
||||
TwitterProvider({
|
||||
// Opt-in to the new Twitter API for now. Should be default in the future.
|
||||
version: "2.0",
|
||||
clientId: process.env.TWITTER_ID,
|
||||
clientSecret: process.env.TWITTER_SECRET,
|
||||
}),
|
||||
GitHubProvider({
|
||||
clientId: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET,
|
||||
}),
|
||||
Auth0Provider({
|
||||
clientId: process.env.AUTH0_ID,
|
||||
clientSecret: process.env.AUTH0_SECRET,
|
||||
issuer: process.env.AUTH0_ISSUER,
|
||||
}),
|
||||
KeycloakProvider({
|
||||
clientId: process.env.KEYCLOAK_ID,
|
||||
clientSecret: process.env.KEYCLOAK_SECRET,
|
||||
issuer: process.env.KEYCLOAK_ISSUER,
|
||||
}),
|
||||
Twitch({
|
||||
clientId: process.env.TWITCH_ID,
|
||||
clientSecret: process.env.TWITCH_SECRET,
|
||||
}),
|
||||
GoogleProvider({
|
||||
clientId: process.env.GOOGLE_ID,
|
||||
clientSecret: process.env.GOOGLE_SECRET,
|
||||
}),
|
||||
FacebookProvider({
|
||||
clientId: process.env.FACEBOOK_ID,
|
||||
clientSecret: process.env.FACEBOOK_SECRET,
|
||||
}),
|
||||
FoursquareProvider({
|
||||
clientId: process.env.FOURSQUARE_ID,
|
||||
clientSecret: process.env.FOURSQUARE_SECRET,
|
||||
}),
|
||||
// FreshbooksProvider({
|
||||
// clientId: process.env.FRESHBOOKS_ID,
|
||||
// clientSecret: process.env.FRESHBOOKS_SECRET,
|
||||
// }),
|
||||
GitlabProvider({
|
||||
clientId: process.env.GITLAB_ID,
|
||||
clientSecret: process.env.GITLAB_SECRET,
|
||||
}),
|
||||
InstagramProvider({
|
||||
clientId: process.env.INSTAGRAM_ID,
|
||||
clientSecret: process.env.INSTAGRAM_SECRET,
|
||||
}),
|
||||
LineProvider({
|
||||
clientId: process.env.LINE_ID,
|
||||
clientSecret: process.env.LINE_SECRET,
|
||||
}),
|
||||
LinkedInProvider({
|
||||
clientId: process.env.LINKEDIN_ID,
|
||||
clientSecret: process.env.LINKEDIN_SECRET,
|
||||
}),
|
||||
MailchimpProvider({
|
||||
clientId: process.env.MAILCHIMP_ID,
|
||||
clientSecret: process.env.MAILCHIMP_SECRET,
|
||||
}),
|
||||
IDS4Provider({
|
||||
clientId: process.env.IDS4_ID,
|
||||
clientSecret: process.env.IDS4_SECRET,
|
||||
issuer: process.env.IDS4_ISSUER,
|
||||
}),
|
||||
DiscordProvider({
|
||||
clientId: process.env.DISCORD_ID,
|
||||
clientSecret: process.env.DISCORD_SECRET,
|
||||
}),
|
||||
AzureADProvider({
|
||||
clientId: process.env.AZURE_AD_CLIENT_ID,
|
||||
clientSecret: process.env.AZURE_AD_CLIENT_SECRET,
|
||||
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||
profilePhotoSize: 48,
|
||||
}),
|
||||
SpotifyProvider({
|
||||
clientId: process.env.SPOTIFY_ID,
|
||||
clientSecret: process.env.SPOTIFY_SECRET,
|
||||
}),
|
||||
CognitoProvider({
|
||||
clientId: process.env.COGNITO_ID,
|
||||
clientSecret: process.env.COGNITO_SECRET,
|
||||
issuer: process.env.COGNITO_ISSUER,
|
||||
}),
|
||||
Okta({
|
||||
clientId: process.env.OKTA_ID,
|
||||
clientSecret: process.env.OKTA_SECRET,
|
||||
issuer: process.env.OKTA_ISSUER,
|
||||
}),
|
||||
SlackProvider({
|
||||
clientId: process.env.SLACK_ID,
|
||||
clientSecret: process.env.SLACK_SECRET,
|
||||
}),
|
||||
AzureB2C({
|
||||
clientId: process.env.AZURE_B2C_ID,
|
||||
clientSecret: process.env.AZURE_B2C_SECRET,
|
||||
tenantId: process.env.AZURE_B2C_TENANT_ID,
|
||||
primaryUserFlow: process.env.AZURE_B2C_PRIMARY_USER_FLOW,
|
||||
}),
|
||||
OsuProvider({
|
||||
clientId: process.env.OSU_CLIENT_ID,
|
||||
clientSecret: process.env.OSU_CLIENT_SECRET,
|
||||
}),
|
||||
AppleProvider({
|
||||
clientId: process.env.APPLE_ID,
|
||||
clientSecret: process.env.APPLE_SECRET,
|
||||
}),
|
||||
PatreonProvider({
|
||||
clientId: process.env.PATREON_ID,
|
||||
clientSecret: process.env.PATREON_SECRET,
|
||||
}),
|
||||
TraktProvider({
|
||||
clientId: process.env.TRAKT_ID,
|
||||
clientSecret: process.env.TRAKT_SECRET,
|
||||
}),
|
||||
WorkOSProvider({
|
||||
clientId: process.env.WORKOS_ID,
|
||||
clientSecret: process.env.WORKOS_SECRET,
|
||||
}),
|
||||
BoxyHQSAMLProvider({
|
||||
issuer: process.env.BOXYHQSAML_ISSUER,
|
||||
clientId: process.env.BOXYHQSAML_ID,
|
||||
clientSecret: process.env.BOXYHQSAML_SECRET,
|
||||
}),
|
||||
],
|
||||
debug: true,
|
||||
theme: {
|
||||
colorScheme: "auto",
|
||||
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||
brandColor: "#1786fb",
|
||||
// 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
|
||||
},
|
||||
}
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
adapter: adapters.noop(),
|
||||
debug: true,
|
||||
theme: {
|
||||
logo: "https://next-auth.js.org/img/logo/logo-sm.png",
|
||||
brandColor: "#1786fb",
|
||||
},
|
||||
providers: [
|
||||
Credentials({
|
||||
credentials: { password: { label: "Password", type: "password" } },
|
||||
async authorize(credentials) {
|
||||
if (credentials.password !== "pw") return null
|
||||
return { name: "Fill Murray", email: "bill@fillmurray.com", image: "https://www.fillmurray.com/64/64" }
|
||||
},
|
||||
}),
|
||||
Apple({ clientId: process.env.APPLE_ID, clientSecret: process.env.APPLE_SECRET }),
|
||||
Auth0({ clientId: process.env.AUTH0_ID, clientSecret: process.env.AUTH0_SECRET, issuer: process.env.AUTH0_ISSUER }),
|
||||
AzureAD({ clientId: process.env.AZURE_AD_CLIENT_ID, clientSecret: process.env.AZURE_AD_CLIENT_SECRET, tenantId: process.env.AZURE_AD_TENANT_ID }),
|
||||
AzureB2C({ clientId: process.env.AZURE_B2C_ID, clientSecret: process.env.AZURE_B2C_SECRET, issuer: process.env.AZURE_B2C_ISSUER }),
|
||||
BoxyHQSAML({ issuer: "https://jackson-demo.boxyhq.com", clientId: "tenant=boxyhq.com&product=saml-demo.boxyhq.com", clientSecret: "dummy" }),
|
||||
Cognito({ clientId: process.env.COGNITO_ID, clientSecret: process.env.COGNITO_SECRET, issuer: process.env.COGNITO_ISSUER }),
|
||||
Discord({ clientId: process.env.DISCORD_ID, clientSecret: process.env.DISCORD_SECRET }),
|
||||
DuendeIDS6({ clientId: "interactive.confidential", clientSecret: "secret", issuer: "https://demo.duendesoftware.com" }),
|
||||
Facebook({ clientId: process.env.FACEBOOK_ID, clientSecret: process.env.FACEBOOK_SECRET }),
|
||||
Foursquare({ clientId: process.env.FOURSQUARE_ID, clientSecret: process.env.FOURSQUARE_SECRET }),
|
||||
Freshbooks({ clientId: process.env.FRESHBOOKS_ID, clientSecret: process.env.FRESHBOOKS_SECRET }),
|
||||
GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET }),
|
||||
Gitlab({ clientId: process.env.GITLAB_ID, clientSecret: process.env.GITLAB_SECRET }),
|
||||
Google({ clientId: process.env.GOOGLE_ID, clientSecret: process.env.GOOGLE_SECRET }),
|
||||
IDS4({ clientId: process.env.IDS4_ID, clientSecret: process.env.IDS4_SECRET, issuer: process.env.IDS4_ISSUER }),
|
||||
Instagram({ clientId: process.env.INSTAGRAM_ID, clientSecret: process.env.INSTAGRAM_SECRET }),
|
||||
Keycloak({ clientId: process.env.KEYCLOAK_ID, clientSecret: process.env.KEYCLOAK_SECRET, issuer: process.env.KEYCLOAK_ISSUER }),
|
||||
Line({ clientId: process.env.LINE_ID, clientSecret: process.env.LINE_SECRET }),
|
||||
LinkedIn({ clientId: process.env.LINKEDIN_ID, clientSecret: process.env.LINKEDIN_SECRET }),
|
||||
Mailchimp({ clientId: process.env.MAILCHIMP_ID, clientSecret: process.env.MAILCHIMP_SECRET }),
|
||||
Okta({ clientId: process.env.OKTA_ID, clientSecret: process.env.OKTA_SECRET, issuer: process.env.OKTA_ISSUER }),
|
||||
Osu({ clientId: process.env.OSU_CLIENT_ID, clientSecret: process.env.OSU_CLIENT_SECRET }),
|
||||
Patreon({ clientId: process.env.PATREON_ID, clientSecret: process.env.PATREON_SECRET }),
|
||||
Slack({ clientId: process.env.SLACK_ID, clientSecret: process.env.SLACK_SECRET }),
|
||||
Spotify({ clientId: process.env.SPOTIFY_ID, clientSecret: process.env.SPOTIFY_SECRET }),
|
||||
Trakt({ clientId: process.env.TRAKT_ID, clientSecret: process.env.TRAKT_SECRET }),
|
||||
Twitch({ clientId: process.env.TWITCH_ID, clientSecret: process.env.TWITCH_SECRET }),
|
||||
Twitter({ version: "2.0", clientId: process.env.TWITTER_ID, clientSecret: process.env.TWITTER_SECRET }),
|
||||
TwitterLegacy({ clientId: process.env.TWITTER_LEGACY_ID, clientSecret: process.env.TWITTER_LEGACY_SECRET }),
|
||||
Vk({ clientId: process.env.VK_ID, clientSecret: process.env.VK_SECRET }),
|
||||
Wikimedia({ clientId: process.env.WIKIMEDIA_ID, clientSecret: process.env.WIKIMEDIA_SECRET }),
|
||||
WorkOS({ clientId: process.env.WORKOS_ID, clientSecret: process.env.WORKOS_SECRET }),
|
||||
],
|
||||
}
|
||||
|
||||
if (authOptions.adapter) {
|
||||
authOptions.providers.unshift(
|
||||
// NOTE: You can start a fake e-mail server with `pnpm email`
|
||||
// and then go to `http://localhost:1080` in the browser
|
||||
Email({ server: "smtp://127.0.0.1:1025?tls.rejectUnauthorized=false" })
|
||||
)
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
export default async (req, res) => {
|
||||
const token = await getToken({ req, secret: process.env.SECRET })
|
||||
const token = await getToken({ req })
|
||||
res.send(JSON.stringify(token, null, 2))
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// This is an example of to protect an API route
|
||||
import { getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getSession({ req })
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from '../auth/[...nextauth]';
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getSession({ req })
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
res.send(JSON.stringify(session, null, 2))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
@@ -26,7 +26,11 @@ export default function Page({ content, session }) {
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await getServerSession(context, authOptions)
|
||||
const session = await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
)
|
||||
let content = null
|
||||
|
||||
if (session) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import Layout from "../components/layout"
|
||||
import { authOptions } from './api/auth/[...nextauth]';
|
||||
|
||||
export default function Page() {
|
||||
// As this page uses Server Side Rendering, the `session` will be already
|
||||
@@ -11,13 +12,17 @@ export default function Page() {
|
||||
<Layout>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the universal <strong>getSession()</strong> method in{" "}
|
||||
<strong>getServerSideProps()</strong>.
|
||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||
in <strong>getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getSession()</strong> in{" "}
|
||||
<strong>getServerSideProps()</strong> is the recommended approach if you
|
||||
need to support Server Side Rendering with authentication.
|
||||
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||
<strong>getServerSideProps()</strong> is currently the recommended
|
||||
approach, although the API may still change, if you need to support
|
||||
Server Side Rendering with authentication.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getSession()</strong> is still recommended on the client.
|
||||
</p>
|
||||
<p>
|
||||
The advantage of Server Side Rendering is this page does not require
|
||||
@@ -35,7 +40,11 @@ export default function Page() {
|
||||
export async function getServerSideProps(context) {
|
||||
return {
|
||||
props: {
|
||||
session: await getSession(context),
|
||||
session: await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
"incremental": true,
|
||||
"jsx": "preserve",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"next-auth": ["../../packages/next-auth/src"],
|
||||
"next-auth/*": ["../../packages/next-auth/src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules", "jest.config.js"]
|
||||
|
||||
@@ -65,7 +65,6 @@ You **can** skip configuring a database and come back to it later if you want.
|
||||
For more information about setting up a database, please check out the following links:
|
||||
|
||||
* Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||
* Adapters Repo: [nextauthjs/adapters](https://github.com/nextauthjs/adapters)
|
||||
|
||||
### 3. Configure Authentication Providers
|
||||
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.0",
|
||||
"gatsby": "next",
|
||||
"next-auth": "^4.2.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"next-auth": "latest",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vercel": "^23.1.2"
|
||||
|
||||
@@ -68,7 +68,6 @@ You **can** skip configuring a database and come back to it later if you want.
|
||||
For more information about setting up a database, please check out the following links:
|
||||
|
||||
* Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||
* Adapters Repo: [nextauthjs/adapters](https://github.com/nextauthjs/adapters)
|
||||
|
||||
### 3. Configure Authentication Providers
|
||||
|
||||
|
||||
17
apps/example-nextjs/middleware.ts
Normal file
17
apps/example-nextjs/middleware.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
|
||||
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
||||
export default withAuth({
|
||||
callbacks: {
|
||||
authorized({ req, token }) {
|
||||
// `/admin` requires admin role
|
||||
if (req.nextUrl.pathname === "/admin") {
|
||||
return token?.userRole === "admin"
|
||||
}
|
||||
// `/me` only requires the user to be logged in
|
||||
return !!token
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export const config = { matcher: ["/admin", "/me"] }
|
||||
@@ -1,19 +1,15 @@
|
||||
{
|
||||
"name": "next-auth-example",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"description": "An example project for NextAuth.js",
|
||||
"description": "An example project for NextAuth.js with Next.js",
|
||||
"repository": "https://github.com/nextauthjs/next-auth-example.git",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"homepage": "https://next-auth-example.vercel.app",
|
||||
"main": "",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"types": "tsc --noEmit"
|
||||
"start": "next start"
|
||||
},
|
||||
"author": "Iain Collins <me@iaincollins.com>",
|
||||
"contributors": [
|
||||
@@ -21,20 +17,16 @@
|
||||
"Nico Domino <yo@ndo.dev>",
|
||||
"Lluis Agusti <hi@llu.lu>"
|
||||
],
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"next": "^12.0.11-canary.4",
|
||||
"next": "latest",
|
||||
"next-auth": "latest",
|
||||
"nodemailer": "^6.6.3",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"nodemailer": "^6",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.14",
|
||||
"@types/react": "^17.0.39",
|
||||
"typescript": "^4.5.5"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false
|
||||
"@types/node": "^17",
|
||||
"@types/react": "^18.0.15",
|
||||
"typescript": "^4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
import type { AppProps } from "next/app"
|
||||
import "./styles.css"
|
||||
|
||||
import type { AppProps } from "next/app"
|
||||
|
||||
// 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) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Layout from "../../components/layout"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
@@ -1,8 +0,0 @@
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
|
||||
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
||||
export default withAuth({
|
||||
callbacks: {
|
||||
authorized: ({ token }) => token?.userRole === "admin",
|
||||
},
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import NextAuth from "next-auth"
|
||||
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import FacebookProvider from "next-auth/providers/facebook"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
@@ -9,7 +9,7 @@ import Auth0Provider from "next-auth/providers/auth0"
|
||||
|
||||
// For more information on each option (and a full list of options) go to
|
||||
// https://next-auth.js.org/configuration/options
|
||||
export default NextAuth({
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// https://next-auth.js.org/configuration/providers/oauth
|
||||
providers: [
|
||||
/* EmailProvider({
|
||||
@@ -18,7 +18,7 @@ export default NextAuth({
|
||||
}),
|
||||
// Temporarily removing the Apple provider from the demo site as the
|
||||
// callback URL for it needs updating due to Vercel changing domains
|
||||
|
||||
|
||||
Providers.Apple({
|
||||
clientId: process.env.APPLE_ID,
|
||||
clientSecret: {
|
||||
@@ -60,4 +60,6 @@ export default NextAuth({
|
||||
return token
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// This is an example of how to read a JSON Web Token from an API route
|
||||
import { getToken } from "next-auth/jwt"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
const secret = process.env.NEXTAUTH_SECRET
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const token = await getToken({ req, secret })
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
// If you don't have the NEXTAUTH_SECRET environment variable set,
|
||||
// you will have to pass your secret as `secret` to `getToken`
|
||||
const token = await getToken({ req })
|
||||
res.send(JSON.stringify(token, null, 2))
|
||||
}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
// This is an example of to protect an API route
|
||||
import { getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const session = await getSession({ req })
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
return res.send({
|
||||
content:
|
||||
"This is protected content. You can access this content because you are signed in.",
|
||||
})
|
||||
} else {
|
||||
res.send({
|
||||
error: "You must be signed in to view the protected content on this page.",
|
||||
})
|
||||
}
|
||||
|
||||
res.send({
|
||||
error: "You must be signed in to view the protected content on this page.",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
// This is an example of how to access a session from an API route
|
||||
import { getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth"
|
||||
import { authOptions } from "../auth/[...nextauth]"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
const session = await getSession({ req })
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
) {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
res.send(JSON.stringify(session, null, 2))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useSession } from "next-auth/react"
|
||||
import Layout from "../../components/layout"
|
||||
import Layout from "../components/layout"
|
||||
|
||||
export default function MePage() {
|
||||
const { data } = useSession()
|
||||
@@ -1,2 +0,0 @@
|
||||
// More on how NextAuth.js middleware works: https://next-auth.js.org/configuration/nextjs#middleware
|
||||
export { default } from "next-auth/middleware"
|
||||
@@ -1,26 +1,25 @@
|
||||
import { useSession, getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
import type { NextPageContext } from "next"
|
||||
|
||||
export default function ServerSidePage() {
|
||||
import type { GetServerSidePropsContext } from "next"
|
||||
import type { Session } from "next-auth"
|
||||
|
||||
export default function ServerSidePage({ session }: { session: Session }) {
|
||||
// As this page uses Server Side Rendering, the `session` will be already
|
||||
// populated on render without needing to go through a loading stage.
|
||||
// This is possible because of the shared context configured in `_app.js` that
|
||||
// is used by `useSession()`.
|
||||
const { data: session, status } = useSession()
|
||||
const loading = status === "loading"
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<h1>Server Side Rendering</h1>
|
||||
<p>
|
||||
This page uses the universal <strong>getSession()</strong> method in{" "}
|
||||
<strong>getServerSideProps()</strong>.
|
||||
This page uses the <strong>unstable_getServerSession()</strong> method
|
||||
in <strong>unstable_getServerSideProps()</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Using <strong>getSession()</strong> in{" "}
|
||||
<strong>getServerSideProps()</strong> is the recommended approach if you
|
||||
need to support Server Side Rendering with authentication.
|
||||
Using <strong>unstable_getServerSession()</strong> in{" "}
|
||||
<strong>unstable_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
|
||||
@@ -30,15 +29,20 @@ export default function ServerSidePage() {
|
||||
The disadvantage of Server Side Rendering is that this page is slower to
|
||||
render.
|
||||
</p>
|
||||
<pre>{JSON.stringify(session, null, 2)}</pre>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
// Export the `session` prop to use sessions with Server Side Rendering
|
||||
export async function getServerSideProps(context: NextPageContext) {
|
||||
export async function getServerSideProps(context: GetServerSidePropsContext) {
|
||||
return {
|
||||
props: {
|
||||
session: await getSession(context),
|
||||
session: await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -6,82 +6,60 @@ SvelteKit support with NextAuth.js is currently experimental. This directory con
|
||||
|
||||
## 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,38 @@
|
||||
{
|
||||
"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",
|
||||
"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",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte-check": "^2.2.6",
|
||||
"svelte-preprocess": "^4.10.1",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "~4.5.4"
|
||||
"@sveltejs/adapter-auto": "1.0.0-next.66",
|
||||
"@sveltejs/kit": "1.0.0-next.443",
|
||||
"@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.8.1",
|
||||
"svelte-preprocess": "^4.10.7",
|
||||
"tslib": "^2.4.0",
|
||||
"typescript": "~4.8.2",
|
||||
"vite": "^2.9.13"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"cookie": "0.4.1",
|
||||
"next-auth": "^4.3.2"
|
||||
"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 {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<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%
|
||||
</head>
|
||||
<body>
|
||||
<div>%svelte.body%</div>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
<div>%sveltekit.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,24 +1,12 @@
|
||||
import { getServerSession } from "$lib"
|
||||
import type { Session } from "next-auth"
|
||||
import type { NextAuthOptions } from "next-auth"
|
||||
import GithubProvider from "next-auth/providers/github"
|
||||
import type { Handle } from "@sveltejs/kit"
|
||||
import { getServerSession, options as nextAuthOptions } from "$lib/next-auth"
|
||||
|
||||
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> {
|
||||
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): Session {
|
||||
return event.locals.session || {}
|
||||
}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import NextAuth, { getServerSession } from "./next-auth"
|
||||
|
||||
export default NextAuth
|
||||
export { getServerSession }
|
||||
@@ -1,29 +1,53 @@
|
||||
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 {
|
||||
GITHUB_CLIENT_ID,
|
||||
GITHUB_CLIENT_SECRET,
|
||||
NEXTAUTH_SECRET,
|
||||
} from "$env/static/private"
|
||||
import { PUBLIC_NEXTAUTH_URL } from "$env/static/public"
|
||||
import getFormBody from "./utils/get-form-body"
|
||||
|
||||
async function toSvelteKitResponse(
|
||||
request: Request,
|
||||
nextAuthResponse: OutgoingResponse<unknown>
|
||||
) {
|
||||
const { headers, cookies, body, redirect, status = 200 } = nextAuthResponse
|
||||
const github = GithubProvider?.default || GithubProvider
|
||||
|
||||
const response = {
|
||||
status,
|
||||
headers: {},
|
||||
export const options: NextAuthOptions = {
|
||||
providers: [
|
||||
github({
|
||||
clientId: GITHUB_CLIENT_ID,
|
||||
clientSecret: GITHUB_CLIENT_SECRET,
|
||||
}),
|
||||
],
|
||||
}
|
||||
|
||||
const toSvelteKitResponse = async (
|
||||
request: Request,
|
||||
nextAuthResponse: NextAuthResponse<unknown>
|
||||
): Promise<Response> => {
|
||||
const { cookies, redirect } = nextAuthResponse
|
||||
|
||||
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
|
||||
@@ -34,41 +58,45 @@ async function toSvelteKitResponse(
|
||||
// no formData passed
|
||||
}
|
||||
if (formData?.json !== "true") {
|
||||
response.status = 302
|
||||
response.headers["Location"] = redirect
|
||||
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 = 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,
|
||||
options.secret = NEXTAUTH_SECRET
|
||||
const req: RequestInternal = {
|
||||
host: PUBLIC_NEXTAUTH_URL,
|
||||
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 +107,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 +126,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) => Promise<unknown>
|
||||
POST: (event) => Promise<unknown>
|
||||
} => ({
|
||||
get: (req) => SKNextAuthHandler(req, options),
|
||||
post: (req) => SKNextAuthHandler(req, options),
|
||||
GET: (event) => SKNextAuthHandler(event, options),
|
||||
POST: (event) => SKNextAuthHandler(event, options),
|
||||
})
|
||||
|
||||
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 {}
|
||||
}
|
||||
@@ -9,6 +9,11 @@ const config = {
|
||||
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
||||
// Override http methods in the Todo forms
|
||||
methodOverride: {
|
||||
allowed: ["PATCH", "DELETE"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -11,11 +11,11 @@ This is the Dgraph Adapter for [`next-auth`](https://next-auth.js.org).
|
||||
|
||||
1. Install the necessary packages
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
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"
|
||||
@@ -226,22 +226,22 @@ database you must customize next-auth `encode` and `decode` functions, as the de
|
||||
further customize the jwt with roles if you want to implement [`RBAC logic`](https://dgraph.io/docs/graphql/authorization/directive/#role-based-access-control).
|
||||
|
||||
```js
|
||||
import * as jwt from "jsonwebtoken";
|
||||
import * as jwt from "jsonwebtoken"
|
||||
export default NextAuth({
|
||||
session: {
|
||||
strategy: "jwt"
|
||||
strategy: "jwt",
|
||||
},
|
||||
jwt: {
|
||||
secret: process.env.SECRET,
|
||||
encode: async ({ secret, token }) => {
|
||||
return jwt.sign({...token, userId: token.id}, secret, {
|
||||
return jwt.sign({ ...token, userId: token.id }, secret, {
|
||||
algorithm: "HS256",
|
||||
expiresIn: 30 * 24 * 60 * 60; // 30 days
|
||||
});
|
||||
expiresIn: 30 * 24 * 60 * 60, // 30 days
|
||||
})
|
||||
},
|
||||
decode: async ({ secret, token }) => {
|
||||
return jwt.verify(token, secret, { algorithms: ["HS256"] });
|
||||
}
|
||||
return jwt.verify(token, secret, { algorithms: ["HS256"] })
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
@@ -15,7 +15,7 @@ You can find the full schema in the table structure section below.
|
||||
|
||||
1. Install `next-auth` and `@next-auth/dynamodb-adapter`
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/dynamodb-adapter
|
||||
```
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ You can find the Fauna schema and seed information in the docs at [next-auth.js.
|
||||
|
||||
1. Install the necessary packages
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
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"
|
||||
|
||||
@@ -5,18 +5,14 @@ title: Firebase
|
||||
|
||||
# Firebase
|
||||
|
||||
:::warning
|
||||
This adapter is still experimental and does not work with NextAuth.js 4 or newer. If you would like to help out upgrading it, please visit [this PR](https://github.com/nextauthjs/next-auth/pull/3873)
|
||||
:::
|
||||
|
||||
This is the Firebase Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
|
||||
This is the Firebase (Firestore) Adapter for [`next-auth`](https://next-auth.js.org). This package can only be used in conjunction with the primary `next-auth` package. It is not a standalone package.
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install the necessary packages
|
||||
|
||||
```bash npm2yarn
|
||||
npm install next-auth @next-auth/firebase-adapter@experimental
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/firebase-adapter
|
||||
```
|
||||
|
||||
2. Add this adapter to your `pages/api/auth/[...nextauth].js` next-auth configuration object.
|
||||
@@ -24,28 +20,31 @@ npm install next-auth @next-auth/firebase-adapter@experimental
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
import NextAuth from "next-auth"
|
||||
import GoogleProvider from "next-auth/providers/google"
|
||||
import { FirebaseAdapter } from "@next-auth/firebase-adapter"
|
||||
|
||||
import firebase from "firebase/app"
|
||||
import "firebase/firestore"
|
||||
|
||||
const firestore = (
|
||||
firebase.apps[0] ?? firebase.initializeApp(/* your config */)
|
||||
).firestore()
|
||||
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,
|
||||
clientSecret: process.env.GOOGLE_SECRET,
|
||||
}),
|
||||
],
|
||||
adapter: FirebaseAdapter(firestore),
|
||||
...
|
||||
})
|
||||
adapter: FirestoreAdapter({
|
||||
apiKey: process.env.FIREBASE_API_KEY,
|
||||
appId: process.env.FIREBASE_APP_ID,
|
||||
authDomain: process.env.FIREBASE_AUTH_DOMAIN,
|
||||
databaseURL: process.env.FIREBASE_DATABASE_URL,
|
||||
projectId: process.env.FIREBASE_PROJECT_ID,
|
||||
storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
|
||||
messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
|
||||
// Optional emulator config (see below for options)
|
||||
emulator: {},
|
||||
}),
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## Options
|
||||
@@ -69,6 +68,21 @@ const firebaseConfig = {
|
||||
|
||||
See [firebase.google.com/docs/web/setup](https://firebase.google.com/docs/web/setup) for more details.
|
||||
|
||||
You can optionally pass in emulator options to automatically connect to your local Firebase emulator.
|
||||
|
||||
```js
|
||||
FirestoreAdapter({
|
||||
// ...
|
||||
// Passing in an enable object will enable the emulator
|
||||
emulator: {
|
||||
// Optional host, defaults to `localhost`
|
||||
host: 'localhost',
|
||||
// Optional port, defaults to `3001`
|
||||
port: 3001,
|
||||
},
|
||||
}),
|
||||
```
|
||||
|
||||
:::tip **From Firebase**
|
||||
|
||||
**Caution**: We do not recommend manually modifying an app's Firebase config file or object. If you initialize an app with invalid or missing values for any of these required "Firebase options", then your end users may experience serious issues.
|
||||
|
||||
@@ -5,7 +5,7 @@ title: MikroORM
|
||||
|
||||
To use this Adapter, you need to install Mikro ORM, the driver that suits your database, and the separate `@next-auth/mikro-orm-adapter` package:
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/mikro-orm-adapter @mikro-orm/core @mikro-orm/[YOUR DRIVER]
|
||||
```
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ The MongoDB adapter does not handle connections automatically, so you will have
|
||||
|
||||
1. Install the necessary packages
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/mongodb-adapter mongodb
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,11 +11,11 @@ This is the Neo4j Adapter for [`next-auth`](https://next-auth.js.org). This pack
|
||||
|
||||
1. Install the necessary packages
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
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"
|
||||
|
||||
@@ -19,7 +19,7 @@ Depending on your architecture you can use PouchDB's http adapter to reach any d
|
||||
|
||||
1. Install `next-auth` and `@next-auth/pouchdb-adapter`
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/pouchdb-adapter
|
||||
```
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ title: Prisma
|
||||
|
||||
To use this Adapter, you need to install Prisma Client, Prisma CLI, and the separate `@next-auth/prisma-adapter` package:
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @prisma/client @next-auth/prisma-adapter
|
||||
npm install prisma --save-dev
|
||||
```
|
||||
@@ -107,6 +107,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
|
||||
```
|
||||
|
||||
@@ -11,7 +11,7 @@ This is the Sequelize Adapter for [`next-auth`](https://next-auth.js.org).
|
||||
|
||||
1. Install the necessary packages
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/sequelize-adapter sequelize
|
||||
```
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -5,21 +5,25 @@ title: TypeORM
|
||||
|
||||
# TypeORM
|
||||
|
||||
This Adapter is used to support SQL-flavored databases (like SQLite, MySQL, MSSQL, MariaDB, CockroachDB, etc.) through [TypeORM](https://typeorm.io), and mostly kept around for legacy reasons. (See the warning below.)
|
||||
This Adapter is used to support SQL-flavored databases (like SQLite, MySQL, MSSQL, MariaDB, CockroachDB, etc.) through [TypeORM](https://typeorm.io).
|
||||
|
||||
:::note
|
||||
If you previously used this Adapter with MongoDB, check out the [MongoDB Adapter](/adapters/mongodb) instead.
|
||||
:::
|
||||
|
||||
:::warning
|
||||
:::note
|
||||
In the future, we might split up this adapter to support single flavors of SQL for easier maintenance and reduced bundle size.
|
||||
:::
|
||||
|
||||
## Usage
|
||||
|
||||
:::warning
|
||||
[`typeorm`](https://github.com/typeorm/typeorm) is still in active development and has not yet published a stable release. Because of this, you can expect breaking changes in minor versions. This adapter expects `typeorm@0.3.7` and is not validated against previous or future releases.
|
||||
:::
|
||||
|
||||
To use this Adapter, you need to install the following packages:
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth @next-auth/typeorm-legacy-adapter typeorm
|
||||
```
|
||||
|
||||
@@ -36,7 +40,7 @@ export default NextAuth({
|
||||
})
|
||||
```
|
||||
|
||||
`TypeORMLegacyAdapter` takes either a connection string, or a [`ConnectionOptions`](https://github.com/typeorm/typeorm/blob/master/docs/connection-options.md) object as its first parameter.
|
||||
`TypeORMLegacyAdapter` takes either a connection string, or a [`DataSourceOptions`](https://github.com/typeorm/typeorm/blob/master/docs/data-source-options.md) object as its first parameter.
|
||||
|
||||
## Custom models
|
||||
|
||||
@@ -217,9 +221,9 @@ For example, you can add the naming convention option to the connection object i
|
||||
import NextAuth from "next-auth"
|
||||
import { TypeORMLegacyAdapter } from "@next-auth/typeorm-legacy-adapter"
|
||||
import { SnakeNamingStrategy } from 'typeorm-naming-strategies'
|
||||
import { ConnectionOptions } from "typeorm"
|
||||
|
||||
const connection: ConnectionOptions = {
|
||||
export default NextAuth({
|
||||
adapter: TypeORMLegacyAdapter({
|
||||
type: "mysql",
|
||||
host: "localhost",
|
||||
port: 3306,
|
||||
@@ -227,10 +231,7 @@ const connection: ConnectionOptions = {
|
||||
password: "test",
|
||||
database: "test",
|
||||
namingStrategy: new SnakeNamingStrategy()
|
||||
}
|
||||
|
||||
export default NextAuth({
|
||||
adapter: TypeORMLegacyAdapter(connection),
|
||||
}),
|
||||
...
|
||||
})
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@ title: Upstash Redis
|
||||
|
||||
To use this Adapter, you need to install `@upstash/redis` and `@next-auth/upstash-redis-adapter` package:
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install @upstash/redis @next-auth/upstash-redis-adapter
|
||||
```
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -107,7 +107,7 @@ The redirect callback may be invoked more than once in the same flow.
|
||||
This callback is called whenever a JSON Web Token is created (i.e. at sign
|
||||
in) or updated (i.e whenever a session is accessed in the client). The returned value will be [encrypted](/configuration/options#jwt), and it is stored in a cookie.
|
||||
|
||||
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `useSession()` will invoke this function, but only if you are using a [JWT session](/configuration/options#session). This method is not invoked when you persist sessions in a database.
|
||||
Requests to `/api/auth/signin`, `/api/auth/session` and calls to `getSession()`, `unstable_getServerSession()`, `useSession()` will invoke this function, but only if you are using a [JWT session](/configuration/options#session). This method is not invoked when you persist sessions in a database.
|
||||
|
||||
- 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.
|
||||
|
||||
@@ -53,6 +53,7 @@ The message object will contain:
|
||||
|
||||
- `user`: The user object from your adapter.
|
||||
- `account`: The object returned from the provider.
|
||||
- `profile`: The object returned from the `profile` callback of the OAuth provider.
|
||||
|
||||
### session
|
||||
|
||||
|
||||
@@ -1,5 +1,73 @@
|
||||
# Next.js
|
||||
|
||||
## `unstable_getServerSession`
|
||||
|
||||
:::warning
|
||||
This feature is experimental and may be removed or changed in the future.
|
||||
:::
|
||||
|
||||
When calling from server-side i.e. in API routes or in `getServerSideProps`, we recommend using this function instead of `getSession` to retrieve the `session` object. This method is especially useful when you are using NextAuth.js with a database. This method can _drastically_ reduce response time when used over `getSession` server-side, due to avoiding an extra `fetch` to an API Route (this is generally [not recommended in Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops-or-api-routes)). In addition, `unstable_getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
|
||||
|
||||
Otherwise, if you only want to get the session token, see [`getToken`](/tutorials/securing-pages-and-api-routes#using-gettoken).
|
||||
|
||||
`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].ts`:
|
||||
```ts
|
||||
import { NextAuth } from 'next-auth'
|
||||
import type { NextAuthOptions } from 'next-auth'
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// your configs
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions);
|
||||
```
|
||||
|
||||
In `getServerSideProps`:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await unstable_getServerSession(context.req, context.res, authOptions)
|
||||
|
||||
if (!session) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/',
|
||||
permanent: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
In API routes:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/auth/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
|
||||
export async function handler(req, res) {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (!session) {
|
||||
res.status(401).json({ message: "You must be logged in." });
|
||||
return;
|
||||
}
|
||||
|
||||
return res.json({
|
||||
message: 'Success',
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Middleware
|
||||
|
||||
You can use a Next.js Middleware with NextAuth.js to protect your site.
|
||||
@@ -12,20 +80,35 @@ You can get the `withAuth` middleware function from `next-auth/middleware` eithe
|
||||
|
||||
### Prerequisites
|
||||
|
||||
You must set the [`NEXTAUTH_SECRET`](/configuration/options#nextauth_secret) environment variable when using this middleware. If you are using the [`secret` option](/configuration/options#secret) this value must match.
|
||||
You must set the same secret in the middleware that you use in NextAuth. The easiest way is to set the [`NEXTAUTH_SECRET`](/configuration/options#nextauth_secret) environment variable. It will be picked up by both the [NextAuth config](/configuration/options#options), as well as the middleware config.
|
||||
|
||||
**We strongly recommend** replacing the `secret` value completely with this `NEXTAUTH_SECRET` environment variable. This environment variable will be picked up by both the [NextAuth config](/configuration/options#options), as well as the middleware config.
|
||||
Alternatively, you can provide the secret using the [`secret`](#secret) option in the middleware config.
|
||||
|
||||
---
|
||||
**We strongly recommend** replacing the `secret` value completely with this `NEXTAUTH_SECRET` environment variable.
|
||||
|
||||
### Basic usage
|
||||
|
||||
The most simple usage is when you want to require authentication for your entire site. You can add a `middleware.js` file with the following:
|
||||
|
||||
```js
|
||||
import withAuth from "next-auth/middleware"
|
||||
// or
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
export { default } from "next-auth/middleware"
|
||||
```
|
||||
|
||||
---
|
||||
That's it! Your application is now secured. 🎉
|
||||
|
||||
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"] }
|
||||
```
|
||||
|
||||
Now you will still be able to visit every page, but only `/dashboard` will require authentication.
|
||||
|
||||
If a user is not logged in, the default behavior is to redirect them to the sign-in page.
|
||||
|
||||
---
|
||||
### `callbacks`
|
||||
|
||||
- **Required:** No
|
||||
@@ -54,12 +137,16 @@ Callbacks are asynchronous functions you can use to control what happens when an
|
||||
|
||||
Specify URLs to be used if you want to create custom sign in, and error pages. Pages specified will override the corresponding built-in page.
|
||||
|
||||
:::note
|
||||
This should match the `pages` configuration that's found in `[...nextauth].ts`.
|
||||
:::
|
||||
|
||||
#### Example (default value)
|
||||
|
||||
```js
|
||||
pages: {
|
||||
signIn: '/auth/signin',
|
||||
error: '/auth/error',
|
||||
signIn: '/api/auth/signin',
|
||||
error: '/api/auth/error',
|
||||
}
|
||||
```
|
||||
|
||||
@@ -67,46 +154,38 @@ See the documentation for the [pages option](/configuration/pages) for more info
|
||||
|
||||
---
|
||||
|
||||
### Examples
|
||||
### `secret`
|
||||
|
||||
`withAuth` is very flexible, there are multiple ways to use it.
|
||||
- **Required**: _No_
|
||||
|
||||
#### Description
|
||||
|
||||
The same `secret` used in the [NextAuth.js config](/configuration/options#options).
|
||||
|
||||
#### Example (default value)
|
||||
|
||||
```js
|
||||
secret: process.env.NEXTAUTH_SECRET
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Advanced usage
|
||||
|
||||
NextAuth.js Middleware is very flexible, there are multiple ways to use it.
|
||||
|
||||
:::note
|
||||
If you do not define the options, NextAuth.js will use the default values for the omitted options.
|
||||
:::
|
||||
|
||||
#### default re-export
|
||||
|
||||
```js title="pages/_middleware.js"
|
||||
export { default } from "next-auth/middleware"
|
||||
```
|
||||
|
||||
With this one line, when someone tries to load any of your pages, they will have to be logged-in first. Otherwise, they are redirected to the login page. It will assume that you are using the `NEXTAUTH_SECRET` environment variable.
|
||||
|
||||
#### default `withAuth` export
|
||||
|
||||
```js title="pages/admin/_middleware.js"
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
|
||||
export default withAuth({
|
||||
callbacks: {
|
||||
authorized: ({ token }) => token?.role === "admin",
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
With the above code, you just made sure that only user's with the `admin` role can access any of the pages under the `/admin` route. (Including nested routes as well, like `/admin/settings` etc.).
|
||||
|
||||
#### wrap middleware
|
||||
|
||||
```ts title="pages/admin/_middleware.ts"
|
||||
import type { NextRequest } from "next/server"
|
||||
import type { JWT } from "next-auth/jwt"
|
||||
|
||||
```ts title="middleware.ts"
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
|
||||
export default withAuth(
|
||||
function middleware(req: NextRequest & { nextauth: { token: JWT } }) {
|
||||
// `withAuth` augments your `Request` with the user's token.
|
||||
function middleware(req) {
|
||||
console.log(req.nextauth.token)
|
||||
},
|
||||
{
|
||||
@@ -115,12 +194,53 @@ export default withAuth(
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export const config = { matcher: ["/admin"] }
|
||||
```
|
||||
|
||||
The `middleware` function will only be invoked if the `authorized` callback returns `true`.
|
||||
|
||||
---
|
||||
|
||||
#### Custom JWT decode method
|
||||
|
||||
If you have a custom jwt decode method set in `[...nextauth].ts`, you must also pass the same `decode` method to `withAuth` in order to read the custom-signed JWT correctly. You may want to extract the encode/decode logic to a separate function for consistency.
|
||||
|
||||
``
|
||||
```ts title="/api/auth/[...nextauth].ts"
|
||||
import type { NextAuthOptions } from "next-auth"
|
||||
import NextAuth from "next-auth"
|
||||
import jwt from "jsonwebtoken"
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
providers: [...],
|
||||
jwt: {
|
||||
async encode({ secret, token }) {
|
||||
return jwt.sign(token, secret)
|
||||
},
|
||||
async decode({ secret, token }) {
|
||||
return jwt.verify(token, secret)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions)
|
||||
```
|
||||
|
||||
And:
|
||||
|
||||
```ts title="middleware.ts"
|
||||
import withAuth from "next-auth/middleware"
|
||||
import { authOptions } from "pages/api/auth/[...nextauth]";
|
||||
|
||||
export default withAuth({
|
||||
jwt: { decode: authOptions.jwt },
|
||||
callbacks: {
|
||||
authorized: ({ token }) => !!token,
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Caveats
|
||||
|
||||
- Currently only supports session verification, as parts of the sign-in code need to run in a Node.js environment. In the future, we would like to make sure that NextAuth.js can fully run at the [Edge](https://nextjs.org/docs/api-reference/edge-runtime)
|
||||
|
||||
@@ -13,19 +13,22 @@ 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.
|
||||
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).
|
||||
|
||||
_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).
|
||||
:::
|
||||
|
||||
:::note
|
||||
Using [System Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables#system-environment-variables) we automatically detect when you deploy to [Vercel](https://vercel.com) so you don't have to define this variable. Make sure **Automatically expose System Environment Variables** is checked in your Project Settings.
|
||||
:::
|
||||
|
||||
### NEXTAUTH_SECRET
|
||||
|
||||
Used to encrypt the NextAuth.js JWT, and to hash [email verification tokens](/adapters/models#verification-token). This is the default value for the [`secret`](/configuration/options#secret) option. The `secret` option might be removed in the future in favor of this.
|
||||
Used to encrypt the NextAuth.js JWT, and to hash [email verification tokens](/adapters/models#verification-token). This is the default value for the `secret` option in [NextAuth](/configuration/options#secret) and [Middleware](/configuration/nextjs#secret).
|
||||
|
||||
If you are using [Middleware](/configuration/nextjs#prerequisites) this environment variables must be set.
|
||||
|
||||
### NEXTAUTH_URL_INTERNAL
|
||||
|
||||
@@ -65,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.
|
||||
@@ -226,6 +229,10 @@ pages: {
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
When using this configuration, ensure that these pages actually exist. For example `error: '/auth/error'` refers to a page file at `pages/auth/error.js`.
|
||||
:::
|
||||
|
||||
See the documentation for the [pages option](/configuration/pages) for more information.
|
||||
|
||||
---
|
||||
@@ -319,7 +326,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.
|
||||
|
||||
@@ -362,11 +369,14 @@ Changes the color scheme theme of [pages](/configuration/pages) as well as allow
|
||||
|
||||
In addition, you can define a logo URL in `theme.logo` which will be rendered above the main card in the default signin/signout/error/verify-request pages, as well as a `theme.brandColor` which will affect the accent color of these pages.
|
||||
|
||||
The sign-in button's background color will match the `brandColor` and defaults to `"#346df1"`. The text color is `#fff` by default, but if your brand color gives a weak contrast, correct it with the `buttonText` color option.
|
||||
|
||||
```js
|
||||
theme: {
|
||||
colorScheme: "auto", // "auto" | "dark" | "light"
|
||||
brandColor: "", // Hex color code
|
||||
logo: "" // Absolute URL to image
|
||||
logo: "", // Absolute URL to image
|
||||
buttonText: "" // Hex color code
|
||||
}
|
||||
```
|
||||
|
||||
@@ -468,6 +478,15 @@ cookies: {
|
||||
secure: useSecureCookies,
|
||||
},
|
||||
},
|
||||
nonce: {
|
||||
name: `${cookiePrefix}next-auth.nonce`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
secure: useSecureCookies,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -481,6 +500,8 @@ Using a custom cookie policy may introduce security flaws into your application
|
||||
|
||||
NextAuth.js uses encrypted JSON Web Tokens ([JWE](https://datatracker.ietf.org/doc/html/rfc7516)) by default. Unless you have a good reason, we recommend keeping this behaviour. Although you can override this using the `encode` and `decode` methods. Both methods must be defined at the same time.
|
||||
|
||||
**IMPORTANT: If you use middleware to protect routes, make sure the same method is also set in the [`_middleware.ts` options](/configuration/nextjs#custom-jwt-decode-method)**
|
||||
|
||||
```js
|
||||
jwt: {
|
||||
async encode(params: {
|
||||
|
||||
@@ -21,6 +21,10 @@ To add a custom login page, you can use the `pages` option:
|
||||
...
|
||||
```
|
||||
|
||||
:::note
|
||||
When using this configuration, ensure that these pages actually exist. For example `error: '/auth/error'` refers to a page file at `pages/auth/error.js`.
|
||||
:::
|
||||
|
||||
## Error codes
|
||||
|
||||
We purposefully restrict the returned error codes for increased security.
|
||||
|
||||
@@ -80,7 +80,7 @@ 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/"
|
||||
@@ -350,7 +350,7 @@ providers: [
|
||||
|
||||
## Built-in providers
|
||||
|
||||
NextAuth.js comes with a set of built-in providers. You can find them [here](https://github.com/nextauthjs/next-auth/tree/main/src/providers). Each built-in provider has its own documentation page:
|
||||
NextAuth.js comes with a set of built-in providers. You can find them [here](https://github.com/nextauthjs/next-auth/tree/main/packages/next-auth/src/providers). Each built-in provider has its own documentation page:
|
||||
|
||||
<div className="provider-name-list">
|
||||
{Object.entries(require("../../../providers.json"))
|
||||
|
||||
@@ -11,6 +11,7 @@ Without these people, the project could not have become one of the most used aut
|
||||
- [Balázs Orbán](https://github.com/balazsorban44) - **Lead Maintainer**
|
||||
- [Nico Domino](https://github.com/ndom91) - Maintainer (Documentation, Core)
|
||||
- [Lluis Agusti](https://github.com/lluia) - Maintainer (Documentation, Testing, TypeScript)
|
||||
- [Thang Huu Vu](https://github.com/ThangHuuVu) - Maintainer (Core, TypeScript)
|
||||
|
||||
## Special thanks
|
||||
|
||||
|
||||
@@ -85,6 +85,8 @@ Preview deployments at Vercel are often available via multiple URLs. For example
|
||||
|
||||
Netlify is very similar to Vercel in that you can deploy a Next.js project without almost any extra work.
|
||||
|
||||
In order to setup NextAuth.js correctly here, you will want to make sure you add your `NEXTAUTH_SECRET` and `NEXTAUTH_URL` environment variables in the project settings. Netlify also exposes some [system environment variables](https://docs.netlify.com/configure-builds/environment-variables/) from which you can check which `NODE_ENV` you are currently in and much more.
|
||||
In order to setup NextAuth.js correctly here, you will want to make sure you add your `NEXTAUTH_SECRET` environment variable in the project settings. If you are using the [Essential Next.js Build Plugin](https://github.com/netlify/netlify-plugin-nextjs) within your project, you **do not** need to set the `NEXTAUTH_URL` environment variable as it is set automatically as part of the build process.
|
||||
|
||||
Netlify also exposes some [system environment variables](https://docs.netlify.com/configure-builds/environment-variables/) from which you can check which `NODE_ENV` you are currently in and much more.
|
||||
|
||||
After this, just make sure you either have your OAuth provider setup correctly with `clientId` / `clientSecret`'s and callback URLs.
|
||||
|
||||
@@ -61,19 +61,26 @@ There should also be further details logged when this occurs, such as the error
|
||||
|
||||
### Signin / Callback
|
||||
|
||||
#### GET_AUTHORIZATION_URL_ERROR
|
||||
|
||||
This error can occur when we cannot get the OAuth v1 request token and generate the authorization URL.
|
||||
|
||||
Please double check your OAuth v1 provider settings, especially the OAuth token and OAuth token secret.
|
||||
|
||||
#### SIGNIN_OAUTH_ERROR
|
||||
|
||||
This error can occur in one of a few places, first during the redirect to the authorization URL of the provider. Next, in the signin flow while creating the PKCE code verifier. Finally, during the generation of the CSRF Token hash in the internal state during signin.
|
||||
This error occurs during the redirection to the authorization URL of the OAuth provider. Possible causes:
|
||||
|
||||
Please check your OAuth provider settings and make sure your URLs and other options are correctly set on the provider side.
|
||||
1. Cookie handling
|
||||
Either PKCE code verifier or the generation of the CSRF token hash in the internal state failed.
|
||||
|
||||
#### CALLBACK_OAUTH_ERROR
|
||||
If set, check your [`cookies` configuration](/configuration/options#cookies), and make sure the browser is not blocking/restricting cookies.
|
||||
|
||||
2. OAuth misconfiguration
|
||||
|
||||
Please check your OAuth provider and make sure your URLs and other options are correctly set.
|
||||
|
||||
If you are using an OAuth v1 provider, check your OAuth v1 provider settings, especially the OAuth token and OAuth token secret.
|
||||
|
||||
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.
|
||||
|
||||
@@ -99,7 +106,7 @@ This is required to store the verification token. Please see the [email provider
|
||||
|
||||
The Credentials Provider can only be used if JSON Web Tokens are used for sessions.
|
||||
|
||||
JSON Web Tokens are used for Sessions by default if you have not specified a database. However, if you are using a database, then Database Sessions are enabled by default and you need to [explicitly enable JWT Sessions](https://next-auth.js.org/configuration/options#session) to use the Credentials Provider.
|
||||
JSON Web Tokens are used for Sessions by default if you have not specified a database. However, if you are using a database, then Database Sessions are enabled by default and you need to [explicitly enable JWT Sessions](/configuration/options#session) to use the Credentials Provider.
|
||||
|
||||
If you are using a Credentials Provider, NextAuth.js will not persist users or sessions in a database - user accounts used with the Credentials Provider must be created and managed outside of NextAuth.js.
|
||||
|
||||
@@ -119,13 +126,17 @@ The default `code_challenge_method` is `"S256"`. This is currently not configura
|
||||
> If the client is capable of using "S256", it MUST use "S256", as
|
||||
S256" is Mandatory To Implement (MTI) on the server.
|
||||
|
||||
#### INVALID_CALLBACK_URL_ERROR
|
||||
|
||||
The `callbackUrl` provided was either invalid or not defined. See [specifying a `callbackUrl`](/getting-started/client#specifying-a-callbackurl) for more information.
|
||||
|
||||
---
|
||||
|
||||
### Session Handling
|
||||
|
||||
#### JWT_SESSION_ERROR
|
||||
|
||||
https://next-auth.js.org/errors#jwt_session_error JWKKeySupport: the key does not support HS512 verify algorithm
|
||||
JWKKeySupport: 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
|
||||
|
||||
@@ -145,13 +156,7 @@ This error occurs when there was an issue deleting the session from the database
|
||||
|
||||
---
|
||||
|
||||
### Other
|
||||
|
||||
#### SEND_VERIFICATION_EMAIL_ERROR
|
||||
|
||||
This error occurs when the Email Authentication Provider is unable to send an email.
|
||||
|
||||
Check your mail server configuration.
|
||||
### Configuration
|
||||
|
||||
#### MISSING_NEXTAUTH_API_ROUTE_ERROR
|
||||
|
||||
@@ -161,8 +166,20 @@ Make sure the file is there and the filename is written correctly.
|
||||
|
||||
#### NO_SECRET
|
||||
|
||||
In production, we expect you to define a `secret` property in your configuration. In development, this is shown as a warning for convenience. [Read more](https://next-auth.js.org/configuration/options#secret)
|
||||
In production, we expect you to define a `secret` property in your configuration. In development, this is shown as a warning for convenience. [Read more](/configuration/options#secret)
|
||||
|
||||
#### 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)
|
||||
#### AUTH_ON_ERROR_PAGE_ERROR
|
||||
|
||||
You have a custom error page defined that was rendered due to an error, but the page also required authentication. To avoid an infinite redirect loop, NextAuth.js bailed out and rendered its default error page instead.
|
||||
|
||||
If you are using a Middleware, make sure you include the same `pages` configuration in your `middleware.ts` and `[...nextauth].ts` files. Or use the `matcher` option to only require authentication for certain sites (and exclude your custom error page).
|
||||
|
||||
If you do not use a Middleware, make sure you don't try redirecting the user to the sign-in page when hitting your custom error page.
|
||||
|
||||
Useful links:
|
||||
|
||||
- https://next-auth.js.org/configuration/nextjs#pages
|
||||
- https://next-auth.js.org/configuration/pages
|
||||
- https://nextjs.org/docs/advanced-features/middleware#matcher
|
||||
|
||||
|
||||
@@ -63,17 +63,32 @@ _If you use a custom credentials provider user accounts will not be persisted in
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Can I use NextAuth.js with a website that does not use Next.js?</h3>
|
||||
<h3 style={{display:"inline-block"}}>Can I use NextAuth.js with a framework different than Next.js?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js is designed for use with Next.js and Serverless.
|
||||
NextAuth.js was originally designed for use with Next.js and Serverless. However, today you could use the NextAuth.js core with any other framework. Checkout the examples for <a href="https://github.com/nextauthjs/next-auth/tree/main/apps/example-gatsby" target="_blank">Gatsby</a> and <a href="https://github.com/nextauthjs/next-auth/tree/main/apps/playground-sveltekit" target="_blank">SvelteKit</a>. If you would add another integration with other frameworks, feel free to work on it and send a pull request. Make sure to check if there's any on-going work before open a new issue.
|
||||
|
||||
If you are using a different framework for your website, you can create a website that handles sign in with Next.js and then access those sessions on a website that does not use Next.js as long as the websites are on the same domain.
|
||||
</p>
|
||||
</details>
|
||||
|
||||
If you use NextAuth.js on a website with a different subdomain then the rest of your website (e.g. `auth.example.com` vs `www.example.com`) you will need to set a custom cookie domain policy for the Session Token cookie. (See also: [Cookies](/configuration/options#cookies))
|
||||
<details>
|
||||
<summary>
|
||||
<h3 style={{display:"inline-block"}}>Can session generated by NextAuth.js be used by another website?</h3>
|
||||
</summary>
|
||||
<p>
|
||||
|
||||
NextAuth.js does not currently support automatically signing into sites on different top level domains (e.g. `www.example.com` vs `www.example.org`) using a single session.
|
||||
**Same domain**: you can create a website that handles sign-in with NextAuth.js and then access those sessions on a website that does not use NextAuth.js as long as the websites are on the same domain.
|
||||
|
||||
**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 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>.
|
||||
|
||||
**Different root domains**: NextAuth.js does not currently support automatically signing into sites on different top-level domains (e.g. `www.example.com` vs. `www.example.org`) using a single session.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
@@ -221,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>
|
||||
|
||||
@@ -314,7 +333,7 @@ JSON Web Tokens can be used for session tokens, but are also used for lots of ot
|
||||
|
||||
Avoid storing any data in a token that might be problematic if it were to be decrypted in the future.
|
||||
|
||||
- If you do not explicitly specify a secret for for NextAuth.js, existing sessions will be invalidated any time your NextAuth.js configuration changes, as NextAuth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
|
||||
- If you do not explicitly specify a secret for NextAuth.js, existing sessions will be invalidated any time your NextAuth.js configuration changes, as NextAuth.js will default to an auto-generated secret. Since v4 this only impacts development and generating a secret is required in production.
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -126,15 +126,15 @@ function Auth({ children }) {
|
||||
// if `{ required: true }` is supplied, `status` can only be "loading" or "authenticated"
|
||||
const { status } = useSession({ required: true })
|
||||
|
||||
if (status === 'loading') {
|
||||
if (status === "loading") {
|
||||
return <div>Loading...</div>
|
||||
}
|
||||
|
||||
|
||||
return children
|
||||
}
|
||||
```
|
||||
|
||||
It can be easily be extended/modified to support something like an options object for role based authentication on pages. An example:
|
||||
It can be easily extended/modified to support something like an options object for role based authentication on pages. An example:
|
||||
|
||||
```jsx title="pages/admin.jsx"
|
||||
AdminDashboard.auth = {
|
||||
@@ -148,26 +148,28 @@ Because of how `_app` is written, it won't unnecessarily contact the `/api/auth/
|
||||
|
||||
More information can be found in the following [GitHub Issue](https://github.com/nextauthjs/next-auth/issues/1210).
|
||||
|
||||
### NextAuth.js + React-Query
|
||||
### NextAuth.js + React Query
|
||||
|
||||
There is also an alternative client-side API library based upon [`react-query`](https://www.npmjs.com/package/react-query) available under [`nextauthjs/react-query`](https://github.com/nextauthjs/react-query).
|
||||
|
||||
If you use `react-query` in your project already, you can leverage it with NextAuth.js to handle the client-side session management for you as well. This replaces NextAuth.js's native `useSession` and `SessionProvider` from `next-auth/react`.
|
||||
|
||||
See repository [`README`](https://github.com/nextauthjs/react-query) for more details.
|
||||
You can create your own session management solution using data fetching libraries like [React Query](https://tanstack.com/query/v4/docs/adapters/react-query) or [SWR](https://swr.vercel.app). You can use the [original implementation of `@next-auth/react-query`](https://github.com/nextauthjs/react-query) and look at the [`next-auth/react` source code](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/react/index.tsx) as a starting point.
|
||||
|
||||
---
|
||||
|
||||
## getSession()
|
||||
|
||||
- Client Side: **Yes**
|
||||
- Server Side: **Yes**
|
||||
- Server Side: **No** (See: [`unstable_getServerSession()`](/configuration/nextjs#unstable_getserversession)
|
||||
|
||||
NextAuth.js provides a `getSession()` method which can be called client or server side to return a session.
|
||||
NextAuth.js provides a `getSession()` helper which should be called **client side only** to return the current active session.
|
||||
|
||||
It calls `/api/auth/session` and returns a promise with a session object, or null if no session exists.
|
||||
On the server side, **this is still available to use**, however, we recommend using `unstable_getServerSession` going forward. The idea behind this is to avoid an additional unnecessary `fetch` call on the server side. For more information, please check out [this issue](https://github.com/nextauthjs/next-auth/issues/1535).
|
||||
|
||||
#### Client Side Example
|
||||
:::note
|
||||
The `unstable_getServerSession` only has the prefix `unstable_` at the moment, because the API may change in the future. There are no known bugs at the moment and it is safe to use. If you discover any issues, please do report them as a [GitHub Issue](https://github.com/nextauthjs/next-auth/issues) and we will patch them as soon as possible.
|
||||
:::
|
||||
|
||||
This helper is helpful in case you want to read the session outside of the context of React.
|
||||
|
||||
When called, `getSession()` will send a request to `/api/auth/session` and returns a promise with a [session object](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/core/types.ts#L407-L425), or `null` if no session exists.
|
||||
|
||||
```js
|
||||
async function myFunction() {
|
||||
@@ -176,23 +178,7 @@ async function myFunction() {
|
||||
}
|
||||
```
|
||||
|
||||
#### Server Side Example
|
||||
|
||||
```js
|
||||
import { getSession } from "next-auth/react"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getSession({ req })
|
||||
/* ... */
|
||||
res.end()
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
When calling `getSession()` server side, you need to pass `{req}` or `context` object.
|
||||
:::
|
||||
|
||||
The tutorial [securing pages and API routes](/tutorials/securing-pages-and-api-routes) shows how to use `getSession()` in server side calls.
|
||||
Read the tutorial [securing pages and API routes](/tutorials/securing-pages-and-api-routes) to know how to fetch the session in server side calls using `unstable_getServerSession()`.
|
||||
|
||||
---
|
||||
|
||||
@@ -254,7 +240,7 @@ export default async (req, res) => {
|
||||
```
|
||||
|
||||
:::note
|
||||
Unlike `getSession()` and `getCsrfToken()`, when calling `getProviders()` server side, you don't need to pass anything, just as calling it client side.
|
||||
Unlike and `getCsrfToken()`, when calling `getProviders()` server side, you don't need to pass anything, just as calling it client side.
|
||||
:::
|
||||
|
||||
---
|
||||
@@ -436,14 +422,15 @@ If you pass the `session` page prop to the `<SessionProvider>` – as in the exa
|
||||
This only works on pages where you provide the correct `pageProps`, however. This is normally done in `getInitialProps` or `getServerSideProps` on an individual page basis like so:
|
||||
|
||||
```js title="pages/index.js"
|
||||
import { getSession } from "next-auth/react"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from './api/auth/[...nextauth]'
|
||||
|
||||
...
|
||||
|
||||
export async function getServerSideProps(ctx) {
|
||||
export async function getServerSideProps({ req, res }) {
|
||||
return {
|
||||
props: {
|
||||
session: await getSession(ctx)
|
||||
session: await unstable_getServerSession(req, res, authOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,7 +442,7 @@ If every one of your pages needs to be protected, you can do this in `getInitial
|
||||
|
||||
The session state is automatically synchronized across all open tabs/windows and they are all updated whenever they gain or lose focus or the state changes (e.g. a user signs in or out) when `refetchOnWindowFocus` is `true`.
|
||||
|
||||
If you have session expiry times of 30 days (the default) or more then you probably don't need to change any of the default options in the Provider. If you need to, you can trigger an update of the session object across all tabs/windows by calling `getSession()` from a client side function.
|
||||
If you have session expiry times of 30 days (the default) or more then you probably don't need to change any of the default options in the Provider. If you need to, you can trigger an update of the session object across all tabs/windows by calling [`getSession()`](/getting-started/client#getsession) from a client side function.
|
||||
|
||||
However, if you need to customize the session behavior and/or are using short session expiry times, you can pass options to the provider to customize the behavior of the `useSession()` hook.
|
||||
|
||||
@@ -515,3 +502,29 @@ However, if it was set to `false`, it stops re-fetching the session and the comp
|
||||
:::note
|
||||
See [**the Next.js documentation**](https://nextjs.org/docs/advanced-features/custom-app) for more information on **\_app.js** in Next.js applications.
|
||||
:::
|
||||
|
||||
### Custom base path
|
||||
When your Next.js application uses a custom base path, set the `NEXTAUTH_URL` environment variable to the route to the API endpoint in full - as in the example below and as explained [here](/configuration/options#nextauth_url).
|
||||
|
||||
Also, make sure to pass the `basePath` page prop to the `<SessionProvider>` – as in the example below – so your custom base path is fully configured and used by NextAuth.js.
|
||||
|
||||
#### Example
|
||||
In this example, the custom base path used is `/custom-route`.
|
||||
|
||||
```
|
||||
NEXTAUTH_URL=https://example.com/custom-route/api/auth
|
||||
```
|
||||
|
||||
```jsx title="pages/_app.js"
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
export default function App({
|
||||
Component,
|
||||
pageProps: { session, ...pageProps },
|
||||
}) {
|
||||
return (
|
||||
<SessionProvider session={session} basePath="/custom-route/api/auth">
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -11,15 +11,26 @@ 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.
|
||||
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
```javascript title="pages/api/auth/[...nextauth].js" showLineNumbers
|
||||
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.
|
||||
@@ -42,8 +55,7 @@ All requests to `/api/auth/*` (`signIn`, `callback`, `signOut`, etc.) will autom
|
||||
|
||||
To be able to use `useSession` first you'll need to expose the session context, [`<SessionProvider />`](/getting-started/client#sessionprovider), at the top level of your application:
|
||||
|
||||
```javascript
|
||||
// pages/_app.js
|
||||
```jsx title="pages/_app.jsx" showLineNumbers
|
||||
import { SessionProvider } from "next-auth/react"
|
||||
|
||||
export default function App({
|
||||
@@ -68,7 +80,7 @@ Check out the [client documentation](/getting-started/client) to see how you can
|
||||
|
||||
The [`useSession()`](/getting-started/client#usesession) React Hook in the NextAuth.js client is the easiest way to check if someone is signed in.
|
||||
|
||||
```javascript
|
||||
```jsx title="components/login-btn.jsx" showLineNumbers
|
||||
import { useSession, signIn, signOut } from "next-auth/react"
|
||||
|
||||
export default function Component() {
|
||||
@@ -94,13 +106,14 @@ You can use the `useSession` hook from anywhere in your application (e.g. in a h
|
||||
|
||||
### Backend - API Route
|
||||
|
||||
To protect an API Route, you can use the [`getSession()`](/getting-started/client#getsession) method in the NextAuth.js client.
|
||||
To protect an API Route, you can use the [`unstable_getServerSession()`](/configuration/nextjs#unstable_getserversession) method.
|
||||
|
||||
```javascript
|
||||
import { getSession } from "next-auth/react"
|
||||
```javascript title="pages/api/restricted.js" showLineNumbers
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./auth/[...nextauth]"
|
||||
|
||||
export default async (req, res) => {
|
||||
const session = await getSession({ req })
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (session) {
|
||||
res.send({
|
||||
@@ -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.",
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -123,18 +136,20 @@ NextAuth.js allows you to hook into various parts of the authentication flow via
|
||||
|
||||
For example, to pass a value from the sign-in to the frontend, client-side, you can use a combination of the [`session`](/configuration/callbacks#session-callback) and [`jwt`](/configuration/callbacks#jwt-callback) callback like so:
|
||||
|
||||
```javascript
|
||||
```javascript title="pages/api/auth/[...nextauth].js"
|
||||
...
|
||||
callbacks: {
|
||||
async jwt({ token, account }) {
|
||||
// Persist the OAuth access_token to the token right after signin
|
||||
if (account) {
|
||||
// highlight-next-line
|
||||
token.accessToken = account.access_token
|
||||
}
|
||||
return token
|
||||
},
|
||||
async session({ session, token, user }) {
|
||||
// Send properties to the client, like an access_token from a provider.
|
||||
// highlight-next-line
|
||||
session.accessToken = token.accessToken
|
||||
return session
|
||||
}
|
||||
@@ -142,12 +157,13 @@ callbacks: {
|
||||
...
|
||||
```
|
||||
|
||||
Now whenever you call `getSession` or `useSession`, the data object which is returned will include the `accessToken` value.
|
||||
Now whenever you call [`getSession`](/getting-started/client#getsession) or [`useSession`](/getting-started/client#usesession), the data object which is returned will include the `accessToken` value.
|
||||
|
||||
```js
|
||||
```jsx title="components/accessToken.jsx" showLineNumbers
|
||||
import { useSession, signIn, signOut } from "next-auth/react"
|
||||
|
||||
export default function Component() {
|
||||
// highlight-next-line
|
||||
const { data } = useSession()
|
||||
const { accessToken } = data
|
||||
|
||||
@@ -158,7 +174,7 @@ export default function Component() {
|
||||
## Configuring callback URL (OAuth only)
|
||||
|
||||
If you are using an OAuth provider either through one of our [built-in providers](/configuration/providers/oauth)
|
||||
or through a [custom provider](/configuration/providers/oauth#using-a-custom-provider), you'll need to configure
|
||||
or through a [custom provider](/configuration/providers/oauth#using-a-custom-provider), you'll need to configure
|
||||
a callback URL in your provider's settings. Each provider has a "Configuration" section that should give you pointers on how to do that.
|
||||
|
||||
Follow [these steps](/configuration/providers/oauth#how-to) to learn how to integrate with an OAuth provider.
|
||||
|
||||
@@ -13,7 +13,7 @@ We encourage users to try it out and report any and all issues they come across.
|
||||
|
||||
You can upgrade to the new version by running:
|
||||
|
||||
```bash npm2yarn
|
||||
```bash npm2yarn2pnpm
|
||||
npm install next-auth
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -28,3 +28,7 @@ title: Fullstack
|
||||
### [Creating a database adapter](/tutorials/creating-a-database-adapter)
|
||||
|
||||
- How to create a custom adapter, to use any database to fetch and store user / account data.
|
||||
|
||||
### [Adding role based login to database session strategy](/tutorials/role-based-login-strategy)
|
||||
|
||||
- Implement a role based login system by adding a custom session callback.
|
||||
|
||||
17
docs/docs/guides/index.md
Normal file
17
docs/docs/guides/index.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
id: guides
|
||||
title: Guides
|
||||
---
|
||||
|
||||
# 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}/>
|
||||
```
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
})
|
||||
]
|
||||
...
|
||||
|
||||
@@ -31,5 +31,5 @@ providers: [
|
||||
```
|
||||
|
||||
:::note
|
||||
`issuer` should include the slug – e.g. `https://my-authentik-domain.com/application/o/My_Slug/`
|
||||
`issuer` should include the slug without a trailing slash – e.g., `https://my-authentik-domain.com/application/o/My_Slug`
|
||||
:::
|
||||
|
||||
@@ -71,7 +71,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";
|
||||
@@ -124,67 +124,74 @@ providers: [
|
||||
The following code shows the complete source for the built-in `sendVerificationRequest()` method:
|
||||
|
||||
```js
|
||||
import nodemailer from "nodemailer"
|
||||
import { createTransport } from "nodemailer"
|
||||
|
||||
async function sendVerificationRequest({
|
||||
identifier: email,
|
||||
url,
|
||||
provider: { server, from },
|
||||
}) {
|
||||
async function sendVerificationRequest(params) {
|
||||
const { identifier, url, provider, theme } = params
|
||||
const { host } = new URL(url)
|
||||
const transport = nodemailer.createTransport(server)
|
||||
await transport.sendMail({
|
||||
to: email,
|
||||
from,
|
||||
// NOTE: You are not required to use `nodemailer`, use whatever you want.
|
||||
const transport = createTransport(provider.server)
|
||||
const result = await transport.sendMail({
|
||||
to: identifier,
|
||||
from: provider.from,
|
||||
subject: `Sign in to ${host}`,
|
||||
text: text({ url, host }),
|
||||
html: html({ url, host, email }),
|
||||
html: html({ url, host, theme }),
|
||||
})
|
||||
const failed = result.rejected.concat(result.pending).filter(Boolean)
|
||||
if (failed.length) {
|
||||
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`)
|
||||
}
|
||||
}
|
||||
|
||||
// Email HTML body
|
||||
function html({ url, host, email }: Record<"url" | "host" | "email", string>) {
|
||||
// Insert invisible space into domains and email address to prevent both the
|
||||
// email address and the domain from being turned into a hyperlink by email
|
||||
// clients like Outlook and Apple mail, as this is confusing because it seems
|
||||
// like they are supposed to click on their email address to sign in.
|
||||
const escapedEmail = `${email.replace(/\./g, "​.")}`
|
||||
const escapedHost = `${host.replace(/\./g, "​.")}`
|
||||
/**
|
||||
* Email HTML body
|
||||
* Insert invisible space into domains from being turned into a hyperlink by email
|
||||
* clients like Outlook and Apple mail, as this is confusing because it seems
|
||||
* like they are supposed to click on it to sign in.
|
||||
*
|
||||
* @note We don't add the email address to avoid needing to escape it, if you do, remember to sanitize it!
|
||||
*/
|
||||
function html(params: { url: string; host: string; theme: Theme }) {
|
||||
const { url, host, theme } = params
|
||||
|
||||
// Some simple styling options
|
||||
const backgroundColor = "#f9f9f9"
|
||||
const textColor = "#444444"
|
||||
const mainBackgroundColor = "#ffffff"
|
||||
const buttonBackgroundColor = "#346df1"
|
||||
const buttonBorderColor = "#346df1"
|
||||
const buttonTextColor = "#ffffff"
|
||||
const escapedHost = host.replace(/\./g, "​.")
|
||||
|
||||
const brandColor = theme.brandColor || "#346df1"
|
||||
const color = {
|
||||
background: "#f9f9f9",
|
||||
text: "#444",
|
||||
mainBackground: "#fff",
|
||||
buttonBackground: brandColor,
|
||||
buttonBorder: brandColor,
|
||||
buttonText: theme.buttonText || "#fff",
|
||||
}
|
||||
|
||||
return `
|
||||
<body style="background: ${backgroundColor};">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<body style="background: ${color.background};">
|
||||
<table width="100%" border="0" cellspacing="20" cellpadding="0"
|
||||
style="background: ${color.mainBackground}; max-width: 600px; margin: auto; border-radius: 10px;">
|
||||
<tr>
|
||||
<td align="center" style="padding: 10px 0px 20px 0px; font-size: 22px; font-family: Helvetica, Arial, sans-serif; color: ${textColor};">
|
||||
<strong>${escapedHost}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table width="100%" border="0" cellspacing="20" cellpadding="0" style="background: ${mainBackgroundColor}; max-width: 600px; margin: auto; border-radius: 10px;">
|
||||
<tr>
|
||||
<td align="center" style="padding: 10px 0px 0px 0px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; color: ${textColor};">
|
||||
Sign in as <strong>${escapedEmail}</strong>
|
||||
<td align="center"
|
||||
style="padding: 10px 0px; font-size: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
|
||||
Sign in to <strong>${escapedHost}</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding: 20px 0;">
|
||||
<table border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td align="center" style="border-radius: 5px;" bgcolor="${buttonBackgroundColor}"><a href="${url}" target="_blank" style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; color: ${buttonTextColor}; text-decoration: none; border-radius: 5px; padding: 10px 20px; border: 1px solid ${buttonBorderColor}; display: inline-block; font-weight: bold;">Sign in</a></td>
|
||||
<td align="center" style="border-radius: 5px;" bgcolor="${color.buttonBackground}"><a href="${url}"
|
||||
target="_blank"
|
||||
style="font-size: 18px; font-family: Helvetica, Arial, sans-serif; color: ${color.buttonText}; text-decoration: none; border-radius: 5px; padding: 10px 20px; border: 1px solid ${color.buttonBorder}; display: inline-block; font-weight: bold;">Sign
|
||||
in</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding: 0px 0px 10px 0px; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: ${textColor};">
|
||||
<td align="center"
|
||||
style="padding: 0px 0px 10px 0px; font-size: 16px; line-height: 22px; font-family: Helvetica, Arial, sans-serif; color: ${color.text};">
|
||||
If you did not request this email you can safely ignore it.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -193,8 +200,8 @@ function html({ url, host, email }: Record<"url" | "host" | "email", string>) {
|
||||
`
|
||||
}
|
||||
|
||||
// Email Text body (fallback for email clients that don't render HTML, e.g. feature phones)
|
||||
function text({ url, host }: Record<"url" | "host", string>) {
|
||||
/** Email Text body (fallback for email clients that don't render HTML, e.g. feature phones) */
|
||||
function text({ url, host }: { url: string; host: string }) {
|
||||
return `Sign in to ${host}\n${url}\n\n`
|
||||
}
|
||||
```
|
||||
@@ -216,3 +223,31 @@ providers: [
|
||||
})
|
||||
],
|
||||
```
|
||||
|
||||
## Normalizing the email address
|
||||
|
||||
By default, NextAuth.js will normalize the email address. It treats values as case-insensitive (which is technically not compliant to the [RFC 2821 spec](https://datatracker.ietf.org/doc/html/rfc2821), but in practice this causes more problems than it solves, eg. when looking up users by e-mail from databases.) and also removes any secondary email address that was passed in as a comma-separated list. You can apply your own normalization via the `normalizeIdentifier` method on the `EmailProvider`. The following example shows the default behavior:
|
||||
```ts
|
||||
EmailProvider({
|
||||
// ...
|
||||
normalizeIdentifier(identifier: string): string {
|
||||
// Get the first two elements only,
|
||||
// separated by `@` from user input.
|
||||
let [local, domain] = identifier.toLowerCase().trim().split("@")
|
||||
// The part before "@" can contain a ","
|
||||
// but we remove it on the domain part
|
||||
domain = domain.split(",")[0]
|
||||
return `${local}@${domain}`
|
||||
|
||||
// You can also throw an error, which will redirect the user
|
||||
// to the error page with error=EmailSignin in the URL
|
||||
// if (identifier.split("@").length > 2) {
|
||||
// throw new Error("Only one email allowed")
|
||||
// }
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
:::warning
|
||||
Always make sure this returns a single e-mail address, even if multiple ones were passed in.
|
||||
:::
|
||||
@@ -19,7 +19,7 @@ https://github.com/settings/apps
|
||||
|
||||
The **GitHub Provider** comes with a set of default options:
|
||||
|
||||
- [GitHub Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/github.js)
|
||||
- [GitHub Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/github.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
@@ -30,8 +30,8 @@ import GitHubProvider from "next-auth/providers/github";
|
||||
...
|
||||
providers: [
|
||||
GitHubProvider({
|
||||
clientId: process.env.GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET
|
||||
clientId: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET
|
||||
})
|
||||
]
|
||||
...
|
||||
|
||||
@@ -15,7 +15,7 @@ https://gitlab.com/-/profile/applications
|
||||
|
||||
The **Gitlab Provider** comes with a set of default options:
|
||||
|
||||
- [Gitlab Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/gitlab.js)
|
||||
- [Gitlab Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/gitlab.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
|
||||
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.
|
||||
:::
|
||||
|
||||
@@ -5,7 +5,7 @@ title: Overview
|
||||
|
||||
Authentication Providers in **NextAuth.js** are services that can be used to sign in a user.
|
||||
|
||||
There's four ways a user can be signed in:
|
||||
There are four ways a user can be signed in:
|
||||
|
||||
- [Using a built-in OAuth Provider](/configuration/providers/oauth) (e.g Github, Twitter, Google, etc...)
|
||||
- [Using a custom OAuth Provider](/configuration/providers/oauth#using-a-custom-provider)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -46,27 +53,15 @@ This Provider template only has a one hour access token to it and only has the "
|
||||
|
||||
```js
|
||||
providers: [
|
||||
{
|
||||
id: "reddit",
|
||||
name: "Reddit",
|
||||
RedditProvider({
|
||||
clientId: process.env.REDDIT_CLIENT_ID,
|
||||
clientSecret: process.env.REDDIT_CLIENT_SECRET,
|
||||
scope: "identity mysubreddits read", //Check Reddit API Documentation for more. The identity scope is required.
|
||||
type: "oauth",
|
||||
version: "2.0",
|
||||
params: { grant_type: "authorization_code" },
|
||||
accessTokenUrl: " https://www.reddit.com/api/v1/access_token",
|
||||
authorizationUrl:
|
||||
"https://www.reddit.com/api/v1/authorize?response_type=code&duration=permanent",
|
||||
profileUrl: "https://oauth.reddit.com/api/v1/me",
|
||||
profile: (profile) => {
|
||||
return {
|
||||
id: profile.id,
|
||||
name: profile.name,
|
||||
email: null,
|
||||
}
|
||||
authorization: {
|
||||
params: {
|
||||
duration: 'permanent',
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ https://api.slack.com/docs/sign-in-with-slack
|
||||
https://api.slack.com/apps
|
||||
|
||||
:::warning
|
||||
Slack requires you that the redirect URL of your app uses `https`, even for local development. An easy workaround for this is using a service like [`ngrok`](https://ngrok.com) that creates a secure tunnel to your app, using `https`. Remember to set the url as `NEXTAUTH_URL` as well.
|
||||
Slack requires that the redirect URL of your app uses `https`, even for local development. An easy workaround for this is using a service like [`ngrok`](https://ngrok.com) that creates a secure tunnel to your app, using `https`. Remember to set the url as `NEXTAUTH_URL` as well.
|
||||
:::
|
||||
|
||||

|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ providers: [
|
||||
You must enable the _"Request email address from users"_ option in your app permissions if you want to obtain the users email address.
|
||||
:::
|
||||
|
||||

|
||||

|
||||
|
||||
## OAuth 2
|
||||
## OAuth 2.0
|
||||
|
||||
Twitter supports OAuth 2, which is currently opt-in. To enable it, simply add `version: "2.0"` to your Provider configuration:
|
||||
|
||||
@@ -56,3 +56,7 @@ TwitterProvider({
|
||||
```
|
||||
|
||||
Keep in mind that although this change is easy, it changes how and with which of [Twitter APIs](https://developer.twitter.com/en/docs/api-reference-index) you can interact with. Read the official [Twitter OAuth 2 documentation](https://developer.twitter.com/en/docs/authentication/oauth-2-0) for more details.
|
||||
|
||||
:::note
|
||||
Email is currently not supported by Twitter OAuth 2.0.
|
||||
:::
|
||||
|
||||
43
docs/docs/providers/united-effects.md
Normal file
43
docs/docs/providers/united-effects.md
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
id: united-effects
|
||||
title: United Effects
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
https://docs.unitedeffects.com/integrations/nextauthjs
|
||||
|
||||
## Configuration
|
||||
|
||||
https://core.unitedeffects.com
|
||||
|
||||
## Options
|
||||
|
||||
The **United Effects Provider** comes with a set of default options:
|
||||
|
||||
- [United Effects Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/united-effects.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import UnitedEffectsProvider from "next-auth/providers/united-effects";
|
||||
...
|
||||
providers: [
|
||||
UnitedEffectsProvider({
|
||||
clientId: process.env.UNITED_EFFECTS_CLIENT_ID,
|
||||
clientSecret: process.env.UNITED_EFFECTS_CLIENT_SECRET,
|
||||
issuer: process.env.UNITED_EFFECTS_ISSUER
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
:::note
|
||||
`issuer` should be the fully qualified URL including your Auth Group ID – e.g. `https://auth.unitedeffects.com/YQpbQV5dbW-224dCovz-3`
|
||||
:::
|
||||
|
||||
:::warning
|
||||
The United Effects API does not return the user name or image by design, so this provider will return null for both. United Effects prioritizes user personal information security above all and has built a secured profile access request system separate from the provider API.
|
||||
:::
|
||||
50
docs/docs/providers/wikimedia.md
Normal file
50
docs/docs/providers/wikimedia.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: wikimedia
|
||||
title: Wikimedia
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
https://www.mediawiki.org/wiki/Extension:OAuth
|
||||
|
||||
This provider also supports all Wikimedia projects:
|
||||
|
||||
- Wikipedia
|
||||
- Wikidata
|
||||
- Wikibooks
|
||||
- Wiktionary
|
||||
- etc..
|
||||
|
||||
Please be aware that Wikimedia accounts do not have to have an associated email address. So you may want to add check if the user has an email address before allowing them to login.
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Go to and accept the Consumer Registration doc: https://meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration
|
||||
2. Request a new OAuth 2.0 consumer to get the `clientId` and `clientSecret`: https://meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration/propose/oauth2
|
||||
2a. Add the following redirect URL into the console `http://<your-next-app-url>/api/auth/callback/wikimedia`
|
||||
2b. Do not check the box next to `This consumer is only for [your username]`
|
||||
2c. Unless you explicitly need a larger scope, feel free to select the radio button labelled `User identity verification only - no ability to read pages or act on the users behalf.`
|
||||
|
||||
After registration, you can initally test your application only with your own Wikimedia account. You may have to wait several days for the application to be approved for it to be used by everyone.
|
||||
|
||||
## Options
|
||||
|
||||
The **Wikimedia Provider** comes with a set of default options:
|
||||
|
||||
- [Wikimedia Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/wikimedia.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import WikimediaProvider from "next-auth/providers/wikimedia";
|
||||
...
|
||||
providers: [
|
||||
WikimediaProvider({
|
||||
clientId: process.env.WIKIMEDIA_CLIENT_ID,
|
||||
clientSecret: process.env.WIKIMEDIA_CLIENT_SECRET
|
||||
})
|
||||
]
|
||||
...
|
||||
```
|
||||
@@ -15,7 +15,7 @@ https://dashboard.workos.com
|
||||
|
||||
The **WorkOS Provider** comes with a set of default options:
|
||||
|
||||
- [WorkOS Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/workos.js)
|
||||
- [WorkOS Provider options](https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/providers/workos.ts)
|
||||
|
||||
You can override any of the options to suit your own use case.
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { CustomSandpack } from "../src/components/Sandpack"
|
||||
|
||||
<CustomSandpack />
|
||||
@@ -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 or me@iaincollins.com and yo@ndo.dev, or raise a public issue requesting someone get in touch with you via whatever means you prefer for more details. (Please do not disclose sensitive details publicly at this stage.)
|
||||
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.)
|
||||
|
||||
:::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.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user