mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
54 Commits
next-auth@
...
feat/oauth
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f48e0f1e2d | ||
|
|
2eef2f85d5 | ||
|
|
bf31512071 | ||
|
|
7cf49566a6 | ||
|
|
2469e44572 | ||
|
|
408b6b175f | ||
|
|
92dfc3c8b0 | ||
|
|
8c5d9faad6 | ||
|
|
49a8d51f79 | ||
|
|
c0d251731d | ||
|
|
76560aed5a | ||
|
|
25517b7315 | ||
|
|
acc9966285 | ||
|
|
6dd44000d7 | ||
|
|
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 | ||
|
|
2267292f5f | ||
|
|
883b36e2b2 | ||
|
|
029edb93ee | ||
|
|
ebcc3280df | ||
|
|
70a16e82c3 | ||
|
|
1365211a4e | ||
|
|
6df5773220 | ||
|
|
e3e3cf12d1 |
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)
|
||||
|
||||
69
.github/workflows/release.yml
vendored
69
.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: 6.32.8
|
||||
- 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,27 +52,22 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
with:
|
||||
version: 6.32.8
|
||||
- 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 }}
|
||||
NPM_TOKEN_PKG: ${{ secrets.NPM_TOKEN_PKG }}
|
||||
@@ -89,22 +81,17 @@ jobs:
|
||||
steps:
|
||||
- name: Init
|
||||
uses: actions/checkout@v2
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v2.2.1
|
||||
with:
|
||||
version: 6.32.8
|
||||
- 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,9 +101,9 @@ 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:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,6 +12,7 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
firebase-debug.log
|
||||
.pnpm-debug.log
|
||||
|
||||
|
||||
# Dependencies
|
||||
@@ -29,7 +30,7 @@ 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
|
||||
|
||||
@@ -6,19 +6,20 @@
|
||||
"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",
|
||||
"watch:css": "cd ../../packages/next-auth && pnpm watch:css",
|
||||
"dev": "concurrently \"pnpm dev:next\" \"pnpm watch:css\" \"pnpm copy:css\"",
|
||||
"dev:next": "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",
|
||||
"cpx": "^1.5.0",
|
||||
"fake-smtp-server": "^0.8.0",
|
||||
"faunadb": "^4.4.1",
|
||||
"next": "^12.1.0",
|
||||
@@ -29,6 +30,7 @@
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"concurrently": "^7.1.0",
|
||||
"prisma": "^3.10.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"cookie": "0.4.1",
|
||||
"next-auth": "^4.3.2"
|
||||
"next-auth": "^4.3.3"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
|
||||
@@ -65,7 +65,7 @@ async function SKNextAuthHandler(
|
||||
query: Object.fromEntries(url.searchParams),
|
||||
headers: request.headers,
|
||||
method: request.method,
|
||||
cookies: cookie.parse(request.headers.get("cookie")),
|
||||
cookies: cookie.parse(request.headers.get("cookie") ?? ""),
|
||||
action: nextauth[0] as NextAuthAction,
|
||||
providerId: nextauth[1],
|
||||
error: nextauth[1],
|
||||
@@ -91,7 +91,7 @@ export async function getServerSession(
|
||||
host: import.meta.env.VITE_NEXTAUTH_URL,
|
||||
action: "session",
|
||||
method: "GET",
|
||||
cookies: cookie.parse(request.headers.get("cookie")),
|
||||
cookies: cookie.parse(request.headers.get("cookie") ?? ""),
|
||||
headers: request.headers,
|
||||
},
|
||||
options,
|
||||
|
||||
@@ -1232,10 +1232,10 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
next-auth@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.3.2.tgz#eb4976511fb19766d0397bd4de45eee87c5c1998"
|
||||
integrity sha512-yj9HN9p81Fg3dkrq4Y0FxjfgupiABac7o+ve47j5GPLjo1qE2FFX1pr7g7mwQ1HDUCoGhLmgBpFBR8+pdWgFfQ==
|
||||
next-auth@^4.3.3:
|
||||
version "4.3.3"
|
||||
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.3.3.tgz#5ff892e73648a0f33c2af0e9d7cafda729f63ae7"
|
||||
integrity sha512-bUs+oOOPT18Pq/+4v9q4PA/DGoVoAX6jwY7RTfE/akFXwlny+y/mNS6lPSUwpqcHjljqBaq34PQA3+01SdOOPw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@panva/hkdf" "^1.0.1"
|
||||
|
||||
@@ -16,16 +16,53 @@ You must set the [`NEXTAUTH_SECRET`](/configuration/options#nextauth_secret) env
|
||||
|
||||
**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.
|
||||
|
||||
---
|
||||
|
||||
### Basic usage
|
||||
```js
|
||||
import withAuth from "next-auth/middleware"
|
||||
// or
|
||||
import { withAuth } from "next-auth/middleware"
|
||||
```
|
||||
|
||||
---
|
||||
### Custom JWT decode method
|
||||
|
||||
If you have 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.
|
||||
|
||||
`[...nextauth].ts`
|
||||
```ts
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
export default NextAuth({
|
||||
providers: [...],
|
||||
secret: /* Please use `process.env.NEXTAUTH_SECRET` */,
|
||||
jwt: {
|
||||
encode: async ({ secret, token }) => {
|
||||
return jwt.sign(token as any, secret);
|
||||
},
|
||||
decode: async ({ secret, token }) => {
|
||||
return jwt.verify(token as string, secret) as any;
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Any `_middleware.ts`
|
||||
```ts
|
||||
import withAuth from "next-auth/middleware"
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
export default withAuth({
|
||||
jwt: {
|
||||
decode: async ({ secret, token }) => {
|
||||
return jwt.verify(token, secret) as any;
|
||||
},
|
||||
},
|
||||
callbacks: {
|
||||
authorized: ({ token }) => !!token,
|
||||
},
|
||||
})
|
||||
```
|
||||
---
|
||||
### `callbacks`
|
||||
|
||||
- **Required:** No
|
||||
|
||||
@@ -25,7 +25,7 @@ Using [System Environment Variables](https://vercel.com/docs/concepts/projects/e
|
||||
|
||||
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.
|
||||
|
||||
If you are using [Middleware](/configuration/nextjs#prerequisites) this environment variables must be set.
|
||||
If you are using [Middleware](/configuration/nextjs#prerequisites) this environment variable must be set.
|
||||
|
||||
### NEXTAUTH_URL_INTERNAL
|
||||
|
||||
@@ -226,6 +226,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.
|
||||
|
||||
---
|
||||
@@ -481,6 +485,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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -99,7 +99,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 +119,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
|
||||
|
||||
@@ -161,7 +165,7 @@ 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
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ function Auth({ 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 = {
|
||||
|
||||
@@ -15,7 +15,7 @@ The easiest way to get started is to clone the [example app](https://github.com/
|
||||
|
||||
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"
|
||||
|
||||
@@ -42,8 +42,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 +67,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() {
|
||||
@@ -96,7 +95,7 @@ You can use the `useSession` hook from anywhere in your application (e.g. in a h
|
||||
|
||||
To protect an API Route, you can use the [`getSession()`](/getting-started/client#getsession) method in the NextAuth.js client.
|
||||
|
||||
```javascript
|
||||
```javascript title="pages/api/restricted.js" showLineNumbers
|
||||
import { getSession } from "next-auth/react"
|
||||
|
||||
export default async (req, res) => {
|
||||
@@ -123,18 +122,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
|
||||
}
|
||||
@@ -144,10 +145,11 @@ callbacks: {
|
||||
|
||||
Now whenever you call `getSession` or `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 +160,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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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`
|
||||
:::
|
||||
|
||||
@@ -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.
|
||||
:::
|
||||
@@ -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 />
|
||||
@@ -13,7 +13,7 @@ title: Tutorials and Explainers
|
||||
|
||||
- This is an introductory video to NextAuth.js for beginners. In this video, it is explained how to set up authentication in a few easy steps and add different configurations to make it more robust and secure.
|
||||
|
||||
#### [Authentication patterns for Next.js](https://leerob.io/blog/nextjs-authentication) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
|
||||
#### [Authentication patterns for Next.js](https://nextjs.org/docs/authentication) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
|
||||
|
||||
- Next.js supports multiple patterns for authentication, each designed for different use cases. This guide will allow you to choose your adventure based on your constraints. By Lee Robinson.
|
||||
|
||||
@@ -50,14 +50,14 @@ title: Tutorials and Explainers
|
||||
|
||||
#### [Build a FullStack App with Next.js, NextAuth.js, Supabase & Prisma](https://themodern.dev/courses/build-a-fullstack-app-with-nextjs-supabase-and-prisma-322389284337222224) <svg xmlns="http://www.w3.org/2000/svg" style={{ marginLeft: '5px', marginBottom:'-6px'}} height="20" width="20" fill="none" viewBox="0 0 24 24" stroke="currentColor"><title>External</title> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </svg>
|
||||
|
||||
In this [free course](https://themodern.dev/courses/build-a-fullstack-app-with-nextjs-supabase-and-prisma-322389284337222224), you'll learn how to build a full-stack app using the following technologies:
|
||||
In this [free course](https://themodern.dev/courses/build-a-fullstack-app-with-nextjs-supabase-and-prisma-322389284337222224), you'll learn how to build a full-stack app using the following technologies:
|
||||
|
||||
- **Next.js** - The React framework for building the UI of the app and the REST API
|
||||
- **NextAuth.js** - For implementing passwordless and OAuth authentication
|
||||
- **Next.js** - The React framework for building the UI of the app and the REST API
|
||||
- **NextAuth.js** - For implementing passwordless and OAuth authentication
|
||||
- **Supabase** - For persisting the app data into a PostgreSQL database and storing media files
|
||||
- **Prisma** - For making it easy to read and write data from our app from and to the database
|
||||
|
||||
The app that we'll work on in this course is called ***SupaVacation***. It is an online marketplace for vacation rentals where users can browse through all the properties for rent, bookmark their favorite ones, and even rent their own properties.
|
||||
The app that we'll work on in this course is called **_SupaVacation_**. It is an online marketplace for vacation rentals where users can browse through all the properties for rent, bookmark their favorite ones, and even rent their own properties.
|
||||
|
||||
> Here's [a live demo](https://supa-vacation.vercel.app/) of the app's final version. It is what your app should look likes after completing this course. Feel free to play with it to get an overview of all the features you'll be working on.
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ async function refreshAccessToken(token) {
|
||||
return {
|
||||
...token,
|
||||
accessToken: refreshedTokens.access_token,
|
||||
accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
|
||||
accessTokenExpires: Date.now() + refreshedTokens.expires_at * 1000,
|
||||
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken, // Fall back to old refresh token
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -88,7 +88,7 @@ export default NextAuth({
|
||||
if (account && user) {
|
||||
return {
|
||||
accessToken: account.access_token,
|
||||
accessTokenExpires: Date.now() + account.expires_in * 1000,
|
||||
accessTokenExpires: Date.now() + account.expires_at * 1000,
|
||||
refreshToken: account.refresh_token,
|
||||
user,
|
||||
}
|
||||
|
||||
60
docs/docs/tutorials/role-based-login-strategy.md
Normal file
60
docs/docs/tutorials/role-based-login-strategy.md
Normal file
@@ -0,0 +1,60 @@
|
||||
To add role based authentication to your application, you must do three things.
|
||||
|
||||
1. Update your database schema
|
||||
2. Add the `role` to the session object
|
||||
3. Check for `role` in your pages/components
|
||||
|
||||
First modify the `user` table and add a `role` column with the type of `String?`.
|
||||
|
||||
Below is an example Prisma schema file.
|
||||
|
||||
```javascript title="/prisma/schema.prisma"
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
email String? @unique
|
||||
emailVerified DateTime?
|
||||
image String?
|
||||
role String? // New Column
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Next, implement a custom session callback in the `[...nextauth].js` file, as shown below.
|
||||
|
||||
```javascript title="/pages/api/auth/[...nextauth].js"
|
||||
callbacks: {
|
||||
async session({ session, token, user }) {
|
||||
session.user.role = user.role; // Add role value to user object so it is passed along with session
|
||||
return session;
|
||||
},
|
||||
```
|
||||
|
||||
Going forward, when using the `getSession` hook, check that `session.user.role` matches the required role. The example below assumes the role `'admin'` is required.
|
||||
|
||||
```javascript title="/pages/admin.js"
|
||||
import { getSession } from "next-auth/react"
|
||||
|
||||
export default function Page() {
|
||||
const session = await getSession({ req })
|
||||
|
||||
if (session && session.user.role === "admin") {
|
||||
return (
|
||||
<div>
|
||||
<h1>Admin</h1>
|
||||
<p>Welcome to the Admin Portal!</p>
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<h1>You are not authorized to view this page!</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then it is up to you how you manage your roles, either through direct database access or building your own role update API.
|
||||
@@ -9,6 +9,13 @@ module.exports = {
|
||||
themeConfig: {
|
||||
prism: {
|
||||
theme: require("prism-react-renderer/themes/vsDark"),
|
||||
magicComments: [
|
||||
{
|
||||
className: "theme-code-block-highlighted-line",
|
||||
line: "highlight-next-line",
|
||||
block: { start: "highlight-start", end: "highlight-end" },
|
||||
},
|
||||
],
|
||||
},
|
||||
algolia: {
|
||||
appId: "OUEDA16KPG",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"url": "git://github.com/nextauthjs/docs.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "npm run generate-providers && docusaurus start --port 8000",
|
||||
"start": "npm run generate-providers && docusaurus start --no-open --port 8000",
|
||||
"dev": "npm run start",
|
||||
"build": "npm run generate-providers && docusaurus build",
|
||||
"docusaurus": "docusaurus",
|
||||
@@ -19,25 +19,31 @@
|
||||
"generate-providers": "node ./scripts/generate-providers.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codesandbox/sandpack-react": "^0.13.12",
|
||||
"@docusaurus/core": "^2.0.0-beta.17",
|
||||
"@docusaurus/preset-classic": "^2.0.0-beta.17",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^2.0.0-beta.17",
|
||||
"@docusaurus/core": "^2.0.0-beta.20",
|
||||
"@docusaurus/preset-classic": "^2.0.0-beta.20",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^2.0.0-beta.20",
|
||||
"@docusaurus/theme-common": "2.0.0-beta.20",
|
||||
"@mdx-js/react": "1.6.22",
|
||||
"classnames": "^2.3.1",
|
||||
"lodash.times": "^4.3.2",
|
||||
"mdx-mermaid": "^1.2.1",
|
||||
"mermaid": "^8.13.10",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"mdx-mermaid": "^1.2.2",
|
||||
"mermaid": "^9.0.1",
|
||||
"prism-react-renderer": "1.3.1",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"react-marquee-slider": "^1.1.5",
|
||||
"remark-github": "^10.1.0",
|
||||
"styled-components": "^5.3.3"
|
||||
"styled-components": "5.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.5.0"
|
||||
"@docusaurus/module-type-aliases": "2.0.0-beta.20",
|
||||
"prettier": "^2.6.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [">0.2%", "not dead", "not op_mini all"],
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
|
||||
@@ -40,10 +40,9 @@ module.exports = {
|
||||
{
|
||||
type: "category",
|
||||
label: "Providers",
|
||||
link: { type: "doc", id: "providers/overview" },
|
||||
collapsed: true,
|
||||
items: [
|
||||
"providers/overview",
|
||||
// TODO: Overview included twice due to autogeneration
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: "providers",
|
||||
@@ -53,9 +52,9 @@ module.exports = {
|
||||
{
|
||||
type: "category",
|
||||
label: "Adapters",
|
||||
link: { type: "doc", id: "adapters/overview" },
|
||||
collapsed: true,
|
||||
items: [
|
||||
"adapters/overview",
|
||||
"adapters/models",
|
||||
"adapters/prisma",
|
||||
"adapters/fauna",
|
||||
@@ -77,17 +76,15 @@ module.exports = {
|
||||
{
|
||||
type: "category",
|
||||
label: "Guides",
|
||||
link: { type: "doc", id: "guides/guides" },
|
||||
collapsed: true,
|
||||
items: [
|
||||
"guides/basics",
|
||||
"guides/fullstack",
|
||||
"guides/testing",
|
||||
],
|
||||
items: ["guides/basics", "guides/fullstack", "guides/testing"],
|
||||
},
|
||||
{
|
||||
type: "html",
|
||||
value: '<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CEAI6K3N&placement=next-authjsorg" id="_carbonads_js"></script>',
|
||||
defaultStyle: true
|
||||
value:
|
||||
'<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?serve=CEAI6K3N&placement=next-authjsorg" id="_carbonads_js"></script>',
|
||||
defaultStyle: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from "react"
|
||||
import Marquee, { Motion, randomIntFromInterval } from "react-marquee-slider"
|
||||
import * as S from "./ProviderMarqueeStyle"
|
||||
import times from "lodash.times"
|
||||
import styles from "./ProviderMarqueeStyle.module.css"
|
||||
|
||||
const icons = [
|
||||
"/img/providers/apple-black.svg",
|
||||
@@ -20,7 +19,7 @@ const icons = [
|
||||
"/img/providers/twitter.svg",
|
||||
]
|
||||
|
||||
const ProviderMarquee = React.memo(({ size }) => {
|
||||
const ProviderMarquee = React.memo(() => {
|
||||
let scale = 0.4
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -39,8 +38,8 @@ const ProviderMarquee = React.memo(({ size }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<S.FullWidth>
|
||||
<S.Height height={500}>
|
||||
<div className={styles.fullWidth}>
|
||||
<div className={styles.height}>
|
||||
<Marquee
|
||||
key="1"
|
||||
velocity={5}
|
||||
@@ -48,24 +47,33 @@ const ProviderMarquee = React.memo(({ size }) => {
|
||||
minScale={0.5}
|
||||
resetAfterTries={200}
|
||||
>
|
||||
{times(icons.length, Number).map((id) => (
|
||||
{icons.map((icon) => (
|
||||
<Motion
|
||||
key={`marquee-example-company-${id}`}
|
||||
key={`marquee-example-company-${icon}`}
|
||||
initDeg={randomIntFromInterval(0, 360)}
|
||||
direction={Math.random() > 0.5 ? "clockwise" : "counterclockwise"}
|
||||
velocity={10}
|
||||
radius={scale * 70}
|
||||
>
|
||||
<S.Company scale={scale}>
|
||||
<S.Circle scale={scale}>
|
||||
<S.Logo src={icons[id]} alt="" />
|
||||
</S.Circle>
|
||||
</S.Company>
|
||||
<div
|
||||
className={styles.company}
|
||||
style={{ height: `${scale * 75}px`, width: `${scale * 75}px` }}
|
||||
>
|
||||
<div
|
||||
className={styles.circle}
|
||||
style={{
|
||||
height: `${scale * 150}px`,
|
||||
width: `${scale * 150}px`,
|
||||
}}
|
||||
>
|
||||
<img className={styles.logo} src={icon} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</Motion>
|
||||
))}
|
||||
</Marquee>
|
||||
</S.Height>
|
||||
</S.FullWidth>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import styled from "styled-components"
|
||||
|
||||
export const Circle = styled.div`
|
||||
.circle {
|
||||
position: absolute;
|
||||
object-position: center center;
|
||||
will-change: transform, opacity;
|
||||
width: ${(props) => props.scale * 150}px;
|
||||
height: ${(props) => props.scale * 150}px;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
border-radius: 50%;
|
||||
@@ -13,33 +9,31 @@ export const Circle = styled.div`
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
`
|
||||
}
|
||||
|
||||
export const Logo = styled.img`
|
||||
.logo {
|
||||
display: block;
|
||||
width: 65%;
|
||||
height: 65%;
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.1;
|
||||
`
|
||||
}
|
||||
|
||||
export const FullWidth = styled.div`
|
||||
.fullWidth {
|
||||
width: 100vw;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
right: 50%;
|
||||
margin-left: -50vw;
|
||||
margin-right: -50vw;
|
||||
`
|
||||
}
|
||||
|
||||
export const Height = styled.div`
|
||||
.height {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: ${(props) => (props.height ? props.height + "px" : "auto")};
|
||||
`
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
export const Company = styled.div`
|
||||
.company {
|
||||
position: relative;
|
||||
width: ${(props) => props.scale * 75}px;
|
||||
height: ${(props) => props.scale * 75}px;
|
||||
`
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from "react"
|
||||
import {
|
||||
SandpackProvider,
|
||||
SandpackLayout,
|
||||
SandpackCodeEditor,
|
||||
SandpackPreview,
|
||||
} from "@codesandbox/sandpack-react"
|
||||
|
||||
export const CustomSandpack = () => (
|
||||
<SandpackProvider template="react">
|
||||
<SandpackLayout>
|
||||
<SandpackCodeEditor />
|
||||
<SandpackPreview />
|
||||
</SandpackLayout>
|
||||
</SandpackProvider>
|
||||
)
|
||||
@@ -7,11 +7,6 @@
|
||||
|
||||
/* @TODO Move as many styles for the homepage as possible into styles.module.css */
|
||||
|
||||
/**
|
||||
* Sandpack integration
|
||||
*/
|
||||
@import "@codesandbox/sandpack-react/dist/index.css";
|
||||
|
||||
/* You can override the default Infima variables here. */
|
||||
:root {
|
||||
--ifm-color-link: #289ef9;
|
||||
@@ -62,12 +57,6 @@ html[data-theme="dark"] svg[id^="mermaid-svg"] text[id*="-attr"] {
|
||||
@import "navbar.css";
|
||||
@import "search.css";
|
||||
|
||||
@media screen and (max-width: 360px) {
|
||||
html {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
29
package.json
29
package.json
@@ -2,30 +2,24 @@
|
||||
"name": "root",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*",
|
||||
"apps/dev",
|
||||
"docs"
|
||||
]
|
||||
},
|
||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||
"scripts": {
|
||||
"build:app": "turbo run build --scope=next-auth-app --include-dependencies",
|
||||
"build": "turbo run build --scope=next-auth --scope=@next-auth/* --no-deps",
|
||||
"lint": "turbo run lint --scope=!next-auth-docs",
|
||||
"build:app": "turbo run build --filter=next-auth-app --include-dependencies",
|
||||
"build": "turbo run build --filter=next-auth --filter=@next-auth/* --no-deps",
|
||||
"lint": "turbo run lint --filter=!next-auth-docs",
|
||||
"lint:fix": "turbo run lint -- --fix",
|
||||
"test": "turbo run test --concurrency=1 --scope=!@next-auth/pouchdb-adapter --scope=!next-auth-*",
|
||||
"test": "turbo run test --concurrency=1 --filter=!@next-auth/pouchdb-adapter --filter=!next-auth-* --filter=[HEAD^1]",
|
||||
"setup": "turbo run setup",
|
||||
"dev": "yarn dev:app",
|
||||
"dev:app": "turbo run dev --parallel --no-deps --no-cache --scope=next-auth-app",
|
||||
"dev:docs": "turbo run dev --parallel --no-deps --no-cache --scope=next-auth-docs",
|
||||
"dev": "pnpm dev:app",
|
||||
"dev:app": "turbo run dev --parallel --no-deps --no-cache --filter=next-auth-app",
|
||||
"dev:docs": "turbo run dev --parallel --no-deps --no-cache --filter=next-auth-docs",
|
||||
"version:pr": "node ./config/version-pr",
|
||||
"release": "ts-node scripts/release"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@actions/core": "^1.6.0",
|
||||
"@commitlint/parse": "16.0.0",
|
||||
"@types/node": "^17.0.25",
|
||||
"@types/semver": "7.3.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.2",
|
||||
"@typescript-eslint/parser": "^4.33.0",
|
||||
@@ -43,11 +37,12 @@
|
||||
"semver": "7.3.5",
|
||||
"stream-to-array": "2.3.0",
|
||||
"ts-node": "10.5.0",
|
||||
"turbo": "^1.1.6",
|
||||
"turbo": "^1.2.5",
|
||||
"typescript": "^4.5.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.19.0 || ^14.15.0 || ^16.13.0"
|
||||
"node": "^12.19.0 || ^14.15.0 || ^16.13.0",
|
||||
"pnpm": ">=6.32.3"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
@@ -102,7 +97,7 @@
|
||||
"**/tests",
|
||||
"**/__tests__"
|
||||
],
|
||||
"packageManager": "yarn@1.22.17",
|
||||
"packageManager": "pnpm@6.32.8",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
|
||||
@@ -31,14 +31,16 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/jsonwebtoken": "^8.5.5",
|
||||
"@types/node-fetch": "^2.5.11",
|
||||
"jest": "^27.0.6",
|
||||
"next-auth": "^4.0.1",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*",
|
||||
"ts-jest": "^27.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -46,6 +48,6 @@
|
||||
"node-fetch": "^2.6.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DgraphAdapter, format } from "../src"
|
||||
import { client as dgraphClient } from "../src/client"
|
||||
import * as fragments from "../src/graphql/fragments"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* https://jestjs.io/docs/en/configuration.html
|
||||
*/
|
||||
module.exports = {
|
||||
...require("adapter-test/jest/jest-preset"),
|
||||
...require("@next-auth/adapter-test/jest/jest-preset"),
|
||||
// // Indicates whether the coverage information should be collected while executing the test
|
||||
// collectCoverage: true,
|
||||
// // Indicates which provider should be used to instrument code for coverage
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"scripts": {
|
||||
"test:default": "jest",
|
||||
"test:custom": "CUSTOM_MODEL=1 jest",
|
||||
"test": "yarn test:default && yarn test:custom",
|
||||
"test": "pnpm test:default && pnpm test:custom",
|
||||
"build": "tsc"
|
||||
},
|
||||
"files": [
|
||||
@@ -32,12 +32,15 @@
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-sdk/client-dynamodb": "^3.36.1",
|
||||
"@aws-sdk/lib-dynamodb": "^3.36.1",
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@shelf/jest-dynamodb": "^2.1.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DynamoDB } from "@aws-sdk/client-dynamodb"
|
||||
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"
|
||||
import { DynamoDBAdapter } from "../src"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { format } from "../src/"
|
||||
const config = {
|
||||
endpoint: "http://127.0.0.1:8000",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"files": ["dist", "README.md"],
|
||||
"files": [
|
||||
"dist",
|
||||
"README.md"
|
||||
],
|
||||
"author": "Bhanu Teja P",
|
||||
"contributors": [
|
||||
{
|
||||
@@ -21,7 +24,12 @@
|
||||
],
|
||||
"main": "dist/index.js",
|
||||
"license": "ISC",
|
||||
"keywords": ["next-auth", "next.js", "fauna", "faunadb"],
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
"next.js",
|
||||
"fauna",
|
||||
"faunadb"
|
||||
],
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -33,14 +41,17 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"faunadb": "^4.3.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fauna-labs/fauna-schema-migrate": "^2.1.3",
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"faunadb": "^4.3.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { collections, FaunaAdapter, format, indexes, query } from "../src"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { Client as FaunaClient, Get, Match, Ref } from "faunadb"
|
||||
|
||||
const client = new FaunaClient({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = require("../adapter-test/jest.config")
|
||||
module.exports = require("@next-auth/adapter-test/jest.config")
|
||||
|
||||
@@ -33,11 +33,14 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"firebase": "^8.6.2",
|
||||
"next-auth": "latest"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"firebase": "^8.6.2",
|
||||
"firebase-tools": "^9.11.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { FirebaseAdapter } from "../src"
|
||||
import { docSnapshotToObject, querySnapshotToObject } from "../src/utils"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/base.json",
|
||||
"extends": "@next-auth/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -33,14 +33,17 @@
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@mikro-orm/core": "^5.0.2",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mikro-orm/core": "^5.0.2",
|
||||
"@mikro-orm/sqlite": "^5.0.2",
|
||||
"next-auth": "^4.0.1"
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Options } from "@mikro-orm/core"
|
||||
import type { SqliteDriver } from "@mikro-orm/sqlite"
|
||||
|
||||
import { MikroORM, wrap } from "@mikro-orm/core"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { MikroOrmAdapter, defaultEntities } from "../src"
|
||||
import { User, VeryImportantEntity } from "./testEntities"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
Property,
|
||||
Unique,
|
||||
} from "@mikro-orm/core"
|
||||
import { randomUUID } from "adapter-test"
|
||||
import { randomUUID } from "@next-auth/adapter-test"
|
||||
import type { defaultEntities } from "../src"
|
||||
import { Account, Session } from "../src/entities"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
|
||||
@@ -10,7 +10,13 @@
|
||||
"author": "Balázs Orbán <info@balazsorban.com>",
|
||||
"main": "dist/index.js",
|
||||
"license": "ISC",
|
||||
"keywords": ["next-auth", "next.js", "oauth", "mongodb", "adapter"],
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
"next.js",
|
||||
"oauth",
|
||||
"mongodb",
|
||||
"adapter"
|
||||
],
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -20,16 +26,22 @@
|
||||
"test:watch": "./tests/test.sh -w",
|
||||
"build": "tsc"
|
||||
},
|
||||
"files": ["README.md", "dist"],
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"mongodb": "^4.1.1",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"jest": "^27.4.3",
|
||||
"mongodb": "^4.4.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
|
||||
import { MongoClient } from "mongodb"
|
||||
const name = "custom-test"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { defaultCollections, format, MongoDBAdapter, _id } from "../src"
|
||||
import { MongoClient } from "mongodb"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -34,17 +34,20 @@
|
||||
],
|
||||
"peerDependencies": {
|
||||
"neo4j-driver": "^4.0.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@types/uuid": "^8.3.3",
|
||||
"jest": "^27.4.3",
|
||||
"neo4j-driver": "^4.4.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as neo4j from "neo4j-driver"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import statements from "./resources/statements"
|
||||
|
||||
import { Neo4jAdapter, format } from "../src"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
"author": "jpbourgeon <jeanphilippe.bourgeon@gmail.com> (https://github.com/jpbourgeon)",
|
||||
"main": "dist/index.js",
|
||||
"license": "ISC",
|
||||
"keywords": ["next-auth", "next.js", "oauth", "pouchdb"],
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
"next.js",
|
||||
"oauth",
|
||||
"pouchdb"
|
||||
],
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -20,9 +25,12 @@
|
||||
"tdd": "jest --watch",
|
||||
"test:wip": "jest"
|
||||
},
|
||||
"files": ["README.md", "dist"],
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"next-auth": "^3.23.3",
|
||||
"next-auth": "workspace:*",
|
||||
"pouchdb": "^7.2.2",
|
||||
"pouchdb-find": "^7.2.2"
|
||||
},
|
||||
@@ -31,13 +39,16 @@
|
||||
"ulid": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@types/pouchdb": "^6.4.0",
|
||||
"next-auth": "^4.0.1",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*",
|
||||
"pouchdb": "^7.2.2",
|
||||
"pouchdb-adapter-memory": "^7.2.2",
|
||||
"pouchdb-find": "^7.2.2"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import find from "pouchdb-find"
|
||||
import { ulid } from "ulid"
|
||||
import Providers from "next-auth/providers"
|
||||
import { PouchDBAdapter } from "../src"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
|
||||
// pouchdb setup
|
||||
PouchDB.plugin(memoryAdapter).plugin(find)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/base.json",
|
||||
"extends": "@next-auth/tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
"author": "William Luke",
|
||||
"main": "dist/index.js",
|
||||
"license": "ISC",
|
||||
"keywords": ["next-auth", "next.js", "oauth", "prisma"],
|
||||
"keywords": [
|
||||
"next-auth",
|
||||
"next.js",
|
||||
"oauth",
|
||||
"prisma"
|
||||
],
|
||||
"private": false,
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -19,24 +24,31 @@
|
||||
"clean": "rm -rf ./prisma/migrations && rm ./prisma/dev.db*",
|
||||
"init:default": "prisma migrate dev --name init --skip-seed",
|
||||
"init:custom": "prisma migrate dev --name init-custom --schema ./prisma/custom.prisma",
|
||||
"test:default": "yarn init:default && jest",
|
||||
"test:custom": "yarn init:custom && CUSTOM_MODEL=1 jest",
|
||||
"test:default": "pnpm init:default && jest",
|
||||
"test:custom": "pnpm init:custom && CUSTOM_MODEL=1 jest",
|
||||
"test:mongodb": "./tests/mongodb.test.sh",
|
||||
"test": "yarn test:default && yarn test:custom && yarn test:mongodb",
|
||||
"test": "pnpm test:default && pnpm test:custom && pnpm test:mongodb",
|
||||
"build": "prisma generate && tsc",
|
||||
"studio": "prisma studio"
|
||||
},
|
||||
"files": ["README.md", "dist"],
|
||||
"files": [
|
||||
"README.md",
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@prisma/client": ">=2.26.0 || >=3",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@prisma/client": "^3.10.0",
|
||||
"next-auth": "^4.0.1",
|
||||
"jest": "^27.4.3",
|
||||
"mongodb": "^4.4.0",
|
||||
"next-auth": "workspace:*",
|
||||
"prisma": "^3.10.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { randomUUID, runBasicTests } from "adapter-test"
|
||||
import { randomUUID, runBasicTests } from "@next-auth/adapter-test"
|
||||
import { PrismaClient } from "@prisma/client"
|
||||
import { PrismaAdapter } from "../src"
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
@@ -16,7 +16,7 @@ done
|
||||
# Start db
|
||||
docker run -d --rm -p 27017:27017 --name ${CONTAINER_NAME} "prismagraphql/mongo-single-replica:4.4.3-bionic"
|
||||
|
||||
yarn prisma generate --schema ./prisma/mongodb.prisma
|
||||
pnpm prisma generate --schema ./prisma/mongodb.prisma
|
||||
|
||||
if $JEST_WATCH; then
|
||||
# Run jest in watch mode
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@next-auth/sequelize-adapter",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.4",
|
||||
"description": "Sequelize adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
@@ -29,14 +29,17 @@
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"next-auth": "^4.0.1",
|
||||
"next-auth": "workspace:*",
|
||||
"sequelize": "^6.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"next-auth": "^4.0.1",
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*",
|
||||
"sequelize": "^6.6.5"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Account as ApadterAccount } from "next-auth"
|
||||
import type { Account as AdapterAccount } from "next-auth"
|
||||
import type {
|
||||
Adapter,
|
||||
AdapterUser,
|
||||
@@ -12,8 +12,8 @@ export { defaultModels as models }
|
||||
|
||||
// @see https://sequelize.org/master/manual/typescript.html
|
||||
interface AccountInstance
|
||||
extends Model<ApadterAccount, Partial<ApadterAccount>>,
|
||||
ApadterAccount {}
|
||||
extends Model<AdapterAccount, Partial<AdapterAccount>>,
|
||||
AdapterAccount {}
|
||||
interface UserInstance
|
||||
extends Model<AdapterUser, Partial<AdapterUser>>,
|
||||
AdapterUser {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Sequelize, DataTypes } from "sequelize"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import SequelizeAdapter, { models } from "../src"
|
||||
|
||||
const sequelize = new Sequelize({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
".(ts|tsx)$": "ts-jest",
|
||||
".(js|jsx)$": "babel-jest", // jest's default
|
||||
".(ts|tsx)$": "@swc/jest",
|
||||
".(js|jsx)$": "@swc/jest", // jest's default
|
||||
},
|
||||
transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"],
|
||||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "adapter-test",
|
||||
"name": "@next-auth/adapter-test",
|
||||
"version": "0.0.0",
|
||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||
"contributors": [
|
||||
@@ -26,7 +26,7 @@
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.0",
|
||||
"jest": "^27.0.3",
|
||||
"next-auth": "latest",
|
||||
"next-auth": "workspace:*",
|
||||
"prettier": "^2.3.0",
|
||||
"ts-jest": "^27.0.3",
|
||||
"typescript": "^4.2.4"
|
||||
|
||||
@@ -32,14 +32,17 @@
|
||||
"init:db": "tests/init.sh",
|
||||
"test:containers": "tests/test.sh",
|
||||
"test": "tests/test.sh",
|
||||
"mysql": "yarn init:db && tests/mysql/test.sh",
|
||||
"postgres": "yarn init:db && tests/postgresql/test.sh",
|
||||
"mysql": "pnpm init:db && tests/mysql/test.sh",
|
||||
"postgres": "pnpm init:db && tests/postgresql/test.sh",
|
||||
"sqlite": "tests/sqlite/test.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"next-auth": "^4.0.1",
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"jest": "^27.4.3",
|
||||
"mssql": "^7.2.1",
|
||||
"mysql": "^2.18.1",
|
||||
"next-auth": "workspace:*",
|
||||
"pg": "^8.7.1",
|
||||
"sqlite3": "^5.0.2",
|
||||
"typeorm": "^0.2.37",
|
||||
@@ -48,7 +51,7 @@
|
||||
"peerDependencies": {
|
||||
"mssql": "^6.2.1 || 7",
|
||||
"mysql": "^2.18.1",
|
||||
"next-auth": "^4.0.1",
|
||||
"next-auth": "workspace:*",
|
||||
"pg": "^8.2.1",
|
||||
"sqlite3": "^5.0.2",
|
||||
"typeorm": "^0.2.31"
|
||||
@@ -68,6 +71,6 @@
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ConnectionManager, ConnectionOptions } from "typeorm"
|
||||
import { TestOptions } from "adapter-test"
|
||||
import { TestOptions } from "@next-auth/adapter-test"
|
||||
import * as defaultEntities from "../src/entities"
|
||||
import { parseConnectionConfig } from "../src/utils"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
|
||||
@@ -31,17 +31,20 @@
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@upstash/redis": "^1.0.1",
|
||||
"next-auth": "^4.0.1"
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next-auth/adapter-test": "workspace:^0.0.0",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@upstash/redis": "^1.0.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"next-auth": "^4.0.1"
|
||||
"jest": "^27.4.3",
|
||||
"next-auth": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "adapter-test/jest"
|
||||
"preset": "@next-auth/adapter-test/jest"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Redis } from "@upstash/redis"
|
||||
import { runBasicTests } from "adapter-test"
|
||||
import { runBasicTests } from "@next-auth/adapter-test"
|
||||
import { hydrateDates, UpstashRedisAdapter } from "../src"
|
||||
import "dotenv/config"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "tsconfig/adapters.json",
|
||||
"extends": "@next-auth/tsconfig/adapters.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
|
||||
@@ -25,7 +25,7 @@ module.exports = (api) => {
|
||||
ignore: [
|
||||
"../src/**/__tests__/**",
|
||||
"../src/adapters.ts",
|
||||
"../src/lib/types.ts",
|
||||
"../src/core/types.ts",
|
||||
"../src/providers/oauth-types.ts",
|
||||
],
|
||||
comments: false,
|
||||
@@ -33,7 +33,7 @@ module.exports = (api) => {
|
||||
{
|
||||
test: [
|
||||
"../src/react/index.tsx",
|
||||
"../src/lib/logger.ts",
|
||||
"../src/utils/logger.ts",
|
||||
"../src/core/errors.ts",
|
||||
"../src/client/**",
|
||||
],
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
/** @type {import('@jest/types').Config.InitialOptions} */
|
||||
module.exports = {
|
||||
transform: {
|
||||
"\\.(js|jsx|ts|tsx)$": [
|
||||
"babel-jest",
|
||||
{ configFile: "./config/babel.config.js" },
|
||||
],
|
||||
"\\.(js|jsx|ts|tsx)$": ["@swc/jest", require("./swc.config")],
|
||||
},
|
||||
rootDir: "../src",
|
||||
setupFilesAfterEnv: ["../config/jest-setup.js"],
|
||||
13
packages/next-auth/config/jest.core.config.js
Normal file
13
packages/next-auth/config/jest.core.config.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/** @type {import('@jest/types').Config.InitialOptions} */
|
||||
module.exports = {
|
||||
transform: {
|
||||
"\\.(js|jsx|ts|tsx)$": ["@swc/jest", require("./swc.config")],
|
||||
},
|
||||
rootDir: "..",
|
||||
testMatch: ["**/*.test.ts"],
|
||||
setupFilesAfterEnv: ["./config/jest-setup.js"],
|
||||
watchPlugins: [
|
||||
"jest-watch-typeahead/filename",
|
||||
"jest-watch-typeahead/testname",
|
||||
],
|
||||
}
|
||||
17
packages/next-auth/config/swc.config.js
Normal file
17
packages/next-auth/config/swc.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: "typescript",
|
||||
tsx: true,
|
||||
},
|
||||
transform: {
|
||||
react: {
|
||||
runtime: "automatic",
|
||||
pragma: "React.createElement",
|
||||
pragmaFrag: "React.Fragment",
|
||||
throwIfNamespace: true,
|
||||
useBuiltins: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth",
|
||||
"version": "4.3.4",
|
||||
"version": "4.5.0",
|
||||
"description": "Authentication for Next.js",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||
@@ -36,15 +36,17 @@
|
||||
"./providers/*": "./providers/*.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn clean && yarn run build:js && yarn run build:css",
|
||||
"clean": "rm -rf client css lib providers core jwt react next index.d.ts index.js adapters.d.ts middleware.d.ts middleware.js",
|
||||
"build:js": "yarn run clean && yarn run generate-providers && tsc && babel --config-file ./config/babel.config.js src --out-dir . --extensions \".tsx,.ts,.js,.jsx\"",
|
||||
"build": "pnpm clean && pnpm build:js && pnpm build:css",
|
||||
"clean": "rm -rf client css utils providers core jwt react next index.d.ts index.js adapters.d.ts middleware.d.ts middleware.js",
|
||||
"build:js": "pnpm clean && pnpm generate-providers && tsc && babel --config-file ./config/babel.config.js src --out-dir . --extensions \".tsx,.ts,.js,.jsx\"",
|
||||
"build:css": "postcss --config config/postcss.config.js src/**/*.css --base src --dir . && node config/wrap-css.js",
|
||||
"watch:css": "postcss --config config/postcss.config.js --watch src/**/*.css --base src --dir .",
|
||||
"test": "jest --config ./config/jest.config.js",
|
||||
"prepublishOnly": "yarn run build",
|
||||
"test:client": "jest --config ./config/jest.client.config.js",
|
||||
"test:core": "jest --config ./config/jest.core.config.js",
|
||||
"test": "pnpm test:core && pnpm test:client",
|
||||
"prepublishOnly": "pnpm build",
|
||||
"generate-providers": "node ./config/generate-providers.js",
|
||||
"setup": "yarn run generate-providers",
|
||||
"setup": "pnpm generate-providers",
|
||||
"lint": "eslint src config"
|
||||
},
|
||||
"files": [
|
||||
@@ -66,10 +68,10 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.16.3",
|
||||
"@panva/hkdf": "^1.0.1",
|
||||
"@panva/oauth4webapi": "^0.0.10",
|
||||
"cookie": "^0.4.1",
|
||||
"jose": "^4.3.7",
|
||||
"oauth": "^0.9.15",
|
||||
"openid-client": "^5.1.0",
|
||||
"preact": "^10.6.3",
|
||||
"preact-render-to-string": "^5.1.19",
|
||||
"uuid": "^8.3.2"
|
||||
@@ -85,38 +87,40 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.16.0",
|
||||
"@babel/core": "^7.16.0",
|
||||
"@babel/plugin-proposal-optional-catch-binding": "^7.16.0",
|
||||
"@babel/plugin-transform-runtime": "^7.16.4",
|
||||
"@babel/preset-env": "^7.16.4",
|
||||
"@babel/preset-react": "^7.16.0",
|
||||
"@babel/preset-typescript": "^7.16.0",
|
||||
"@testing-library/dom": "^8.11.3",
|
||||
"@testing-library/jest-dom": "^5.16.1",
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/react-hooks": "^7.0.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/node": "^16.11.12",
|
||||
"@babel/cli": "^7.17.10",
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/plugin-proposal-optional-catch-binding": "^7.16.7",
|
||||
"@babel/plugin-transform-runtime": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/preset-react": "^7.17.12",
|
||||
"@babel/preset-typescript": "^7.17.12",
|
||||
"@next-auth/tsconfig": "workspace:^0.0.0",
|
||||
"@swc/core": "^1.2.198",
|
||||
"@swc/jest": "^0.2.21",
|
||||
"@testing-library/dom": "^8.13.0",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@testing-library/react-hooks": "^8.0.0",
|
||||
"@testing-library/user-event": "^14.2.0",
|
||||
"@types/node": "^17.0.42",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/oauth": "^0.9.1",
|
||||
"@types/react": "^17.0.37",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"babel-jest": "^27.4.2",
|
||||
"@types/react": "^18.0.2",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-plugin-jsx-pragmatic": "^1.0.2",
|
||||
"babel-preset-preact": "^2.0.0",
|
||||
"cpx": "^1.5.0",
|
||||
"cssnano": "^5.0.12",
|
||||
"jest": "^27.4.3",
|
||||
"jest-watch-typeahead": "^1.0.0",
|
||||
"msw": "^0.36.3",
|
||||
"next": "12.1.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-cli": "^9.0.2",
|
||||
"cssnano": "^5.1.11",
|
||||
"jest": "^28.1.1",
|
||||
"jest-environment-jsdom": "^28.1.1",
|
||||
"jest-watch-typeahead": "^1.1.0",
|
||||
"msw": "^0.42.1",
|
||||
"next": "^12.1.6",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-cli": "^9.1.0",
|
||||
"postcss-nested": "^5.0.6",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"whatwg-fetch": "^3.6.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -2,11 +2,11 @@ import { useState } from "react"
|
||||
import userEvent from "@testing-library/user-event"
|
||||
import { render, screen, waitFor } from "@testing-library/react"
|
||||
import { server, mockCSRFToken } from "./helpers/mocks"
|
||||
import logger from "../../lib/logger"
|
||||
import logger from "../../utils/logger"
|
||||
import { getCsrfToken } from "../../react"
|
||||
import { rest } from "msw"
|
||||
|
||||
jest.mock("../../lib/logger", () => ({
|
||||
jest.mock("../../utils/logger", () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
warn: jest.fn(),
|
||||
|
||||
@@ -3,10 +3,10 @@ import userEvent from "@testing-library/user-event"
|
||||
import { render, screen, waitFor } from "@testing-library/react"
|
||||
import { server, mockProviders } from "./helpers/mocks"
|
||||
import { getProviders } from "../../react"
|
||||
import logger from "../../lib/logger"
|
||||
import logger from "../../utils/logger"
|
||||
import { rest } from "msw"
|
||||
|
||||
jest.mock("../../lib/logger", () => ({
|
||||
jest.mock("../../utils/logger", () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
warn: jest.fn(),
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { render, screen, waitFor } from "@testing-library/react"
|
||||
import { rest } from "msw"
|
||||
import { server, mockSession } from "./helpers/mocks"
|
||||
import logger from "../../lib/logger"
|
||||
import logger from "../../utils/logger"
|
||||
import { useState, useEffect } from "react"
|
||||
import { getSession } from "../../react"
|
||||
import { getBroadcastEvents } from "./helpers/utils"
|
||||
|
||||
jest.mock("../../lib/logger", () => ({
|
||||
jest.mock("../../utils/logger", () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
warn: jest.fn(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState } from "react"
|
||||
import userEvent from "@testing-library/user-event"
|
||||
import { render, screen, waitFor } from "@testing-library/react"
|
||||
import logger from "../../lib/logger"
|
||||
import logger from "../../utils/logger"
|
||||
import {
|
||||
server,
|
||||
mockCredentialsResponse,
|
||||
@@ -13,7 +13,7 @@ import { rest } from "msw"
|
||||
|
||||
const { location } = window
|
||||
|
||||
jest.mock("../../lib/logger", () => ({
|
||||
jest.mock("../../utils/logger", () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
warn: jest.fn(),
|
||||
|
||||
@@ -61,11 +61,11 @@ test("it redirects to the URL allowed by the server", async () => {
|
||||
})
|
||||
})
|
||||
|
||||
test.skip("if url contains a hash during redirection a page reload happens", async () => {
|
||||
test("if url contains a hash during redirection a page reload happens", async () => {
|
||||
const mockUrlWithHash = "https://path/to/email/url#foo-bar-baz"
|
||||
|
||||
server.use(
|
||||
rest.post("http://localhost/api/auth/signout", (req, res, ctx) => {
|
||||
rest.post("*/api/auth/signout", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
|
||||
@@ -63,6 +63,11 @@ export class UnsupportedStrategy extends UnknownError {
|
||||
code = "CALLBACK_CREDENTIALS_JWT_ERROR"
|
||||
}
|
||||
|
||||
export class InvalidCallbackUrl extends UnknownError {
|
||||
name = "InvalidCallbackUrl"
|
||||
code = "INVALID_CALLBACK_URL_ERROR"
|
||||
}
|
||||
|
||||
type Method = (...args: any[]) => Promise<any>
|
||||
|
||||
export function upperSnake(s: string) {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import logger, { setLogger } from "../lib/logger"
|
||||
import logger, { setLogger } from "../utils/logger"
|
||||
import { detectHost } from "../utils/detect-host"
|
||||
import * as routes from "./routes"
|
||||
import renderPage from "./pages"
|
||||
import { init } from "./init"
|
||||
import { assertConfig } from "./lib/assert"
|
||||
import { SessionStore } from "./lib/cookie"
|
||||
|
||||
import type { NextAuthOptions } from "./types"
|
||||
import type { NextAuthAction } from "../lib/types"
|
||||
import type { NextAuthAction, NextAuthOptions } from "./types"
|
||||
import type { Cookie } from "./lib/cookie"
|
||||
import type { ErrorType } from "./pages/error"
|
||||
|
||||
export interface IncomingRequest {
|
||||
export interface RequestInternal {
|
||||
/** @default "http://localhost:3000" */
|
||||
host?: string
|
||||
method?: string
|
||||
@@ -39,18 +39,55 @@ export interface OutgoingResponse<
|
||||
}
|
||||
|
||||
export interface NextAuthHandlerParams {
|
||||
req: IncomingRequest
|
||||
req: Request | RequestInternal
|
||||
options: NextAuthOptions
|
||||
}
|
||||
|
||||
async function getBody(req: Request): Promise<Record<string, any> | undefined> {
|
||||
try {
|
||||
return await req.json()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
async function toInternalRequest(
|
||||
req: RequestInternal | Request
|
||||
): Promise<RequestInternal> {
|
||||
if (req instanceof Request) {
|
||||
const url = new URL(req.url)
|
||||
// TODO: handle custom paths?
|
||||
const nextauth = url.pathname.split("/").slice(3)
|
||||
const headers = Object.fromEntries(req.headers.entries())
|
||||
const query: Record<string, any> = Object.fromEntries(
|
||||
url.searchParams.entries()
|
||||
)
|
||||
query.nextauth = nextauth
|
||||
|
||||
return {
|
||||
action: nextauth[0] as NextAuthAction,
|
||||
method: req.method,
|
||||
headers,
|
||||
body: await getBody(req),
|
||||
cookies: {},
|
||||
providerId: nextauth[1],
|
||||
error: url.searchParams.get("error") ?? nextauth[1],
|
||||
host: detectHost(headers["x-forwarded-host"] ?? headers.host),
|
||||
query,
|
||||
}
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
export async function NextAuthHandler<
|
||||
Body extends string | Record<string, any> | any[]
|
||||
>(params: NextAuthHandlerParams): Promise<OutgoingResponse<Body>> {
|
||||
const { options: userOptions, req } = params
|
||||
const { options: userOptions, req: incomingRequest } = params
|
||||
|
||||
const req = await toInternalRequest(incomingRequest)
|
||||
|
||||
setLogger(userOptions.logger, userOptions.debug)
|
||||
|
||||
const assertionResult = assertConfig(params)
|
||||
const assertionResult = assertConfig({ options: userOptions, req })
|
||||
|
||||
if (typeof assertionResult === "string") {
|
||||
logger.warn(assertionResult)
|
||||
@@ -108,7 +145,8 @@ export async function NextAuthHandler<
|
||||
let signinUrl = `${pages.signIn}${
|
||||
pages.signIn.includes("?") ? "&" : "?"
|
||||
}callbackUrl=${encodeURIComponent(options.callbackUrl)}`
|
||||
if (error) signinUrl = `${signinUrl}&error=${encodeURIComponent(error)}`
|
||||
if (error)
|
||||
signinUrl = `${signinUrl}&error=${encodeURIComponent(error)}`
|
||||
return { redirect: signinUrl, cookies }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { NextAuthOptions } from ".."
|
||||
import logger from "../lib/logger"
|
||||
import parseUrl from "../lib/parse-url"
|
||||
import { InternalOptions } from "../lib/types"
|
||||
import logger from "../utils/logger"
|
||||
import parseUrl from "../utils/parse-url"
|
||||
import { adapterErrorHandler, eventsErrorHandler } from "./errors"
|
||||
import parseProviders from "./lib/providers"
|
||||
import createSecret from "./lib/utils"
|
||||
@@ -10,7 +9,9 @@ import * as jwt from "../jwt"
|
||||
import { defaultCallbacks } from "./lib/default-callbacks"
|
||||
import { createCSRFToken } from "./lib/csrf-token"
|
||||
import { createCallbackUrl } from "./lib/callback-url"
|
||||
import { IncomingRequest } from "."
|
||||
import { RequestInternal } from "."
|
||||
|
||||
import type { InternalOptions } from "./types"
|
||||
|
||||
interface InitParams {
|
||||
host?: string
|
||||
@@ -23,7 +24,7 @@ interface InitParams {
|
||||
csrfToken?: string
|
||||
/** Is the incoming request a POST request? */
|
||||
isPost: boolean
|
||||
cookies: IncomingRequest["cookies"]
|
||||
cookies: RequestInternal["cookies"]
|
||||
}
|
||||
|
||||
/** Initialize all internal options and cookies. */
|
||||
|
||||
@@ -4,10 +4,13 @@ import {
|
||||
MissingAuthorize,
|
||||
MissingSecret,
|
||||
UnsupportedStrategy,
|
||||
InvalidCallbackUrl,
|
||||
} from "../errors"
|
||||
import parseUrl from "../../utils/parse-url"
|
||||
import { defaultCookies } from "./cookie"
|
||||
|
||||
import type { NextAuthHandlerParams } from ".."
|
||||
import type { WarningCode } from "../../lib/logger"
|
||||
import type { NextAuthHandlerParams, RequestInternal } from ".."
|
||||
import type { WarningCode } from "../../utils/logger"
|
||||
|
||||
type ConfigError =
|
||||
| MissingAPIRoute
|
||||
@@ -18,6 +21,16 @@ type ConfigError =
|
||||
|
||||
let twitterWarned = false
|
||||
|
||||
function isValidHttpUrl(url: string, baseUrl: string) {
|
||||
try {
|
||||
return /^https?:/.test(
|
||||
new URL(url, url.startsWith("/") ? baseUrl : undefined).protocol
|
||||
)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the user configured `next-auth` correctly.
|
||||
* Good place to mention deprecations as well.
|
||||
@@ -25,7 +38,9 @@ let twitterWarned = false
|
||||
* REVIEW: Make some of these and corresponding docs less Next.js specific?
|
||||
*/
|
||||
export function assertConfig(
|
||||
params: NextAuthHandlerParams
|
||||
params: NextAuthHandlerParams & {
|
||||
req: RequestInternal
|
||||
}
|
||||
): ConfigError | WarningCode | undefined {
|
||||
const { options, req } = params
|
||||
|
||||
@@ -44,8 +59,31 @@ export function assertConfig(
|
||||
}
|
||||
}
|
||||
|
||||
const callbackUrlParam = req.query?.callbackUrl as string | undefined
|
||||
|
||||
const url = parseUrl(req.host)
|
||||
|
||||
if (callbackUrlParam && !isValidHttpUrl(callbackUrlParam, url.base)) {
|
||||
return new InvalidCallbackUrl(
|
||||
`Invalid callback URL. Received: ${callbackUrlParam}`
|
||||
)
|
||||
}
|
||||
|
||||
// This is below the callbackUrlParam check because it would obscure the error
|
||||
if (!req.host) return "NEXTAUTH_URL"
|
||||
|
||||
const { callbackUrl: defaultCallbackUrl } = defaultCookies(
|
||||
options.useSecureCookies ?? url.base.startsWith("https://")
|
||||
)
|
||||
const callbackUrlCookie =
|
||||
req.cookies?.[options.cookies?.callbackUrl?.name ?? defaultCallbackUrl.name]
|
||||
|
||||
if (callbackUrlCookie && !isValidHttpUrl(callbackUrlCookie, url.base)) {
|
||||
return new InvalidCallbackUrl(
|
||||
`Invalid callback URL. Received: ${callbackUrlCookie}`
|
||||
)
|
||||
}
|
||||
|
||||
let hasCredentials, hasEmail
|
||||
let hasTwitterOAuth2
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { randomBytes, randomUUID } from "crypto"
|
||||
import { AccountNotLinkedError } from "../errors"
|
||||
import { fromDate } from "./utils"
|
||||
import { randomBytes, randomUUID } from "crypto"
|
||||
import { InternalOptions } from "../../lib/types"
|
||||
import { AdapterSession, AdapterUser } from "../../adapters"
|
||||
import { JWT } from "../../jwt"
|
||||
import { Account, User } from "../.."
|
||||
import { SessionToken } from "./cookie"
|
||||
|
||||
import type { InternalOptions } from "../types"
|
||||
import type { AdapterSession, AdapterUser } from "../../adapters"
|
||||
import type { JWT } from "../../jwt"
|
||||
import type { Account, User } from "../.."
|
||||
import type { SessionToken } from "./cookie"
|
||||
|
||||
/**
|
||||
* This function handles the complex flow of signing users in, and either creating,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { InternalOptions } from "../../lib/types"
|
||||
import type { InternalOptions } from "../types"
|
||||
|
||||
interface CreateCallbackUrlParams {
|
||||
options: InternalOptions
|
||||
|
||||
@@ -68,6 +68,7 @@ export function defaultCookies(useSecureCookies: boolean): CookiesOptions {
|
||||
callbackUrl: {
|
||||
name: `${cookiePrefix}next-auth.callback-url`,
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
secure: useSecureCookies,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createHash, randomBytes } from "crypto"
|
||||
import { InternalOptions } from "../../lib/types"
|
||||
|
||||
import type { InternalOptions } from "../types"
|
||||
|
||||
interface CreateCSRFTokenParams {
|
||||
options: InternalOptions
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { randomBytes } from "crypto"
|
||||
import { InternalOptions } from "../../../lib/types"
|
||||
import { hashToken } from "../utils"
|
||||
import type { InternalOptions } from "../../types"
|
||||
|
||||
/**
|
||||
* Starts an e-mail login flow, by generating a token,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { discoveryRequest, processDiscoveryResponse } from "@panva/oauth4webapi"
|
||||
|
||||
import type { AuthorizationServer } from "@panva/oauth4webapi"
|
||||
import type { InternalProvider } from "src/lib/types"
|
||||
|
||||
export default async function getAuthorizationServer(
|
||||
provider: InternalProvider<"oauth">
|
||||
): Promise<AuthorizationServer> {
|
||||
if (provider.idToken) {
|
||||
const issuer = new URL(provider.issuer as string)
|
||||
return await discoveryRequest(issuer).then(
|
||||
async (response) => await processDiscoveryResponse(issuer, response)
|
||||
)
|
||||
} else {
|
||||
return {
|
||||
issuer: provider.issuer as string,
|
||||
authorization_endpoint:
|
||||
typeof provider.authorization === "string"
|
||||
? provider.authorization
|
||||
: provider.authorization?.url,
|
||||
token_endpoint:
|
||||
typeof provider.token === "string"
|
||||
? provider.token
|
||||
: provider.token?.url,
|
||||
userinfo_endpoint:
|
||||
typeof provider.userinfo === "string"
|
||||
? provider.userinfo
|
||||
: provider.userinfo?.url,
|
||||
jwks_uri: provider.jwks_uri,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { openidClient } from "./client"
|
||||
import { oAuth1Client } from "./client-legacy"
|
||||
import { createState } from "./state-handler"
|
||||
import { createPKCE } from "./pkce-handler"
|
||||
import getAuthorizationServer from "./authorization-server"
|
||||
|
||||
import type { AuthorizationParameters } from "openid-client"
|
||||
import type { InternalOptions } from "../../../lib/types"
|
||||
import type { IncomingRequest } from "../.."
|
||||
import type { InternalOptions } from "../../types"
|
||||
import type { RequestInternal } from "../.."
|
||||
import type { Cookie } from "../cookie"
|
||||
|
||||
/**
|
||||
@@ -16,7 +16,7 @@ import type { Cookie } from "../cookie"
|
||||
*/
|
||||
export default async function getAuthorizationUrl(params: {
|
||||
options: InternalOptions<"oauth">
|
||||
query: IncomingRequest["query"]
|
||||
query: RequestInternal["query"]
|
||||
}) {
|
||||
const { options, query } = params
|
||||
const { logger, provider } = options
|
||||
@@ -50,28 +50,53 @@ export default async function getAuthorizationUrl(params: {
|
||||
return { redirect: url }
|
||||
}
|
||||
|
||||
const client = await openidClient(options)
|
||||
const authorizationServer = await getAuthorizationServer(provider)
|
||||
|
||||
if (!authorizationServer.authorization_endpoint) throw new Error()
|
||||
const authorizationUrl = new URL(authorizationServer.authorization_endpoint)
|
||||
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
authorizationUrl.searchParams.set(key, value as string)
|
||||
}
|
||||
|
||||
authorizationUrl.searchParams.set("client_id", provider.clientId as string)
|
||||
authorizationUrl.searchParams.set("redirect_uri", provider.callbackUrl)
|
||||
|
||||
if (typeof provider.authorization !== "string" && provider.authorization) {
|
||||
const { params: authorizationEndpointParams } = provider.authorization
|
||||
|
||||
if (typeof authorizationEndpointParams?.response_type === "string") {
|
||||
authorizationUrl.searchParams.set(
|
||||
"response_type",
|
||||
authorizationEndpointParams.response_type
|
||||
)
|
||||
}
|
||||
if (typeof authorizationEndpointParams?.scope === "string") {
|
||||
authorizationUrl.searchParams.set(
|
||||
"scope",
|
||||
authorizationEndpointParams.scope
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const authorizationParams: AuthorizationParameters = params
|
||||
const cookies: Cookie[] = []
|
||||
|
||||
const pkce = await createPKCE(options, authorizationServer)
|
||||
authorizationUrl.searchParams.set("code_challenge", pkce.code_challenge)
|
||||
authorizationUrl.searchParams.set(
|
||||
"code_challenge_method",
|
||||
pkce.code_challenge_method
|
||||
)
|
||||
cookies.push(pkce.cookie)
|
||||
|
||||
const state = await createState(options)
|
||||
if (state) {
|
||||
authorizationParams.state = state.value
|
||||
if (!pkce.isSupported && state) {
|
||||
authorizationUrl.searchParams.set("state", state.value)
|
||||
cookies.push(state.cookie)
|
||||
}
|
||||
|
||||
const pkce = await createPKCE(options)
|
||||
if (pkce) {
|
||||
authorizationParams.code_challenge = pkce.code_challenge
|
||||
authorizationParams.code_challenge_method = pkce.code_challenge_method
|
||||
cookies.push(pkce.cookie)
|
||||
}
|
||||
|
||||
const url = client.authorizationUrl(authorizationParams)
|
||||
|
||||
logger.debug("GET_AUTHORIZATION_URL", { url, cookies })
|
||||
return { redirect: url, cookies }
|
||||
logger.debug("GET_AUTHORIZATION_URL", { authorizationUrl, cookies })
|
||||
return { redirect: authorizationUrl.href, cookies }
|
||||
} catch (error) {
|
||||
logger.error("GET_AUTHORIZATION_URL_ERROR", error as Error)
|
||||
throw error
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
import { TokenSet } from "openid-client"
|
||||
import { openidClient } from "./client"
|
||||
import { oAuth1Client } from "./client-legacy"
|
||||
import { useState } from "./state-handler"
|
||||
import { usePKCECodeVerifier } from "./pkce-handler"
|
||||
import { OAuthCallbackError } from "../../errors"
|
||||
import {
|
||||
authorizationCodeGrantRequest,
|
||||
expectNoState,
|
||||
getValidatedIdTokenClaims,
|
||||
isOAuth2Error,
|
||||
processAuthorizationCodeOAuth2Response,
|
||||
processAuthorizationCodeOpenIDResponse,
|
||||
processUserInfoResponse,
|
||||
userInfoRequest,
|
||||
validateAuthResponse,
|
||||
} from "@panva/oauth4webapi"
|
||||
import getAuthorizationServer from "./authorization-server"
|
||||
|
||||
import type { CallbackParamsType } from "openid-client"
|
||||
import type { Account, LoggerInstance, Profile } from "../../.."
|
||||
import type { OAuthChecks, OAuthConfig } from "../../../providers"
|
||||
import type { InternalOptions } from "../../../lib/types"
|
||||
import type { IncomingRequest, OutgoingResponse } from "../.."
|
||||
import type { InternalOptions } from "../../types"
|
||||
import type { RequestInternal, OutgoingResponse } from "../.."
|
||||
import type { Cookie } from "../cookie"
|
||||
import type {
|
||||
OAuth2Error,
|
||||
OAuth2TokenEndpointResponse,
|
||||
OpenIDTokenEndpointResponse,
|
||||
} from "@panva/oauth4webapi"
|
||||
|
||||
export default async function oAuthCallback(params: {
|
||||
options: InternalOptions<"oauth">
|
||||
query: IncomingRequest["query"]
|
||||
body: IncomingRequest["body"]
|
||||
method: Required<IncomingRequest>["method"]
|
||||
cookies: IncomingRequest["cookies"]
|
||||
query: RequestInternal["query"]
|
||||
body: RequestInternal["body"]
|
||||
method: Required<RequestInternal>["method"]
|
||||
cookies: RequestInternal["cookies"]
|
||||
}): Promise<GetProfileResult & { cookies?: OutgoingResponse["cookies"] }> {
|
||||
const { options, query, body, method, cookies } = params
|
||||
const { options, query, body, cookies } = params
|
||||
const { logger, provider } = options
|
||||
|
||||
const errorMessage = body?.error ?? query?.error
|
||||
@@ -65,81 +80,111 @@ export default async function oAuthCallback(params: {
|
||||
}
|
||||
|
||||
try {
|
||||
const client = await openidClient(options)
|
||||
const client = openidClient(provider)
|
||||
const authorizationServer = await getAuthorizationServer(provider)
|
||||
|
||||
let tokens: TokenSet
|
||||
let tokens:
|
||||
| OpenIDTokenEndpointResponse
|
||||
| OAuth2TokenEndpointResponse
|
||||
| OAuth2Error
|
||||
|
||||
const checks: OAuthChecks = {}
|
||||
let expectedState: string | typeof expectNoState = expectNoState
|
||||
const resCookies: Cookie[] = []
|
||||
const authParams = new URLSearchParams(query)
|
||||
|
||||
const codeVerifier = cookies?.[options.cookies.pkceCodeVerifier.name]
|
||||
const pkce = await usePKCECodeVerifier(
|
||||
codeVerifier,
|
||||
options,
|
||||
authorizationServer
|
||||
)
|
||||
resCookies.push(pkce.cookie)
|
||||
|
||||
const state = await useState(cookies?.[options.cookies.state.name], options)
|
||||
|
||||
if (state) {
|
||||
checks.state = state.value
|
||||
if (!pkce.isSupported && state) {
|
||||
resCookies.push(state.cookie)
|
||||
expectedState = state.value
|
||||
authParams.append("state", state.value)
|
||||
}
|
||||
|
||||
const codeVerifier = cookies?.[options.cookies.pkceCodeVerifier.name]
|
||||
const pkce = await usePKCECodeVerifier(codeVerifier, options)
|
||||
if (pkce) {
|
||||
checks.code_verifier = pkce.codeVerifier
|
||||
resCookies.push(pkce.cookie)
|
||||
const callbackParameters = validateAuthResponse(
|
||||
authorizationServer,
|
||||
client,
|
||||
authParams,
|
||||
expectedState
|
||||
)
|
||||
if (isOAuth2Error(callbackParameters)) {
|
||||
throw new OAuthCallbackError(callbackParameters.error)
|
||||
}
|
||||
|
||||
const params: CallbackParamsType = {
|
||||
...client.callbackParams({
|
||||
url: `http://n?${new URLSearchParams(query)}`,
|
||||
// TODO: Ask to allow object to be passed upstream:
|
||||
// https://github.com/panva/node-openid-client/blob/3ae206dfc78c02134aa87a07f693052c637cab84/types/index.d.ts#L439
|
||||
// @ts-expect-error
|
||||
body,
|
||||
method,
|
||||
}),
|
||||
// @ts-expect-error
|
||||
...provider.token?.params,
|
||||
}
|
||||
const response = await authorizationCodeGrantRequest(
|
||||
authorizationServer,
|
||||
client,
|
||||
callbackParameters,
|
||||
provider.callbackUrl,
|
||||
pkce.codeVerifier
|
||||
)
|
||||
|
||||
// @ts-expect-error
|
||||
if (provider.token?.request) {
|
||||
// @ts-expect-error
|
||||
if (typeof provider.token !== "string" && provider.token?.request) {
|
||||
const params = {
|
||||
...callbackParameters,
|
||||
...provider.token?.params,
|
||||
}
|
||||
const checks = new URLSearchParams()
|
||||
if (state) checks.append("state", state.value)
|
||||
checks.append("code_verifier", pkce.codeVerifier)
|
||||
const response = await provider.token.request({
|
||||
provider,
|
||||
params,
|
||||
checks,
|
||||
client,
|
||||
})
|
||||
tokens = new TokenSet(response.tokens)
|
||||
tokens = response.tokens
|
||||
} else if (provider.idToken) {
|
||||
tokens = await client.callback(provider.callbackUrl, params, checks)
|
||||
tokens = await processAuthorizationCodeOpenIDResponse(
|
||||
authorizationServer,
|
||||
client,
|
||||
response
|
||||
)
|
||||
} else {
|
||||
tokens = await client.oauthCallback(provider.callbackUrl, params, checks)
|
||||
tokens = await processAuthorizationCodeOAuth2Response(
|
||||
authorizationServer,
|
||||
client,
|
||||
response
|
||||
)
|
||||
}
|
||||
|
||||
// REVIEW: How can scope be returned as an array?
|
||||
if (Array.isArray(tokens.scope)) {
|
||||
tokens.scope = tokens.scope.join(" ")
|
||||
if (isOAuth2Error(tokens)) {
|
||||
throw new OAuthCallbackError(tokens.error)
|
||||
}
|
||||
|
||||
let profile: Profile
|
||||
// @ts-expect-error
|
||||
if (provider.userinfo?.request) {
|
||||
// @ts-expect-error
|
||||
let profile: Profile | Response
|
||||
if (typeof provider.userinfo !== "string" && provider.userinfo?.request) {
|
||||
profile = await provider.userinfo.request({
|
||||
provider,
|
||||
tokens,
|
||||
client,
|
||||
})
|
||||
} else if (provider.idToken) {
|
||||
profile = tokens.claims()
|
||||
const idToken = getValidatedIdTokenClaims(tokens)
|
||||
|
||||
profile = await processUserInfoResponse(
|
||||
authorizationServer,
|
||||
client,
|
||||
idToken?.sub as string,
|
||||
response
|
||||
)
|
||||
} else {
|
||||
profile = await client.userinfo(tokens, {
|
||||
// @ts-expect-error
|
||||
params: provider.userinfo?.params,
|
||||
})
|
||||
profile = await userInfoRequest(
|
||||
authorizationServer,
|
||||
client,
|
||||
tokens.access_token
|
||||
)
|
||||
}
|
||||
|
||||
const profileResult = await getProfile({
|
||||
profile,
|
||||
profile: profile as Profile,
|
||||
provider,
|
||||
tokens,
|
||||
logger,
|
||||
@@ -156,7 +201,7 @@ export default async function oAuthCallback(params: {
|
||||
|
||||
export interface GetProfileParams {
|
||||
profile: Profile
|
||||
tokens: TokenSet
|
||||
tokens: OpenIDTokenEndpointResponse | OAuth2TokenEndpointResponse
|
||||
provider: OAuthConfig<any>
|
||||
logger: LoggerInstance
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// We have the intentions to provide only minor fixes for this in the future.
|
||||
|
||||
import { OAuth } from "oauth"
|
||||
import { InternalOptions } from "src/lib/types"
|
||||
import type { InternalOptions } from "../../types"
|
||||
|
||||
/**
|
||||
* Client supporting OAuth 1.x
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import { Issuer, Client, custom } from "openid-client"
|
||||
import { InternalOptions } from "src/lib/types"
|
||||
import { InternalProvider } from "src/lib/types"
|
||||
import type { Client as WebApiClient } from "@panva/oauth4webapi"
|
||||
import { Issuer, custom } from "openid-client"
|
||||
import type { Client } from "openid-client"
|
||||
import type { InternalOptions } from "../../types"
|
||||
|
||||
/**
|
||||
* NOTE: We can add auto discovery of the provider's endpoint
|
||||
* that requires only one endpoint to be specified by the user.
|
||||
* Check out `Issuer.discover`
|
||||
*
|
||||
* Client supporting OAuth 2.x and OIDC
|
||||
*/
|
||||
export function webApiClient(provider: InternalProvider<"oauth">): WebApiClient {
|
||||
return {
|
||||
client_id: provider.clientId as string,
|
||||
client_secret: provider.clientSecret as string,
|
||||
token_endpoint_auth_method: "client_secret_basic",
|
||||
...provider.client,
|
||||
}
|
||||
}
|
||||
export async function openidClient(
|
||||
options: InternalOptions<"oauth">
|
||||
): Promise<Client> {
|
||||
const provider = options.provider
|
||||
|
||||
|
||||
if (provider.httpOptions) custom.setHttpOptionsDefaults(provider.httpOptions)
|
||||
|
||||
|
||||
let issuer: Issuer
|
||||
if (provider.wellKnown) {
|
||||
issuer = await Issuer.discover(provider.wellKnown)
|
||||
@@ -30,21 +37,4 @@ export async function openidClient(
|
||||
userinfo_endpoint: provider.userinfo?.url ?? provider.userinfo,
|
||||
})
|
||||
}
|
||||
|
||||
const client = new issuer.Client(
|
||||
{
|
||||
client_id: provider.clientId as string,
|
||||
client_secret: provider.clientSecret as string,
|
||||
redirect_uris: [provider.callbackUrl],
|
||||
...provider.client,
|
||||
},
|
||||
provider.jwks
|
||||
)
|
||||
|
||||
// allow a 10 second skew
|
||||
// See https://github.com/nextauthjs/next-auth/issues/3032
|
||||
// and https://github.com/nextauthjs/next-auth/issues/3067
|
||||
client[custom.clock_tolerance] = 10
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user