Skip to content

Commit

Permalink
Add onError callback for customizing error handling in handleAuth (#193)
Browse files Browse the repository at this point in the history
* add optional resolveErrorResponse resolver for callback error messages

* update README to describe the resolveErrorResponse option

* swap to onError handler for custsom error handling

* format README
  • Loading branch information
nicknisi authored Jan 29, 2025
1 parent 2f6a2c7 commit a0fb119
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export const GET = handleAUth({
| `returnPathname` | `/` | The pathname to redirect the user to after signing in |
| `baseURL` | `undefined` | The base URL to use for the redirect URI instead of the one in the request. Useful if the app is being run in a container like docker where the hostname can be different from the one in the request |
| `onSuccess` | `undefined` | A function that receives successful authentication data and can be used for side-effects like persisting tokens |
| `onError` | `undefined` | A function that can receive the error and the request and handle the error in its own way. |

### Middleware

Expand Down
20 changes: 20 additions & 0 deletions __tests__/authkit-callback-route.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ describe('authkit-callback-route', () => {
expect(data.error.message).toBe('Something went wrong');
});

it('should handle authentication failure with custom onError handler', async () => {
// Mock authentication failure
jest.mocked(workos.userManagement.authenticateWithCode).mockRejectedValue('Auth failed');
request.nextUrl.searchParams.set('code', 'invalid-code');

const handler = handleAuth({
onError: ({ error }) => {
return new Response(JSON.stringify({ error: { message: 'Custom error' } }), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
},
});
const response = await handler(request);

expect(response.status).toBe(500);
const data = await response.json();
expect(data.error.message).toBe('Custom error');
});

it('should handle missing code parameter', async () => {
const handler = handleAuth();
const response = await handler(request);
Expand Down
20 changes: 12 additions & 8 deletions src/authkit-callback-route.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { NextRequest } from 'next/server';
import { cookies } from 'next/headers';
import { workos } from './workos.js';
import { NextRequest } from 'next/server';
import { getCookieOptions } from './cookie.js';
import { WORKOS_CLIENT_ID, WORKOS_COOKIE_NAME } from './env-variables.js';
import { HandleAuthOptions } from './interfaces.js';
import { encryptSession } from './session.js';
import { errorResponseWithFallback, redirectWithFallback } from './utils.js';
import { getCookieOptions } from './cookie.js';
import { HandleAuthOptions } from './interfaces.js';
import { workos } from './workos.js';

export function handleAuth(options: HandleAuthOptions = {}) {
const { returnPathname: returnPathnameOption = '/', baseURL, onSuccess } = options;
const { returnPathname: returnPathnameOption = '/', baseURL, onSuccess, onError } = options;

// Throw early if baseURL is provided but invalid
if (baseURL) {
Expand Down Expand Up @@ -83,14 +83,18 @@ export function handleAuth(options: HandleAuthOptions = {}) {

console.error(errorRes);

return errorResponse();
return errorResponse(request, error);
}
}

return errorResponse();
return errorResponse(request);
};

function errorResponse() {
function errorResponse(request: NextRequest, error?: unknown) {
if (onError) {
return onError({ error, request });
}

return errorResponseWithFallback({
error: {
message: 'Something went wrong',
Expand Down
2 changes: 2 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { OauthTokens, User } from '@workos-inc/node';
import { type NextRequest } from 'next/server';

export interface HandleAuthOptions {
returnPathname?: string;
baseURL?: string;
onSuccess?: (data: HandleAuthSuccessData) => void | Promise<void>;
onError?: (params: { error?: unknown; request: NextRequest }) => Response | Promise<Response>;
}

export interface HandleAuthSuccessData extends Session {
Expand Down

0 comments on commit a0fb119

Please sign in to comment.