Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -621,19 +621,43 @@ The `beforeSessionSaved` hook is run right before the session is persisted. It p
The hook recieves a `SessionData` object and an ID token. The function must return a Promise that resolves to a `SessionData` object: `(session: SessionData) => Promise<SessionData>`. For example:

```ts
import { Auth0Client, filterDefaultIdTokenClaims } from "@auth0/nextjs-auth0/server"

export const auth0 = new Auth0Client({
async beforeSessionSaved(session, idToken) {
return {
...session,
user: {
...session.user,
foo: "bar",
...filterDefaultIdTokenClaims(session.user),
foo: session.user.foo, // keep the foo claim
},
}
},
})
```

The `session.user` object passed to the `beforeSessionSaved` hook will contain every claim in the ID Token, including custom claims. You can use the `filterDefaultIdTokenClaims` utility to filter out the standard claims and only keep the custom claims you want to persist.

> [!INFO]
> Incase you want to understand which claims are being considered the default Id Token Claims, you can refer to `DEFAULT_ID_TOKEN_CLAIMS`, which can be imported from the SDK from `@auth0/nextjs-auth0/server`:
>
> ```ts
> import { DEFAULT_ID_TOKEN_CLAIMS } from "@auth0/nextjs-auth0/server"
> ```

Alternatively, you can use the entire `session.user` object if you would like to include every claim in the ID Token by just returning the `session` like so:

```ts
import { Auth0Client } from "@auth0/nextjs-auth0/server"

export const auth0 = new Auth0Client({
async beforeSessionSaved(session, idToken) {
return session
},
})
```
Do realize that this has an impact on the size of the cookie being issued, so it's best to limit the claims to only those that are necessary for your application.

### `onCallback`

The `onCallback` hook is run once the user has been redirected back from Auth0 to your application with either an error or the authorization code which will be verified and exchanged.
Expand Down
4 changes: 2 additions & 2 deletions src/server/auth-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { toSafeRedirect } from "../utils/url-helpers";
import { addCacheControlHeadersForSession } from "./cookies";
import { AbstractSessionStore } from "./session/abstract-session-store";
import { TransactionState, TransactionStore } from "./transaction-store";
import { filterClaims } from "./user";
import { filterDefaultIdTokenClaims } from "./user";

export type BeforeSessionSavedHook = (
session: SessionData,
Expand Down Expand Up @@ -566,7 +566,7 @@ export class AuthClient {
internal: session.internal
};
} else {
session.user = filterClaims(idTokenClaims);
session.user = filterDefaultIdTokenClaims(idTokenClaims);
}

await this.sessionStore.set(req.cookies, res.cookies, session, true);
Expand Down
2 changes: 2 additions & 0 deletions src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export { AuthClient } from "./auth-client";
export { TransactionStore } from "./transaction-store";

export { AbstractSessionStore } from "./session/abstract-session-store";

export { filterDefaultIdTokenClaims, DEFAULT_ID_TOKEN_CLAIMS } from "./user";
8 changes: 4 additions & 4 deletions src/server/user.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe, expect, it } from "vitest";

import { filterClaims } from "./user";
import { filterDefaultIdTokenClaims } from "./user";

describe("filterClaims", async () => {
describe("filterDefaultIdTokenClaims", async () => {
it("should return only the allowed claims", () => {
const claims = {
sub: "user_123",
Expand All @@ -20,7 +20,7 @@ describe("filterClaims", async () => {
exp: 1234567890
};

expect(filterClaims(claims)).toEqual({
expect(filterDefaultIdTokenClaims(claims)).toEqual({
sub: "user_123",
name: "John Doe",
nickname: "johndoe",
Expand All @@ -34,6 +34,6 @@ describe("filterClaims", async () => {
});

it("should return an empty object if no claims are provided", () => {
expect(filterClaims({})).toEqual({});
expect(filterDefaultIdTokenClaims({})).toEqual({});
});
});
14 changes: 11 additions & 3 deletions src/server/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type { User } from "../types";

const DEFAULT_ALLOWED_CLAIMS = [
/**
* Default claims for the ID token.
*/
export const DEFAULT_ID_TOKEN_CLAIMS = [
"sub",
"name",
"nickname",
Expand All @@ -12,9 +15,14 @@ const DEFAULT_ALLOWED_CLAIMS = [
"org_id"
];

export function filterClaims(claims: { [key: string]: any }) {
/**
* Filters the claims to only include those that are considered default.
* @param claims The claims to filter.
* @returns The filtered claims containing only default ID token claims.
*/
export function filterDefaultIdTokenClaims(claims: { [key: string]: any }) {
return Object.keys(claims).reduce((acc, key) => {
if (DEFAULT_ALLOWED_CLAIMS.includes(key)) {
if (DEFAULT_ID_TOKEN_CLAIMS.includes(key)) {
acc[key] = claims[key];
}
return acc;
Expand Down