Skip to content

Commit 35257e4

Browse files
authored
feat: add support for withApiAuthRequired helper (#2230)
1 parent dbcca6a commit 35257e4

File tree

5 files changed

+509
-5
lines changed

5 files changed

+509
-5
lines changed

EXAMPLES.md

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ By default, the SDK uses OpenID Connect's RP-Initiated Logout when available, fa
9595

9696
```ts
9797
export const auth0 = new Auth0Client({
98-
logoutStrategy: "auto", // default behavior
98+
logoutStrategy: "auto" // default behavior
9999
// ... other config
100-
})
100+
});
101101
```
102102

103103
Available strategies:
@@ -118,9 +118,9 @@ The `"v2"` strategy is useful for applications that:
118118
```ts
119119
// Example: Using v2 logout for wildcard URL support
120120
export const auth0 = new Auth0Client({
121-
logoutStrategy: "v2",
121+
logoutStrategy: "v2"
122122
// ... other config
123-
})
123+
});
124124

125125
// This allows logout URLs like:
126126
// /auth/logout?returnTo=https://localhost:3000/en/dashboard
@@ -300,6 +300,79 @@ export default withPageAuthRequired(function Page({ user }) {
300300
});
301301
```
302302

303+
## Protect an API Route
304+
305+
### Page Router
306+
307+
Requests to `/api/protected` without a valid session cookie will fail with `401`.
308+
309+
```js
310+
// pages/api/protected.js
311+
import { auth0 } from "@/lib/auth0";
312+
313+
export default auth0.withApiAuthRequired(async function myApiRoute(req, res) {
314+
const { user } = await auth0.getSession(req);
315+
res.json({ protected: "My Secret", id: user.sub });
316+
});
317+
```
318+
319+
Then you can access your API from the frontend with a valid session cookie.
320+
321+
```jsx
322+
// pages/products
323+
import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";
324+
import useSWR from "swr";
325+
326+
const fetcher = async (uri) => {
327+
const response = await fetch(uri);
328+
return response.json();
329+
};
330+
331+
export default withPageAuthRequired(function Products() {
332+
const { data, error } = useSWR("/api/protected", fetcher);
333+
if (error) return <div>oops... {error.message}</div>;
334+
if (data === undefined) return <div>Loading...</div>;
335+
return <div>{data.protected}</div>;
336+
});
337+
```
338+
339+
### App Router
340+
341+
Requests to `/api/protected` without a valid session cookie will fail with `401`.
342+
343+
```js
344+
// app/api/protected/route.js
345+
import { auth0 } from "@/lib/auth0";
346+
347+
export const GET = auth0.withApiAuthRequired(async function myApiRoute(req) {
348+
const res = new NextResponse();
349+
const { user } = await auth0.getSession(req);
350+
return NextResponse.json({ protected: "My Secret", id: user.sub }, res);
351+
});
352+
```
353+
354+
Then you can access your API from the frontend with a valid session cookie.
355+
356+
```jsx
357+
// app/products/page.jsx
358+
"use client";
359+
360+
import { withPageAuthRequired } from "@auth0/nextjs-auth0/client";
361+
import useSWR from "swr";
362+
363+
const fetcher = async (uri) => {
364+
const response = await fetch(uri);
365+
return response.json();
366+
};
367+
368+
export default withPageAuthRequired(function Products() {
369+
const { data, error } = useSWR("/api/protected", fetcher);
370+
if (error) return <div>oops... {error.message}</div>;
371+
if (data === undefined) return <div>Loading...</div>;
372+
return <div>{data.protected}</div>;
373+
});
374+
```
375+
303376
## Accessing the idToken
304377

305378
`idToken` can be accessed from the session in the following way:

src/server/client.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { IncomingMessage, ServerResponse } from "node:http";
22
import { cookies } from "next/headers.js";
33
import { NextRequest, NextResponse } from "next/server.js";
4-
import { NextApiRequest, NextApiResponse } from "next/types.js";
4+
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next/types.js";
55

66
import {
77
AccessTokenError,
@@ -18,6 +18,7 @@ import {
1818
StartInteractiveLoginOptions,
1919
User
2020
} from "../types/index.js";
21+
import { isRequest } from "../utils/request.js";
2122
import {
2223
AuthClient,
2324
BeforeSessionSavedHook,
@@ -26,6 +27,7 @@ import {
2627
RoutesOptions
2728
} from "./auth-client.js";
2829
import { RequestCookies, ResponseCookies } from "./cookies.js";
30+
import * as withApiAuthRequired from "./helpers/with-api-auth-required.js";
2931
import {
3032
appRouteHandlerFactory,
3133
AppRouterPageRoute,
@@ -741,6 +743,36 @@ export class Auth0Client {
741743
return pageRouteHandler(fnOrOpts);
742744
}
743745

746+
withApiAuthRequired(
747+
apiRoute: withApiAuthRequired.AppRouteHandlerFn | NextApiHandler
748+
) {
749+
const pageRouteHandler = withApiAuthRequired.pageRouteHandlerFactory(this);
750+
const appRouteHandler = withApiAuthRequired.appRouteHandlerFactory(this);
751+
752+
return (
753+
req: NextRequest | NextApiRequest,
754+
resOrParams:
755+
| withApiAuthRequired.AppRouteHandlerFnContext
756+
| NextApiResponse
757+
) => {
758+
if (isRequest(req)) {
759+
return appRouteHandler(
760+
apiRoute as withApiAuthRequired.AppRouteHandlerFn
761+
)(
762+
req as NextRequest,
763+
resOrParams as withApiAuthRequired.AppRouteHandlerFnContext
764+
);
765+
}
766+
767+
return (
768+
pageRouteHandler as withApiAuthRequired.WithApiAuthRequiredPageRoute
769+
)(apiRoute as NextApiHandler)(
770+
req as NextApiRequest,
771+
resOrParams as NextApiResponse
772+
);
773+
};
774+
}
775+
744776
private async saveToSession(
745777
data: SessionData,
746778
req?: PagesRouterRequest | NextRequest,

0 commit comments

Comments
 (0)