diff --git a/EXAMPLES.md b/EXAMPLES.md index 009418cd..dcab9ae1 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -43,6 +43,9 @@ - [On the server (App Router)](#on-the-server-app-router-3) - [On the server (Pages Router)](#on-the-server-pages-router-3) - [Middleware](#middleware-3) +- [Customizing Auth Handlers](#customizing-auth-handlers) + - [Run custom code before Auth Handlers](#run-custom-code-before-auth-handlers) + - [Run code after callback](#run-code-after-callback) ## Passing authorization parameters @@ -1225,3 +1228,65 @@ export async function middleware(request: NextRequest) { return resWithCombinedHeaders; } ``` + +## Customizing Auth Handlers + +In v4, authentication routes (`/auth/login`, `/auth/logout`, `/auth/callback`) are handled automatically by the middleware. While you can no longer customize individual route handlers directly like in v3, you can intercept these routes in your middleware to run custom logic before the auth handlers execute. + +This approach allows you to: +- Run custom code before authentication actions (logging, analytics, validation) +- Modify the response (set cookies, headers, etc.) +- Implement custom redirects or early returns when needed +- Add business logic around authentication flows +- Maintain compatibility with existing tracking and analytics systems + +The middleware-based approach provides the same level of control as v3's custom handlers while working seamlessly with v4's automatic route handling. + +### Run custom code before Auth Handlers + +Following example shows how to run custom logic before the `logout` handler: +```ts +export async function middleware(request) { + + // prepare NextResponse object from auth0 middleware + const authRes = await auth0.middleware(request); + + // The following interceptUrls can be used: + // "/auth/login" : intercept login auth handler + // "/auth/logout" : intercept logout auth handler + // "/auth/callback" : intercept callback auth handler + // "/your/login/returnTo/url" : intercept redirect after login + // "/your/logout/returnTo/url" : intercept redirect after logout + + const interceptUrl = "/auth/logout"; + + // intercept auth handler + if (request.nextUrl.pathname === interceptUrl) { + // do custom stuff + console.log("Pre-logout code") + + // Example: Set a cookie + authRes.cookies.set('myCustomCookie', 'cookieValue', { path: '/' }); + // Example: Set another cookie with options + authRes.cookies.set({ + name: 'anotherCookie', + value: 'anotherValue', + httpOnly: true, + path: '/', + }); + + // Example: Delete a cookie + // authRes.cookies.delete('cookieNameToDelete'); + + // you can also do an early return here with your own NextResponse object + // return NextResponse.redirect(new URL('/custom-logout-page')); + } + + // return the original auth0-handled NextResponse object + return authRes +} +``` + +### Run code after callback +Please refer to [onCallback](https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md#oncallback) +for details on how to run code after callback. \ No newline at end of file diff --git a/README.md b/README.md index f36ec88f..7f0cde2d 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,23 @@ You can customize the client by using the options below: | httpTimeout | `number` | Integer value for the HTTP timeout in milliseconds for authentication requests. Defaults to `5000` milliseconds | | enableTelemetry | `boolean` | Boolean value to opt-out of sending the library name and version to your authorization server via the `Auth0-Client` header. Defaults to `true`. | +### Customizing Auth Handlers + +While the authentication routes are handled automatically by the middleware, you can still customize the authentication flow through two main approaches: + +- **Run custom code before auth handlers**: Intercept auth routes in your middleware to add custom logic before authentication actions +- **Run code after authentication**: Use the `onCallback` hook to add custom logic after authentication completes + +Additional customization options include: +- Login parameters via query parameters or static configuration +- Session data modification using the `beforeSessionSaved` hook +- Logout redirects using query parameters + +> [!IMPORTANT] +> When customizing auth handlers, always validate user inputs (especially redirect URLs) to prevent security vulnerabilities like open redirects. Use relative URLs when possible and implement proper input sanitization. + +**Quick Start**: For detailed examples and step-by-step migration patterns from v3, see [Customizing Auth Handlers](https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md#customizing-auth-handlers). + ## Session Cookie Configuration You can specify the following environment variables to configure the session cookie: diff --git a/V4_MIGRATION_GUIDE.md b/V4_MIGRATION_GUIDE.md index c667b119..187c3f2c 100644 --- a/V4_MIGRATION_GUIDE.md +++ b/V4_MIGRATION_GUIDE.md @@ -285,3 +285,98 @@ export const auth0 = new Auth0Client({ - `touchSession` method was removed. The middleware enables rolling sessions by default and can be configured via the [Session configuration section in the Examples guide](https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md#session-configuration). - `getAccessToken` can now be called in React Server Components. For examples on how to use `getAccessToken` in various environments (browser, App Router, Pages Router, Middleware), refer to the [Getting an access token section in the Examples guide](https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md#getting-an-access-token). - By default, v4 will use [OpenID Connect's RP-Initiated Logout](https://auth0.com/docs/authenticate/login/logout/log-users-out-of-auth0) if it's enabled on the tenant. Otherwise, it will fallback to the `/v2/logout` endpoint. + +## Customizing Auth Handlers + +In v3, you could customize individual auth handlers by providing custom implementations to the `handleAuth` function: + +```ts +// v3 approach (no longer available in v4) +export const GET = handleAuth({ + async logout(req: NextApiRequest, res: NextApiResponse) { + // Custom logout logic + console.log('User is logging out'); + + return await handleLogout(req, res); + }, + async login(req: NextApiRequest, res: NextApiResponse) { + // Custom login logic + return await handleLogin(req, res, { + authorizationParams: { + audience: 'https://my-api.com' + } + }); + } +}); +``` + +In v4, the auth routes are handled automatically by the middleware, but you can achieve similar customization through two main approaches: + +### 1. Run custom code before auth handlers (Middleware Interception) + +You can intercept auth routes in your middleware to run custom logic before the auth handlers execute: + +```ts +import type { NextRequest } from 'next/server'; +import { auth0 } from './lib/auth0'; + +export async function middleware(request: NextRequest) { + const authRes = await auth0.middleware(request); + + // Intercept specific auth routes + if (request.nextUrl.pathname === '/auth/logout') { + // Custom logout logic runs BEFORE the actual logout + console.log('User is logging out'); + + // Example: Set custom cookies + authRes.cookies.set('logoutTime', new Date().toISOString()); + } + + if (request.nextUrl.pathname === '/auth/login') { + // Custom login logic runs BEFORE the actual login + console.log('User is attempting to login'); + } + + return authRes; +} +``` + +### 2. Run code after authentication (Callback Hook) + +Use the `onCallback` hook to add custom logic after authentication completes: + +```ts +import { NextResponse } from 'next/server'; +import { Auth0Client } from '@auth0/nextjs-auth0/server'; + +export const auth0 = new Auth0Client({ + async onCallback(error, context, session) { + if (error) { + console.error('Authentication error:', error); + return NextResponse.redirect( + new URL('/error', process.env.APP_BASE_URL) + ); + } + + // Custom logic after successful authentication + if (session) { + console.log(`User ${session.user.sub} logged in successfully`); + } + + return NextResponse.redirect( + new URL(context.returnTo || "/", process.env.APP_BASE_URL) + ); + } +}); +``` + +### Additional Customization Options + +- **Login parameters**: Use query parameters (`/auth/login?audience=...`) or static configuration +- **Session data**: Use the `beforeSessionSaved` hook to modify session data +- **Logout redirects**: Use query parameters (`/auth/logout?returnTo=...`) + +> [!IMPORTANT] +> Always validate redirect URLs to prevent open redirect attacks. Use relative URLs when possible. + +For detailed examples and implementation patterns, see [Customizing Auth Handlers](https://github.com/auth0/nextjs-auth0/blob/main/EXAMPLES.md#customizing-auth-handlers) in the Examples guide.