mirror of
https://github.com/SrIzan10/next-auth.git
synced 2026-05-01 10:55:20 +00:00
Compare commits
10 Commits
feat/oauth
...
next-auth@
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b280a0b0b9 | ||
|
|
e03e234b86 | ||
|
|
66fb914a31 | ||
|
|
8ce728197f | ||
|
|
87d1a7af6d | ||
|
|
172813f987 | ||
|
|
cc934fceec | ||
|
|
46e467a7cb | ||
|
|
73d489beac | ||
|
|
e498483b23 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -69,7 +69,7 @@ jobs:
|
||||
git config --global user.name "Balázs Orbán"
|
||||
pnpm release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
NPM_TOKEN_PKG: ${{ secrets.NPM_TOKEN_PKG }}
|
||||
NPM_TOKEN_ORG: ${{ secrets.NPM_TOKEN_ORG }}
|
||||
release-pr:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// This is an example of how to protect content using server rendering
|
||||
import { getServerSession } from "next-auth/next"
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
import { authOptions } from "./api/auth/[...nextauth]"
|
||||
import Layout from "../components/layout"
|
||||
import AccessDenied from "../components/access-denied"
|
||||
@@ -26,7 +26,11 @@ export default function Page({ content, session }) {
|
||||
}
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await getServerSession(context, authOptions)
|
||||
const session = await unstable_getServerSession(
|
||||
context.req,
|
||||
context.res,
|
||||
authOptions
|
||||
)
|
||||
let content = null
|
||||
|
||||
if (session) {
|
||||
|
||||
@@ -65,7 +65,6 @@ You **can** skip configuring a database and come back to it later if you want.
|
||||
For more information about setting up a database, please check out the following links:
|
||||
|
||||
* Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||
* Adapters Repo: [nextauthjs/adapters](https://github.com/nextauthjs/adapters)
|
||||
|
||||
### 3. Configure Authentication Providers
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ You **can** skip configuring a database and come back to it later if you want.
|
||||
For more information about setting up a database, please check out the following links:
|
||||
|
||||
* Docs: [next-auth.js.org/adapters/overview](https://next-auth.js.org/adapters/overview)
|
||||
* Adapters Repo: [nextauthjs/adapters](https://github.com/nextauthjs/adapters)
|
||||
|
||||
### 3. Configure Authentication Providers
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"cookie": "0.4.1",
|
||||
"next-auth": "^4.3.3"
|
||||
"next-auth": "^4.5.0"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
|
||||
@@ -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.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==
|
||||
next-auth@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.5.0.tgz#2df57287fddc705b8971c88c60bad44a89ac6dd1"
|
||||
integrity sha512-B6gYRIbqtj8nlDsx3y2Ruwp/mvZnItPs7VUULY43QYw+M9xtDPIM9EBZ3ryd/wNYA3MDteBJlzGm/ivseXcmJA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.16.3"
|
||||
"@panva/hkdf" "^1.0.1"
|
||||
|
||||
@@ -1,5 +1,73 @@
|
||||
# Next.js
|
||||
|
||||
## `unstable_getServerSession`
|
||||
|
||||
:::warning
|
||||
This feature is experimental and may be removed or changed in the future.
|
||||
:::
|
||||
|
||||
When calling from server-side i.e. in API routes or in `getServerSideProps`, we recommend using this function instead of `getSession` to retrieve the `session` object. This method is especially useful when you are using NextAuth.js with a database. This method can _drastically_ reduce response time when used over `getSession` server-side, due to avoiding an extra `fetch` to an API Route (this is generally [not recommended in Next.js](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops-or-api-routes)). In addition, `unstable_getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
|
||||
|
||||
Otherwise, if you only want to get the session token, see [`getToken`](tutorials/securing-pages-and-api-routes#using-gettoken).
|
||||
|
||||
`unstable_getServerSession` requires passing the same object you would pass to `NextAuth` when initializing NextAuth.js. To do so, you can export your NextAuth.js options in the following way:
|
||||
|
||||
In `[...nextauth.js]`:
|
||||
```ts
|
||||
import { NextAuth } from 'next-auth'
|
||||
import type { NextAuthOptions } from 'next-auth'
|
||||
|
||||
export const authOptions: NextAuthOptions = {
|
||||
// your configs
|
||||
}
|
||||
|
||||
export default NextAuth(authOptions);
|
||||
```
|
||||
|
||||
In `getServerSideProps`:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
export async function getServerSideProps(context) {
|
||||
const session = await unstable_getServerSession(context.req, context.res, authOptions)
|
||||
|
||||
if (!session) {
|
||||
return {
|
||||
redirect: {
|
||||
destination: '/',
|
||||
permanent: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
session,
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
In API routes:
|
||||
```js
|
||||
import { authOptions } from 'pages/api/[...nextauth]'
|
||||
import { unstable_getServerSession } from "next-auth/next"
|
||||
|
||||
|
||||
export async function handler(req, res) {
|
||||
const session = await unstable_getServerSession(req, res, authOptions)
|
||||
|
||||
if (!session) {
|
||||
res.status(401).json({ message: "You must be logged in." });
|
||||
return;
|
||||
}
|
||||
|
||||
return res.json({
|
||||
message: 'Success',
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
## Middleware
|
||||
|
||||
You can use a Next.js Middleware with NextAuth.js to protect your site.
|
||||
|
||||
@@ -30,8 +30,8 @@ import GitHubProvider from "next-auth/providers/github";
|
||||
...
|
||||
providers: [
|
||||
GitHubProvider({
|
||||
clientId: process.env.GITHUB_CLIENT_ID,
|
||||
clientSecret: process.env.GITHUB_CLIENT_SECRET
|
||||
clientId: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET
|
||||
})
|
||||
]
|
||||
...
|
||||
|
||||
@@ -13,7 +13,7 @@ https://api.slack.com/docs/sign-in-with-slack
|
||||
https://api.slack.com/apps
|
||||
|
||||
:::warning
|
||||
Slack requires you that the redirect URL of your app uses `https`, even for local development. An easy workaround for this is using a service like [`ngrok`](https://ngrok.com) that creates a secure tunnel to your app, using `https`. Remember to set the url as `NEXTAUTH_URL` as well.
|
||||
Slack requires that the redirect URL of your app uses `https`, even for local development. An easy workaround for this is using a service like [`ngrok`](https://ngrok.com) that creates a secure tunnel to your app, using `https`. Remember to set the url as `NEXTAUTH_URL` as well.
|
||||
:::
|
||||
|
||||

|
||||
|
||||
@@ -33,6 +33,10 @@ In development, we generate a `secret` based on your configuration for convenien
|
||||
|
||||
Twitter OAuth 2.0 is currently in beta as certain changes might still be necessary. This is not covered by semver. See the docs https://next-auth.js.org/providers/twitter#oauth-2
|
||||
|
||||
#### EXPERIMENTAL_API
|
||||
|
||||
Some APIs are still experimental; they may be changed or removed in the future. Use at your own risk.
|
||||
|
||||
## Adapter
|
||||
|
||||
### ADAPTER_TYPEORM_UPDATING_ENTITIES
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<!-- <p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/prisma-adapter" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/prisma-adapter" alt="@next-auth/prisma-adapter Version" />
|
||||
</p> -->
|
||||
@@ -150,7 +150,7 @@ type User
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "1.0.3",
|
||||
"description": "Dgraph adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/adapters/issues"
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "Arnaud Derbey <arnaud@derbey.dev>",
|
||||
"contributors": [],
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="Build Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="Build Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/dynamodb-adapter/latest" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/dynamodb-adapter" alt="@next-auth/dynamodb-adapter Version" />
|
||||
</p>
|
||||
@@ -96,7 +96,7 @@ Here is a schema of the table :
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@next-auth/dynamodb-adapter",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"version": "1.0.3",
|
||||
"description": "AWS DynamoDB adapter for next-auth.",
|
||||
"keywords": [
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="Build Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="Build Test" />
|
||||
<a href="https://www.npmjs.com/package/@next-auth/faunadb-adapter" target="_blank"><img src="https://img.shields.io/bundlephobia/minzip/@next-auth/fauna-adapter/next" alt="Bundle Size"/></a>
|
||||
<a href="https://www.npmjs.com/package/@next-auth/faunadb-adapter" target="_blank"><img src="https://img.shields.io/npm/v/@next-auth/fauna-adapter/next" alt="@next-auth/fauna-adapter Version" /></a>
|
||||
</p>
|
||||
@@ -53,7 +53,7 @@ export default NextAuth({
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "1.0.3",
|
||||
"description": "Fauna Adapter for NextAuth",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="Build Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="Build Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/firebase-adapter/latest" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/firebase-adapter" alt="@next-auth/firebase-adapter Version" />
|
||||
</p>
|
||||
@@ -83,7 +83,7 @@ See [firebase.google.com/docs/web/setup](https://firebase.google.com/docs/web/se
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "0.1.3",
|
||||
"description": "Firebase adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/adapters/issues"
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "Ron Houben <ron.houben85@gmail.com>",
|
||||
"contributors": [
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<a href="https://www.npmjs.com/package/@next-auth/mikro-orm-adapter" target="_blank"><img src="https://img.shields.io/bundlephobia/minzip/@next-auth/mikro-orm-adapter/next" alt="Bundle Size"/></a>
|
||||
<a href="https://www.npmjs.com/package/@next-auth/mikro-orm-adapter" target="_blank"><img src="https://img.shields.io/npm/v/@next-auth/mikro-orm-adapter/next" alt="@next-auth/mikro-orm-adapter Version" /></a>
|
||||
</p>
|
||||
@@ -49,7 +49,7 @@ This is the MikroORM Adapter for [`next-auth`](https://next-auth.js.org). This p
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "2.0.1",
|
||||
"description": "MikroORM adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<a href="https://www.npmjs.com/package/@next-auth/mongodb-adapter" target="_blank"><img src="https://img.shields.io/bundlephobia/minzip/@next-auth/mongodb-adapter" alt="Bundle Size"/></a>
|
||||
<a href="https://www.npmjs.com/package/@next-auth/mongodb-adapter" target="_blank"><img src="https://img.shields.io/npm/v/@next-auth/mongodb-adapter" alt="@next-auth/mongodb-adapter Version" /></a>
|
||||
</p>
|
||||
@@ -79,7 +79,7 @@ export default NextAuth({
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "1.0.3",
|
||||
"description": "mongoDB adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="Canary CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="Canary CI Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/neo4j-adapter" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/neo4j-adapter" alt="@next-auth/neo4j-adapter Version" />
|
||||
</p>
|
||||
@@ -50,7 +50,7 @@ export default NextAuth({
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please first read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/canary/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please first read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/canary/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "1.0.3",
|
||||
"description": "neo4j adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/pouchdb-adapter" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/pouchdb-adapter" alt="@next-auth/pouchdb-adapter Version" />
|
||||
</p>
|
||||
@@ -71,7 +71,7 @@ For more details, please see https://pouchdb.com/api.html#sync
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.1.3",
|
||||
"description": "PouchDB adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<a href="https://www.npmjs.com/package/@next-auth/prisma-adapter" target="_blank"><img src="https://img.shields.io/bundlephobia/minzip/@next-auth/prisma-adapter/next" alt="Bundle Size"/></a>
|
||||
<a href="https://www.npmjs.com/package/@next-auth/prisma-adapter" target="_blank"><img src="https://img.shields.io/npm/v/@next-auth/prisma-adapter/next" alt="@next-auth/prisma-adapter Version" /></a>
|
||||
</p>
|
||||
@@ -48,7 +48,7 @@ export default NextAuth({
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "1.0.3",
|
||||
"description": "Prisma adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/sequelize-adapter" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/sequelize-adapter" alt="@next-auth/sequelize-adapter Version" />
|
||||
</p>
|
||||
@@ -89,7 +89,7 @@ export default NextAuth({
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "1.0.4",
|
||||
"description": "Sequelize adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/adapters/issues"
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "github.com/luke-j",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="Canary CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="Canary CI Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/typeorm-legacy-adapter/canary" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/typeorm-legacy-adapter" alt="@next-auth/typeorm-legacy-adapter Version" />
|
||||
</p>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "1.0.3",
|
||||
"description": "TypeORM (legacy) adapter for next-auth.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/adapters/issues"
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "Iain Collins",
|
||||
"contributors": [
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
Open Source. Full Stack. Own Your Data.
|
||||
</p>
|
||||
<p align="center" style="align: center;">
|
||||
<img src="https://github.com/nextauthjs/adapters/actions/workflows/release.yml/badge.svg" alt="CI Test" />
|
||||
<img src="https://github.com/nextauthjs/next-auth/actions/workflows/release.yml/badge.svg?branch=main" alt="CI Test" />
|
||||
<img src="https://img.shields.io/bundlephobia/minzip/@next-auth/upstash-adapter" alt="Bundle Size"/>
|
||||
<img src="https://img.shields.io/npm/v/@next-auth/upstash-adapter" alt="@next-auth/upstash-adapter Version" />
|
||||
</p>
|
||||
@@ -80,7 +80,7 @@ export default NextAuth({
|
||||
|
||||
## Contributing
|
||||
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/adapters/blob/main/CONTRIBUTING.md).
|
||||
We're open to all community contributions! If you'd like to contribute in any way, please read our [Contributing Guide](https://github.com/nextauthjs/next-auth/blob/main/CONTRIBUTING.md).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "3.0.0",
|
||||
"description": "Upstash adapter for next-auth. It uses Upstash's connectionless (HTTP based) Redis client.",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/adapters",
|
||||
"repository": "https://github.com/nextauthjs/next-auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/nextauthjs/adapters/issues"
|
||||
"url": "https://github.com/nextauthjs/next-auth/issues"
|
||||
},
|
||||
"author": "github.com/kay-is",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-auth",
|
||||
"version": "4.5.0",
|
||||
"version": "4.6.0",
|
||||
"description": "Authentication for Next.js",
|
||||
"homepage": "https://next-auth.js.org",
|
||||
"repository": "https://github.com/nextauthjs/next-auth.git",
|
||||
@@ -68,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"
|
||||
@@ -136,4 +136,4 @@
|
||||
"**/tests",
|
||||
"**/__tests__"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export interface VerificationToken {
|
||||
* - `deleteUser`
|
||||
* - `unlinkAccount`
|
||||
*
|
||||
* [Community adapters](https://github.com/nextauthjs/adapters) |
|
||||
* [Adapters Overview](https://next-auth.js.org/adapters/overview) |
|
||||
* [Create a custom adapter](https://next-auth.js.org/tutorials/creating-a-database-adapter)
|
||||
*/
|
||||
export interface Adapter {
|
||||
|
||||
@@ -44,7 +44,7 @@ export function assertConfig(
|
||||
): ConfigError | WarningCode | undefined {
|
||||
const { options, req } = params
|
||||
|
||||
// req.query isn't defined when asserting `getServerSession` for example
|
||||
// req.query isn't defined when asserting `unstable_getServerSession` for example
|
||||
if (!req.query?.nextauth && !req.action) {
|
||||
return new MissingAPIRoute(
|
||||
"Cannot find [...nextauth].{js,ts} in `/pages/api/auth`. Make sure the filename is written correctly."
|
||||
|
||||
@@ -120,7 +120,7 @@ export class SessionStore {
|
||||
constructor(
|
||||
option: CookieOption,
|
||||
req: {
|
||||
cookies?: Record<string, string>
|
||||
cookies?: Record<string, string> | { get: (key: string) => string }
|
||||
headers?: Headers | IncomingHttpHeaders | Record<string, string>
|
||||
},
|
||||
logger: LoggerInstance | Console
|
||||
@@ -132,7 +132,10 @@ export class SessionStore {
|
||||
|
||||
for (const name in req.cookies) {
|
||||
if (name.startsWith(option.name)) {
|
||||
this.#chunks[name] = req.cookies[name]
|
||||
this.#chunks[name] =
|
||||
typeof req.cookies.get === "function"
|
||||
? req.cookies.get(name)
|
||||
: req.cookies[name]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
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,7 +1,7 @@
|
||||
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 "../../types"
|
||||
@@ -50,53 +50,28 @@ export default async function getAuthorizationUrl(params: {
|
||||
return { redirect: url }
|
||||
}
|
||||
|
||||
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 client = await openidClient(options)
|
||||
|
||||
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 (!pkce.isSupported && state) {
|
||||
authorizationUrl.searchParams.set("state", state.value)
|
||||
if (state) {
|
||||
authorizationParams.state = state.value
|
||||
cookies.push(state.cookie)
|
||||
}
|
||||
|
||||
logger.debug("GET_AUTHORIZATION_URL", { authorizationUrl, cookies })
|
||||
return { redirect: authorizationUrl.href, cookies }
|
||||
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 }
|
||||
} catch (error) {
|
||||
logger.error("GET_AUTHORIZATION_URL_ERROR", error as Error)
|
||||
throw error
|
||||
|
||||
@@ -1,31 +1,16 @@
|
||||
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 "../../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">
|
||||
@@ -34,7 +19,7 @@ export default async function oAuthCallback(params: {
|
||||
method: Required<RequestInternal>["method"]
|
||||
cookies: RequestInternal["cookies"]
|
||||
}): Promise<GetProfileResult & { cookies?: OutgoingResponse["cookies"] }> {
|
||||
const { options, query, body, cookies } = params
|
||||
const { options, query, body, method, cookies } = params
|
||||
const { logger, provider } = options
|
||||
|
||||
const errorMessage = body?.error ?? query?.error
|
||||
@@ -80,111 +65,81 @@ export default async function oAuthCallback(params: {
|
||||
}
|
||||
|
||||
try {
|
||||
const client = openidClient(provider)
|
||||
const authorizationServer = await getAuthorizationServer(provider)
|
||||
const client = await openidClient(options)
|
||||
|
||||
let tokens:
|
||||
| OpenIDTokenEndpointResponse
|
||||
| OAuth2TokenEndpointResponse
|
||||
| OAuth2Error
|
||||
let tokens: TokenSet
|
||||
|
||||
let expectedState: string | typeof expectNoState = expectNoState
|
||||
const checks: OAuthChecks = {}
|
||||
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 (!pkce.isSupported && state) {
|
||||
if (state) {
|
||||
checks.state = state.value
|
||||
resCookies.push(state.cookie)
|
||||
expectedState = state.value
|
||||
authParams.append("state", state.value)
|
||||
}
|
||||
|
||||
const callbackParameters = validateAuthResponse(
|
||||
authorizationServer,
|
||||
client,
|
||||
authParams,
|
||||
expectedState
|
||||
)
|
||||
if (isOAuth2Error(callbackParameters)) {
|
||||
throw new OAuthCallbackError(callbackParameters.error)
|
||||
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 response = await authorizationCodeGrantRequest(
|
||||
authorizationServer,
|
||||
client,
|
||||
callbackParameters,
|
||||
provider.callbackUrl,
|
||||
pkce.codeVerifier
|
||||
)
|
||||
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,
|
||||
}
|
||||
|
||||
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)
|
||||
// @ts-expect-error
|
||||
if (provider.token?.request) {
|
||||
// @ts-expect-error
|
||||
const response = await provider.token.request({
|
||||
provider,
|
||||
params,
|
||||
checks,
|
||||
client,
|
||||
})
|
||||
tokens = response.tokens
|
||||
tokens = new TokenSet(response.tokens)
|
||||
} else if (provider.idToken) {
|
||||
tokens = await processAuthorizationCodeOpenIDResponse(
|
||||
authorizationServer,
|
||||
client,
|
||||
response
|
||||
)
|
||||
tokens = await client.callback(provider.callbackUrl, params, checks)
|
||||
} else {
|
||||
tokens = await processAuthorizationCodeOAuth2Response(
|
||||
authorizationServer,
|
||||
client,
|
||||
response
|
||||
)
|
||||
tokens = await client.oauthCallback(provider.callbackUrl, params, checks)
|
||||
}
|
||||
|
||||
if (isOAuth2Error(tokens)) {
|
||||
throw new OAuthCallbackError(tokens.error)
|
||||
// REVIEW: How can scope be returned as an array?
|
||||
if (Array.isArray(tokens.scope)) {
|
||||
tokens.scope = tokens.scope.join(" ")
|
||||
}
|
||||
|
||||
let profile: Profile | Response
|
||||
if (typeof provider.userinfo !== "string" && provider.userinfo?.request) {
|
||||
let profile: Profile
|
||||
// @ts-expect-error
|
||||
if (provider.userinfo?.request) {
|
||||
// @ts-expect-error
|
||||
profile = await provider.userinfo.request({
|
||||
provider,
|
||||
tokens,
|
||||
client,
|
||||
})
|
||||
} else if (provider.idToken) {
|
||||
const idToken = getValidatedIdTokenClaims(tokens)
|
||||
|
||||
profile = await processUserInfoResponse(
|
||||
authorizationServer,
|
||||
client,
|
||||
idToken?.sub as string,
|
||||
response
|
||||
)
|
||||
profile = tokens.claims()
|
||||
} else {
|
||||
profile = await userInfoRequest(
|
||||
authorizationServer,
|
||||
client,
|
||||
tokens.access_token
|
||||
)
|
||||
profile = await client.userinfo(tokens, {
|
||||
// @ts-expect-error
|
||||
params: provider.userinfo?.params,
|
||||
})
|
||||
}
|
||||
|
||||
const profileResult = await getProfile({
|
||||
profile: profile as Profile,
|
||||
profile,
|
||||
provider,
|
||||
tokens,
|
||||
logger,
|
||||
@@ -201,7 +156,7 @@ export default async function oAuthCallback(params: {
|
||||
|
||||
export interface GetProfileParams {
|
||||
profile: Profile
|
||||
tokens: OpenIDTokenEndpointResponse | OAuth2TokenEndpointResponse
|
||||
tokens: TokenSet
|
||||
provider: OAuthConfig<any>
|
||||
logger: LoggerInstance
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
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> {
|
||||
@@ -37,4 +31,21 @@ 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
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import { generateRandomCodeVerifier } from "@panva/oauth4webapi"
|
||||
|
||||
/**
|
||||
* Generate random `state` value encoded as base64url. This method returns oauth4webapi's `generateRandomCodeVerifier` for convenience.
|
||||
* @see {@link https://github.com/panva/oauth4webapi/blob/main/docs/functions/generateRandomCodeVerifier.md generateRandomCodeVerifier.}
|
||||
*/
|
||||
export function generateRandomState() {
|
||||
return generateRandomCodeVerifier()
|
||||
}
|
||||
@@ -1,43 +1,30 @@
|
||||
import * as jwt from "../../../jwt"
|
||||
import {
|
||||
generateRandomCodeVerifier,
|
||||
calculatePKCECodeChallenge,
|
||||
} from "@panva/oauth4webapi"
|
||||
import { generators } from "openid-client"
|
||||
import type { InternalOptions } from "../../types"
|
||||
import type { Cookie } from "../cookie"
|
||||
import type { AuthorizationServer } from "@panva/oauth4webapi"
|
||||
|
||||
const PKCE_CODE_CHALLENGE_METHOD = "S256"
|
||||
const PKCE_MAX_AGE = 60 * 15 // 15 minutes in seconds
|
||||
|
||||
/**
|
||||
* Check if PKCE is supported by the authorization server.
|
||||
* @see {@link https://datatracker.ietf.org/doc/html/rfc8414#section-2 code_challenge_methods_supported}
|
||||
* @param as The authorization server. @see {@link https://github.com/panva/oauth4webapi/blob/main/docs/interfaces/AuthorizationServer.md AuthorizationServer}
|
||||
*/
|
||||
function isPKCESupported(as: AuthorizationServer) {
|
||||
return !!as.code_challenge_methods_supported?.includes(
|
||||
PKCE_CODE_CHALLENGE_METHOD
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `code_challenge` and `code_challenge_method`
|
||||
* and saves them in a cookie.
|
||||
*/
|
||||
export async function createPKCE(
|
||||
options: InternalOptions<"oauth">,
|
||||
as: AuthorizationServer
|
||||
): Promise<{
|
||||
code_challenge: string
|
||||
code_challenge_method: "S256"
|
||||
cookie: Cookie
|
||||
isSupported: boolean
|
||||
}> {
|
||||
const { cookies, logger } = options
|
||||
const code_verifier = generateRandomCodeVerifier()
|
||||
const code_challenge = await calculatePKCECodeChallenge(code_verifier)
|
||||
export async function createPKCE(options: InternalOptions<"oauth">): Promise<
|
||||
| undefined
|
||||
| {
|
||||
code_challenge: string
|
||||
code_challenge_method: "S256"
|
||||
cookie: Cookie
|
||||
}
|
||||
> {
|
||||
const { cookies, logger, provider } = options
|
||||
if (!provider.checks?.includes("pkce")) {
|
||||
// Provider does not support PKCE, return nothing.
|
||||
return
|
||||
}
|
||||
const code_verifier = generators.codeVerifier()
|
||||
const code_challenge = generators.codeChallenge(code_verifier)
|
||||
|
||||
const expires = new Date()
|
||||
expires.setTime(expires.getTime() + PKCE_MAX_AGE * 1000)
|
||||
@@ -64,37 +51,34 @@ export async function createPKCE(
|
||||
value: encryptedCodeVerifier,
|
||||
options: { ...cookies.pkceCodeVerifier.options, expires },
|
||||
},
|
||||
isSupported: isPKCESupported(as),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns `code_verifier`,
|
||||
* Returns code_verifier if provider uses PKCE,
|
||||
* and clears the container cookie afterwards.
|
||||
*/
|
||||
export async function usePKCECodeVerifier(
|
||||
codeVerifier: string | undefined,
|
||||
options: InternalOptions<"oauth">,
|
||||
as: AuthorizationServer
|
||||
): Promise<{ codeVerifier: string; cookie: Cookie; isSupported: boolean }> {
|
||||
if (codeVerifier === undefined) throw new Error("Invalid code verifier")
|
||||
options: InternalOptions<"oauth">
|
||||
): Promise<{ codeVerifier: string; cookie: Cookie } | undefined> {
|
||||
const { cookies, provider } = options
|
||||
|
||||
const { cookies } = options
|
||||
if (!provider?.checks?.includes("pkce") || !codeVerifier) {
|
||||
return
|
||||
}
|
||||
|
||||
const pkce = await jwt.decode({
|
||||
const pkce = (await jwt.decode({
|
||||
...options.jwt,
|
||||
token: codeVerifier,
|
||||
})
|
||||
|
||||
if (pkce === null) throw new Error("Invalid code verifier")
|
||||
})) as any
|
||||
|
||||
return {
|
||||
codeVerifier: pkce.code_verifier as string,
|
||||
codeVerifier: pkce?.code_verifier ?? undefined,
|
||||
cookie: {
|
||||
name: cookies.pkceCodeVerifier.name,
|
||||
value: "",
|
||||
options: { ...cookies.pkceCodeVerifier.options, maxAge: 0 },
|
||||
},
|
||||
isSupported: isPKCESupported(as),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import { generators } from "openid-client"
|
||||
|
||||
import type { InternalOptions } from "../../types"
|
||||
import type { Cookie } from "../cookie"
|
||||
import { generateRandomState } from "./helper"
|
||||
|
||||
const STATE_MAX_AGE = 60 * 15 // 15 minutes in seconds
|
||||
|
||||
@@ -17,7 +16,7 @@ export async function createState(
|
||||
return
|
||||
}
|
||||
|
||||
const state = generateRandomState()
|
||||
const state = generators.state()
|
||||
|
||||
const encodedState = await jwt.encode({
|
||||
...jwt,
|
||||
|
||||
@@ -11,7 +11,6 @@ import type { TokenSetParameters } from "openid-client"
|
||||
import type { JWT, JWTOptions } from "../jwt"
|
||||
import type { LoggerInstance } from "../utils/logger"
|
||||
import type { CookieSerializeOptions } from "cookie"
|
||||
import type { TokenEndpointResponse } from "@panva/oauth4webapi"
|
||||
|
||||
import type { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
@@ -118,7 +117,7 @@ export interface NextAuthOptions {
|
||||
* * **Required**: *No*
|
||||
*
|
||||
* [Documentation](https://next-auth.js.org/configuration/options#adapter) |
|
||||
* [Community adapters](https://github.com/nextauthjs/adapters)
|
||||
* [Adapters Overview](https://next-auth.js.org/adapters/overview)
|
||||
*/
|
||||
adapter?: Adapter
|
||||
/**
|
||||
@@ -225,7 +224,7 @@ export interface Theme {
|
||||
* Some of them are available with different casing,
|
||||
* but they refer to the same value.
|
||||
*/
|
||||
export type TokenSet = TokenEndpointResponse
|
||||
export type TokenSet = TokenSetParameters
|
||||
|
||||
/**
|
||||
* Usually contains information about the provider being used
|
||||
|
||||
@@ -67,7 +67,7 @@ function NextAuth(
|
||||
options: NextAuthOptions
|
||||
): any
|
||||
|
||||
/** Tha main entry point to next-auth */
|
||||
/** The main entry point to next-auth */
|
||||
function NextAuth(
|
||||
...args:
|
||||
| [NextAuthOptions]
|
||||
@@ -83,26 +83,33 @@ function NextAuth(
|
||||
|
||||
export default NextAuth
|
||||
|
||||
export async function getServerSession(
|
||||
context:
|
||||
| GetServerSidePropsContext
|
||||
| { req: NextApiRequest; res: NextApiResponse },
|
||||
options: NextAuthOptions
|
||||
export async function unstable_getServerSession(
|
||||
...args:
|
||||
| [GetServerSidePropsContext['req'], GetServerSidePropsContext['res'], NextAuthOptions]
|
||||
| [NextApiRequest, NextApiResponse, NextAuthOptions]
|
||||
): Promise<Session | null> {
|
||||
console.warn(
|
||||
"[next-auth][warn][EXPERIMENTAL_API]",
|
||||
"\n`unstable_getServerSession` is experimental and may be removed or changed in the future, as the name suggested.",
|
||||
`\nhttps://next-auth.js.org/configuration/nextjs#unstable_getServerSession}`,
|
||||
`\nhttps://next-auth.js.org/warnings#EXPERIMENTAL_API`
|
||||
)
|
||||
|
||||
const [req, res, options] = args;
|
||||
const session = await NextAuthHandler<Session | {}>({
|
||||
options,
|
||||
req: {
|
||||
host: detectHost(context.req.headers["x-forwarded-host"]),
|
||||
host: detectHost(req.headers["x-forwarded-host"]),
|
||||
action: "session",
|
||||
method: "GET",
|
||||
cookies: context.req.cookies,
|
||||
headers: context.req.headers,
|
||||
cookies: req.cookies,
|
||||
headers: req.headers,
|
||||
},
|
||||
})
|
||||
|
||||
const { body, cookies } = session
|
||||
|
||||
cookies?.forEach((cookie) => setCookie(context.res, cookie))
|
||||
cookies?.forEach((cookie) => setCookie(res, cookie))
|
||||
|
||||
if (body && Object.keys(body).length) return body as Session
|
||||
return null
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AuthorizationServer, userInfoRequest } from "@panva/oauth4webapi"
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
|
||||
interface FacebookPictureData {
|
||||
@@ -27,17 +26,11 @@ export default function Facebook<P extends FacebookProfile>(
|
||||
// https://developers.facebook.com/docs/graph-api/reference/user/#fields
|
||||
params: { fields: "id,name,email,picture" },
|
||||
async request({ tokens, client, provider }) {
|
||||
// @ts-expect-error
|
||||
const userinfo_endpoint = new URL(provider.userinfo?.url)
|
||||
// @ts-expect-error
|
||||
Object.entries(provider.userinfo?.params).forEach(([key, value]) => {
|
||||
userinfo_endpoint.searchParams.append(key, value as string)
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return await client.userinfo(tokens.access_token!, {
|
||||
// @ts-expect-error
|
||||
params: provider.userinfo?.params,
|
||||
})
|
||||
const as: AuthorizationServer = {
|
||||
issuer: options.issuer as string,
|
||||
userinfo_endpoint: userinfo_endpoint.href,
|
||||
}
|
||||
return await userInfoRequest(as, client, tokens.access_token)
|
||||
},
|
||||
},
|
||||
profile(profile: P) {
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
import type { CommonProviderOptions } from "../providers"
|
||||
import type { Profile, TokenSet, User, Awaitable } from ".."
|
||||
|
||||
import type {
|
||||
AuthorizationParameters,
|
||||
CallbackParamsType,
|
||||
Issuer,
|
||||
ClientMetadata,
|
||||
IssuerMetadata,
|
||||
OAuthCallbackChecks,
|
||||
OpenIDCallbackChecks,
|
||||
HttpOptions,
|
||||
} from "openid-client"
|
||||
import type { JWK } from "jose"
|
||||
import type { AuthorizationServer, Client } from "@panva/oauth4webapi"
|
||||
|
||||
type Client = InstanceType<Issuer["Client"]>
|
||||
|
||||
export type { OAuthProviderType } from "./oauth-types"
|
||||
|
||||
type ChecksType = "pkce" | "state" | "none"
|
||||
|
||||
type PartialIssuer = Partial<Pick<AuthorizationServer, "jwks_uri" | "issuer">>
|
||||
export type OAuthChecks = OpenIDCallbackChecks | OAuthCallbackChecks
|
||||
|
||||
type PartialIssuer = Partial<Pick<IssuerMetadata, "jwks_endpoint" | "issuer">>
|
||||
|
||||
type UrlParams = Record<string, unknown>
|
||||
|
||||
type EndpointRequest<C, R, P> = (
|
||||
context: C & {
|
||||
/** `oauth4webapi` Client */
|
||||
/** `openid-client` Client */
|
||||
client: Client
|
||||
/** Provider is passed for convenience, ans also contains the `callbackUrl`. */
|
||||
provider: OAuthConfig<P> & {
|
||||
@@ -48,7 +61,8 @@ export type EndpointHandler<
|
||||
R = any
|
||||
> = AdvancedEndpointHandler<P, C, R>
|
||||
|
||||
export type AuthorizationEndpointHandler = EndpointHandler<UrlParams>
|
||||
export type AuthorizationEndpointHandler =
|
||||
EndpointHandler<AuthorizationParameters>
|
||||
|
||||
export type TokenEndpointHandler = EndpointHandler<
|
||||
UrlParams,
|
||||
@@ -57,12 +71,12 @@ export type TokenEndpointHandler = EndpointHandler<
|
||||
* Parameters extracted from the request to the `/api/auth/callback/:providerId` endpoint.
|
||||
* Contains params like `state`.
|
||||
*/
|
||||
params: URLSearchParams
|
||||
params: CallbackParamsType
|
||||
/**
|
||||
* When using this custom flow, make sure to do all the necessary security checks.
|
||||
* This object contains parameters you have to match against the request to make sure it is valid.
|
||||
* Thist object contains parameters you have to match against the request to make sure it is valid.
|
||||
*/
|
||||
checks: URLSearchParams
|
||||
checks: OAuthChecks
|
||||
},
|
||||
{
|
||||
tokens: TokenSet
|
||||
@@ -72,7 +86,7 @@ export type TokenEndpointHandler = EndpointHandler<
|
||||
export type UserinfoEndpointHandler = EndpointHandler<
|
||||
UrlParams,
|
||||
{ tokens: TokenSet },
|
||||
Profile | Response
|
||||
Profile
|
||||
>
|
||||
|
||||
export interface OAuthConfig<P> extends CommonProviderOptions, PartialIssuer {
|
||||
@@ -98,7 +112,7 @@ export interface OAuthConfig<P> extends CommonProviderOptions, PartialIssuer {
|
||||
version?: string
|
||||
profile?: (profile: P, tokens: TokenSet) => Awaitable<User & { id: string }>
|
||||
checks?: ChecksType | ChecksType[]
|
||||
client?: Partial<Client>
|
||||
client?: Partial<ClientMetadata>
|
||||
jwks?: { keys: JWK[] }
|
||||
clientId?: string
|
||||
clientSecret?: string
|
||||
@@ -114,6 +128,11 @@ export interface OAuthConfig<P> extends CommonProviderOptions, PartialIssuer {
|
||||
idToken?: boolean
|
||||
// TODO: only allow for BattleNet
|
||||
region?: string
|
||||
// TODO: only allow for some
|
||||
issuer?: string
|
||||
/** Read more at: https://github.com/panva/node-openid-client/tree/main/docs#customizing-http-requests */
|
||||
httpOptions?: HttpOptions
|
||||
|
||||
/**
|
||||
* The options provided by the user.
|
||||
* We will perform a deep-merge of these values
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import type { OAuthConfig, OAuthUserConfig } from "."
|
||||
import {
|
||||
authorizationCodeGrantRequest,
|
||||
AuthorizationServer,
|
||||
isOAuth2Error,
|
||||
processAuthorizationCodeOAuth2Response,
|
||||
} from "@panva/oauth4webapi"
|
||||
|
||||
export interface TwitterLegacyProfile {
|
||||
id: number
|
||||
@@ -189,33 +183,13 @@ export default function Twitter<
|
||||
url: "https://api.twitter.com/2/oauth2/token",
|
||||
// TODO: Remove this
|
||||
async request({ client, params, checks, provider }) {
|
||||
const as: AuthorizationServer = {
|
||||
issuer: options.issuer as string,
|
||||
// @ts-expect-error
|
||||
token_endpoint: provider.token?.url,
|
||||
}
|
||||
const additionalParameters = new URLSearchParams()
|
||||
additionalParameters.append("client_id", options.clientId)
|
||||
const response = await authorizationCodeGrantRequest(
|
||||
as,
|
||||
client,
|
||||
params,
|
||||
const response = await client.oauthCallback(
|
||||
provider.callbackUrl,
|
||||
checks.get("code_verifier") as string,
|
||||
{
|
||||
additionalParameters,
|
||||
}
|
||||
params,
|
||||
checks,
|
||||
{ exchangeBody: { client_id: options.clientId } }
|
||||
)
|
||||
const tokens = await processAuthorizationCodeOAuth2Response(
|
||||
as,
|
||||
client,
|
||||
response
|
||||
)
|
||||
|
||||
if (isOAuth2Error(tokens)) {
|
||||
throw new Error()
|
||||
}
|
||||
return { tokens }
|
||||
return { tokens: response }
|
||||
},
|
||||
},
|
||||
userinfo: {
|
||||
|
||||
@@ -175,7 +175,7 @@ export async function getProviders() {
|
||||
export async function signIn<
|
||||
P extends RedirectableProviderType | undefined = undefined
|
||||
>(
|
||||
provider?: LiteralUnion<BuiltInProviderType>,
|
||||
provider?: LiteralUnion<P extends RedirectableProviderType ? P | BuiltInProviderType : BuiltInProviderType>,
|
||||
options?: SignInOptions,
|
||||
authorizationParams?: SignInAuthorizationParams
|
||||
): Promise<
|
||||
|
||||
@@ -13,6 +13,22 @@ it("Show error page if secret is not defined", async () => {
|
||||
expect(log.error).toBeCalledWith("NO_SECRET", expect.anything())
|
||||
})
|
||||
|
||||
it("Should show configuration error page on invalid `callbackUrl`", async () => {
|
||||
const { res, log } = await handler(
|
||||
{ providers: [] },
|
||||
{ prod: true, params: { callbackUrl: "invalid-callback" } }
|
||||
)
|
||||
|
||||
expect(res.status).toBe(500)
|
||||
expect(res.html).toMatch(/there is a problem with the server configuration./i)
|
||||
expect(res.html).toMatch(/check the server logs for more information./i)
|
||||
|
||||
expect(log.error).toBeCalledWith(
|
||||
"INVALID_CALLBACK_URL_ERROR",
|
||||
expect.anything()
|
||||
)
|
||||
})
|
||||
|
||||
it("Allow relative `callbackUrl`", async () => {
|
||||
const { res, log } = await handler(
|
||||
{ providers: [] },
|
||||
|
||||
12232
pnpm-lock.yaml
generated
12232
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user