Compare commits

...

29 Commits

Author SHA1 Message Date
Thang Vu
2510f74809 chore(release): bump version [skip ci] 2023-10-02 18:57:37 +07:00
Thang Vu
27b2519b84 fix(next): returns correct status for signing in with redirect: false for route handler (#8775)
* fix: returns status for signing in with credentials provider `redirect: false`

* chore: format cookie.ts
2023-10-02 18:48:36 +07:00
Ahmed Abdelbaset
5f15b0704a docs: fix typo (#8767)
fix typo
2023-10-02 01:03:25 +01:00
Balázs Orbán
e4573ffff5 docs: typo 2023-10-02 01:37:14 +02:00
Balázs Orbán
4ce1951a2b docs: close admonition 2023-10-02 01:34:55 +02:00
Balázs Orbán
c95531d651 docs: mention auth() convention under getServerSession 2023-10-02 01:32:35 +02:00
Balázs Orbán
654d52bb56 docs: mention getServerSession under SessionProvider 2023-10-02 01:27:35 +02:00
Herbie Vine
b72d7be9be docs: set decode fn not jwt obj (#8742)
Co-authored-by: Balázs Orbán <info@balazsorban.com>
2023-09-29 15:36:32 +02:00
Balázs Orbán
76fcc4e70c chore: don't sync example from v4 branch 2023-09-27 12:49:25 +02:00
Balázs Orbán
4cacf504dd docs: clarify pages in middleware 2023-09-26 13:23:04 +02:00
Balázs Orbán
50eb23f626 fix: update security policy link 2023-09-25 11:30:27 +02:00
Balázs Orbán
d813c00b3e fix(ts): fix typo 2023-09-20 19:48:30 +01:00
Soheil Nazari
fc4448a85a docs: add extra tips for next app router (#8227)
* Update example.md

* Update example.md

* Update example.md

* Update docs/docs/getting-started/example.md

* Update docs/docs/getting-started/example.md

* Update docs/docs/getting-started/example.md

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-20 13:46:47 +07:00
Thang Vu
16f781c091 chore: update email 2023-09-16 12:07:27 +07:00
Jared Wyce
ebfdaece0e fix: remove trailing ? from signIn URL (#8466)
* fix: 🎣 avoid phishing categorization by VPNs

* Update packages/next-auth/src/react/index.tsx

* Update packages/next-auth/src/react/index.tsx

---------

Co-authored-by: Thang Vu <hi@thvu.dev>
2023-09-06 12:55:03 +07:00
Devdat Kumar
64a190e549 docs: Update adapters.md (#8397)
"Drizzle" and "Kysely" links have been added to the list, and the list has been sorted.

https://next-auth.js.org/adapters
2023-08-24 10:23:41 +01:00
Arif Shanji
e11f898c10 docs: typo (#8366) 2023-08-21 13:53:35 +02:00
Balázs Orbán
dcb11da2e2 docs: update error page
closes #8174
2023-08-18 09:22:25 +01:00
Thang Vu
9f900befe6 chore(release): bump version [skip ci] 2023-08-16 14:43:26 +07:00
Gabriel Villenave
09c2a89df8 fix: use default submodules export in package.json (#8330)
Use `default` submodules export in `package.json` to ensure compatibility, as specified in https://nodejs.org/api/packages.html#conditional-exports
2023-08-16 09:33:07 +02:00
Balázs Orbán
20c3fe3331 fix(ts): correctly expose next-auth/adapters
Fixes https://github.com/nextauthjs/next-auth/issues/8283#issuecomment-1675939280
2023-08-12 16:37:18 +02:00
Manuel Cattelan
e26f500d18 docs(providers): add warning for gitlab provider (#8292) 2023-08-11 13:56:56 +02:00
Balázs Orbán
494d16e54d chore(release): bump version [skip ci] 2023-08-11 13:43:03 +02:00
Balázs Orbán
5a8aa2e5e5 feat(providers): add Passage by 1Password 2023-08-11 13:39:52 +02:00
Balázs Orbán
05ff6ae221 fix(ts): correctly export submodule types 2023-08-11 11:31:35 +02:00
Jonathan Edenström
1fbc684f53 fix: sort cookie chunks correctly (#8284) 2023-08-10 12:17:41 +01:00
Balázs Orbán
124be4fb1f chore(release): bump version [skip ci] 2023-08-08 19:21:49 +02:00
Balázs Orbán
3b0128c3ca fix(ts): match next-auth/adapter & @auth/core/adapters 2023-08-08 19:20:30 +02:00
Balázs Orbán
36b97aafb8 docs: amplify note 2023-08-08 18:00:41 +02:00
19 changed files with 182 additions and 73 deletions

7
.github/sync.yml vendored
View File

@@ -1,7 +0,0 @@
# This is a legacy example pushed from the v4 branch
nextauthjs/next-auth-example:
- source: apps/example-nextjs
dest: .
deleteOrphaned: true
- .github/FUNDING.yml
- LICENSE

View File

@@ -1,18 +0,0 @@
name: Sync Example Repositories
on:
push:
branches:
- v4
workflow_dispatch:
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Run GitHub File Sync
# Can update to v1 when https://github.com/BetaHuhn/repo-file-sync-action/issues/168 is resolved
uses: BetaHuhn/repo-file-sync-action@v1.16.5
with:
GH_PAT: ${{ secrets.GH_PAT_CLASSIC }}
SKIP_PR: true

View File

@@ -6,16 +6,18 @@ title: Adapters
Visit the [authjs.dev](https://authjs.dev/reference/adapters) page for the up-to-date documentation.
- [Dgraph](https://authjs.dev/reference/adapter/dgraph)
- [Drizzle](https://authjs.dev/reference/adapter/drizzle)
- [DynamoDB](https://authjs.dev/reference/adapter/dynamodb)
- [Fauna](https://authjs.dev/reference/adapter/fauna)
- [Firebase](https://authjs.dev/reference/adapter/firebase)
- [MongoDB](https://authjs.dev/reference/adapter/mongodb)
- [Prisma](https://authjs.dev/reference/adapter/prisma)
- [TypeORM](https://authjs.dev/reference/adapter/typeorm)
- [kysely](https://authjs.dev/reference/adapter/kysely)
- [MikroORM](https://authjs.dev/reference/adapter/mikro-orm)
- [MongoDB](https://authjs.dev/reference/adapter/mongodb)
- [neo4j](https://authjs.dev/reference/adapter/neo4j)
- [Prisma](https://authjs.dev/reference/adapter/prisma)
- [PouchDB](https://authjs.dev/reference/adapter/pouchdb)
- [Sequelize](https://authjs.dev/reference/adapter/sequelize)
- [Supabase](https://authjs.dev/reference/adapter/supabase)
- [TypeORM](https://authjs.dev/reference/adapter/typeorm)
- [Upstash Redis](https://authjs.dev/reference/adapter/upstash-redis)
- [Xata](https://authjs.dev/reference/adapter/xata)

View File

@@ -2,6 +2,27 @@
## `getServerSession`
:::tip
You can create a helper function so you don't need to pass `authOptions` around:
```ts title=auth.ts
import type { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from "next"
import type { NextAuthOptions } from "next-auth"
import { getServerSession } from "next-auth"
// You'll need to import and pass this
// to `NextAuth` in `app/api/auth/[...nextauth]/route.ts`
export const config = {
providers: [], // rest of your config
} satisfies NextAuthOptions
// Use it in server contexts
export function auth(...args: [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]] | [NextApiRequest, NextApiResponse] | []) {
return getServerSession(...args, config)
}
```
:::
When calling from the server-side i.e. in Route Handlers, React Server Components, 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` on 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, `getServerSession` will correctly update the cookie expiry time and update the session content if `callbacks.jwt` or `callbacks.session` changed something.
`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:
@@ -157,22 +178,27 @@ Callbacks are asynchronous functions you can use to control what happens when an
#### Description
Specify URLs to be used if you want to create custom sign in, and error pages. Pages specified will override the corresponding built-in page.
Specify URLs to be used if you want to create custom sign-in and error pages. The pages specified will override the corresponding built-in page.
:::note
This should match the `pages` configuration that's found in `[...nextauth].ts`.
:::info
The `pages` configuration should match the same configuration in `[...nextauth].ts`. This is so that the `next-auth` Middleware is aware of your custom pages, so it won't end up redirecting to itself when an unauthenticated condition is met.
:::
#### Example (default value)
```js
pages: {
signIn: '/api/auth/signin',
error: '/api/auth/error',
}
import { withAuth } from "next-auth/middleware"
export default withAuth({
// Matches the pages config in `[...nextauth]`
pages: {
signIn: '/login',
error: '/error',
}
})
```
See the documentation for the [pages option](/configuration/pages) for more information.
For more information, see the documentation for the [pages option](/configuration/pages).
---
@@ -182,7 +208,7 @@ See the documentation for the [pages option](/configuration/pages) for more info
#### Description
The same `secret` used in the [NextAuth.js config](/configuration/options#options).
The same `secret` is used in the [NextAuth.js config](/configuration/options#options).
#### Example (default value)
@@ -255,7 +281,7 @@ import withAuth from "next-auth/middleware"
import { authOptions } from "pages/api/auth/[...nextauth]";
export default withAuth({
jwt: { decode: authOptions.jwt },
jwt: { decode: authOptions.jwt?.decode },
callbacks: {
authorized: ({ token }) => !!token,
},

View File

@@ -21,7 +21,7 @@ This error occurs when the `SessionProvider` Context has a problem fetching sess
#### CLIENT_FETCH_ERROR
If you see `CLIENT_FETCH_ERROR` make sure you have configured the `NEXTAUTH_URL` environment variable.
This can happen for multiple reasons. Make sure that you [configured](/configuration/initialization) NextAuth.js correctly, and if you used [`NEXTAUTH_URL`](https://next-auth.js.org/configuration/options#nextauth_url) that it's correctly set.
---

View File

@@ -203,7 +203,7 @@ export default NextAuth({
jwt({ token, trigger, session }) {
if (trigger === "update" && session?.name) {
// Note, that `session` can be any arbitrary object, remember to validate it!
token.name = session
token.name = session.name
}
return token
}
@@ -519,6 +519,10 @@ where `data.url` is the validated URL you can redirect the user to without any f
## SessionProvider
:::note
If you are using the App Router, we encourage you to use [`getServerSession`](/configuration/nextjs#getserversession) in server contexts instead. (`SessionProvider` *can* be used in the App Router, which might be the easier choice if you are migrating from pages.)
:::
Using the supplied `<SessionProvider>` allows instances of `useSession()` to share the session object across components, by using [React Context](https://react.dev/learn/passing-data-deeply-with-context) under the hood. It also takes care of keeping the session updated and synced between tabs/windows.
```jsx title="pages/_app.js"

View File

@@ -76,6 +76,7 @@ Instances of `useSession` will then have access to the session data and status.
:::tip
Check out the [client documentation](/getting-started/client) to see how you can improve the user experience and page performance by using the NextAuth.js client.
If you are using the Next.js App Router, please note that `<SessionProvider />` requires a client component and therefore cannot be put inside the root layout. For more details, check out the [Next.js documentation](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts).
:::
### Frontend - Add React Hook

View File

@@ -3,6 +3,10 @@ id: gitlab
title: GitLab
---
:::note
GitLab returns a field on `Account` called `created_at` which is a number. See their [docs](https://docs.gitlab.com/ee/api/oauth2.html). Remember to add this field as optional to your database schema, in case if you are using an [Adapter](https://authjs.dev/reference/adapters).
:::
## Documentation
https://docs.gitlab.com/ee/api/oauth2.html

View File

@@ -118,7 +118,7 @@ Once you have saved your schema, use the Prisma CLI to generate the Prisma Clien
npx prisma generate
```
To configure you database to use the new schema (i.e. create tables and columns) use the `prisma migrate` command:
To configure your database to use the new schema (i.e. create tables and columns) use the `prisma migrate` command:
```
npx prisma migrate dev

View File

@@ -168,7 +168,7 @@ export default function App({
## Security
If you think you have found a vulnerability (or not sure) in NextAuth.js or any of the related packages (i.e. Adapters), we ask you to have a read of our [Security Policy](https://github.com/nextauthjs/next-auth/blob/main/SECURITY.md) to reach out responsibly. Please do not open Pull Requests/Issues/Discussions before consulting with us.
If you think you have found a vulnerability (or not sure) in NextAuth.js or any of the related packages (i.e. Adapters), we ask you to have a read of our [Security Policy](https://github.com/nextauthjs/next-auth/security/policy) to reach out responsibly. Please do not open Pull Requests/Issues/Discussions before consulting with us.
## Acknowledgments

View File

@@ -1,6 +1,6 @@
{
"name": "next-auth",
"version": "4.22.4",
"version": "4.23.2",
"description": "Authentication for Next.js",
"homepage": "https://next-auth.js.org",
"repository": "https://github.com/nextauthjs/next-auth.git",
@@ -9,7 +9,7 @@
"Balázs Orbán <info@balazsorban.com>",
"Nico Domino <yo@ndo.dev>",
"Lluis Agusti <hi@llu.lu>",
"Thang Huu Vu <thvu@hey.com>"
"Thang Huu Vu <hi@thvu.dev>"
],
"main": "index.js",
"module": "index.js",
@@ -27,19 +27,42 @@
"nextauth"
],
"exports": {
".": "./index.js",
"./jwt": "./jwt/index.js",
"./react": "./react/index.js",
"./core": "./core/index.js",
"./next": "./next/index.js",
"./middleware": "./middleware.js",
"./client/_utils": "./client/_utils.js",
"./providers/*": "./providers/*.js"
".": {
"types": "./index.d.ts",
"default": "./index.js"
},
"./adapters": {
"types": "./adapters.d.ts"
},
"./jwt": {
"types": "./jwt/index.d.ts",
"default": "./jwt/index.js"
},
"./react": {
"types": "./react/index.d.ts",
"default": "./react/index.js"
},
"./next": {
"types": "./next/index.d.ts",
"default": "./next/index.js"
},
"./middleware": {
"types": "./middleware.d.ts",
"default": "./middleware.js"
},
"./client/_utils": {
"types": "./client/_utils.d.ts",
"default": "./client/_utils.js"
},
"./providers/*": {
"types": "./providers/*.d.ts",
"default": "./providers/*.js"
}
},
"scripts": {
"build": "pnpm clean && pnpm build:js && pnpm build:css",
"build:js": "pnpm clean && pnpm generate-providers && pnpm tsc --project tsconfig.json && babel --config-file ./config/babel.config.js src --out-dir . --extensions \".tsx,.ts,.js,.jsx\"",
"clean": "rm -rf coverage client css utils providers core jwt react next index.d.ts index.js adapters.d.ts middleware.d.ts middleware.js",
"clean": "rm -rf coverage client css utils providers core jwt react next lib ./*.js ./*.ts*",
"build:css": "postcss --config config/postcss.config.js src/**/*.css --base src --dir . && node config/wrap-css.js",
"dev": "pnpm clean && pnpm generate-providers && concurrently \"pnpm watch:css\" \"pnpm watch:ts\"",
"watch:ts": "pnpm tsc --project tsconfig.dev.json",

View File

@@ -60,19 +60,21 @@ export interface VerificationToken {
* [Create a custom adapter](https://next-auth.js.org/tutorials/creating-a-database-adapter)
*/
export interface Adapter {
createUser: (user: Omit<AdapterUser, "id">) => Awaitable<AdapterUser>
getUser: (id: string) => Awaitable<AdapterUser | null>
getUserByEmail: (email: string) => Awaitable<AdapterUser | null>
createUser?: (user: Omit<AdapterUser, "id">) => Awaitable<AdapterUser>
getUser?: (id: string) => Awaitable<AdapterUser | null>
getUserByEmail?: (email: string) => Awaitable<AdapterUser | null>
/** Using the provider id and the id of the user for a specific account, get the user. */
getUserByAccount: (
getUserByAccount?: (
providerAccountId: Pick<AdapterAccount, "provider" | "providerAccountId">
) => Awaitable<AdapterUser | null>
updateUser: (user: Partial<AdapterUser> & Pick<AdapterUser, 'id'>) => Awaitable<AdapterUser>
updateUser?: (
user: Partial<AdapterUser> & Pick<AdapterUser, "id">
) => Awaitable<AdapterUser>
/** @todo Implement */
deleteUser?: (
userId: string
) => Promise<void> | Awaitable<AdapterUser | null | undefined>
linkAccount: (
linkAccount?: (
account: AdapterAccount
) => Promise<void> | Awaitable<AdapterAccount | null | undefined>
/** @todo Implement */
@@ -80,15 +82,15 @@ export interface Adapter {
providerAccountId: Pick<AdapterAccount, "provider" | "providerAccountId">
) => Promise<void> | Awaitable<AdapterAccount | undefined>
/** Creates a session for the user and returns it. */
createSession: (session: {
createSession?: (session: {
sessionToken: string
userId: string
expires: Date
}) => Awaitable<AdapterSession>
getSessionAndUser: (
getSessionAndUser?: (
sessionToken: string
) => Awaitable<{ session: AdapterSession; user: AdapterUser } | null>
updateSession: (
updateSession?: (
session: Partial<AdapterSession> & Pick<AdapterSession, "sessionToken">
) => Awaitable<AdapterSession | null | undefined>
/**
@@ -96,7 +98,7 @@ export interface Adapter {
* It is preferred that this method also returns the session
* that is being deleted for logging purposes.
*/
deleteSession: (
deleteSession?: (
sessionToken: string
) => Promise<void> | Awaitable<AdapterSession | null | undefined>
createVerificationToken?: (

View File

@@ -1,4 +1,4 @@
import type { EventCallbacks, LoggerInstance } from ".."
import type { EventCallbacks, InternalOptions, LoggerInstance } from ".."
/**
* Same as the default `Error`, but it is JSON serializable.
@@ -106,7 +106,7 @@ export function eventsErrorHandler(
export function adapterErrorHandler<TAdapter>(
adapter: TAdapter | undefined,
logger: LoggerInstance
): TAdapter | undefined {
): InternalOptions["adapter"] | undefined {
if (!adapter) return
return Object.keys(adapter).reduce<any>((acc, name) => {

View File

@@ -114,7 +114,7 @@ export function defaultCookies(useSecureCookies: boolean): CookiesOptions {
path: "/",
secure: useSecureCookies,
},
}
},
}
}
@@ -161,8 +161,21 @@ export class SessionStore {
}
}
/**
* The JWT Session or database Session ID
* constructed from the cookie chunks.
*/
get value() {
return Object.values(this.#chunks)?.join("")
// Sort the chunks by their keys before joining
const sortedKeys = Object.keys(this.#chunks).sort((a, b) => {
const aSuffix = parseInt(a.split(".").pop() ?? "0")
const bSuffix = parseInt(b.split(".").pop() ?? "0")
return aSuffix - bSuffix
})
// Use the sorted keys to join the chunks in the correct order
return sortedKeys.map((key) => this.#chunks[key]).join("")
}
/** Given a cookie, return a list of cookies, chunked to fit the allowed cookie size. */

View File

@@ -580,10 +580,12 @@ export type AuthAction =
| "error"
| "_log"
type NonNullableFields<T> = {
[P in keyof T]-?: NonNullable<T[P]>
}
/** @internal */
export interface InternalOptions<
TProviderType = ProviderType,
> {
export interface InternalOptions<TProviderType = ProviderType> {
providers: InternalProvider[]
/**
* Parsed from `NEXTAUTH_URL` or `x-forwarded-host` and `x-forwarded-proto` if the host is trusted.
@@ -602,7 +604,7 @@ export interface InternalOptions<
pages: Partial<PagesOptions>
jwt: JWTOptions
events: Partial<EventCallbacks>
adapter?: Adapter
adapter?: NonNullableFields<Adapter>
callbacks: CallbacksOptions
cookies: CookiesOptions
callbackUrl: string

View File

@@ -36,7 +36,7 @@ export interface JWTDecodeParams {
export interface JWTOptions {
/**
* The secret used to encode/decode the NextAuth.js issued JWT.
* @deprecated Set the `NEXTAUTH_SECRET` environment vairable or
* @deprecated Set the `NEXTAUTH_SECRET` environment variable or
* use the top-level `secret` option instead
*/
secret: string

View File

@@ -101,6 +101,7 @@ async function NextAuthRouteHandler(
response.headers.delete("Location")
response.headers.set("Content-Type", "application/json")
return new Response(JSON.stringify({ url: redirect }), {
status: internalResponse.status,
headers: response.headers,
})
}

View File

@@ -0,0 +1,56 @@
import type { OAuthConfig, OAuthUserConfig } from "."
/** @see [Supported Scopes](https://docs.passage.id/hosted-login/oidc-client-configuration#supported-scopes) */
export interface PassageProfile {
iss: string
/** Unique identifer in Passage for the user */
sub: string
aud: string[]
exp: number
iat: number
auth_time: number
azp: string
client_id: string
at_hash: string
c_hash: string
/** The user's email address */
email: string
/** Whether the user has verified their email address */
email_verified: boolean
/** The user's phone number */
phone: string
/** Whether the user has verified their phone number */
phone_number_verified: boolean
}
export default function Passage(
config: OAuthUserConfig<PassageProfile>
): OAuthConfig<PassageProfile> {
config.issuer = config.issuer?.replace(/\/$/, "")
return {
id: "passage",
name: "Passage",
type: "oauth",
wellKnown: `${config.issuer}/.well-known/openid-configuration`,
authorization: { params: { scope: "openid email" } },
client: { token_endpoint_auth_method: "client_secret_basic" },
checks: ["pkce", "state"],
profile(profile) {
return {
id: profile.sub,
name: null,
email: profile.email,
image: null,
}
},
style: {
logo: "/passage.svg",
logoDark: "/passage.svg",
bg: "#fff",
bgDark: "#fff",
text: "#000",
textDark: "#000",
},
options: config,
}
}

View File

@@ -247,7 +247,7 @@ export async function signIn<
isCredentials ? "callback" : "signin"
}/${provider}`
const _signInUrl = `${signInUrl}?${new URLSearchParams(authorizationParams)}`
const _signInUrl = `${signInUrl}${authorizationParams ? `?${new URLSearchParams(authorizationParams)}` : ""}`
const res = await fetch(_signInUrl, {
method: "post",