Skip to content

Commit 2b9706c

Browse files
committed
refactor: make dynamic API (cookies()) can be correctly throwed
1 parent f95f028 commit 2b9706c

3 files changed

Lines changed: 74 additions & 55 deletions

File tree

lib/auth.rsc.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import { redirect } from "next/navigation";
2-
import { getAuthStatus } from "./auth";
2+
import { getAuthStatus, getAuthToken } from "./auth";
33

44
export async function redirectIfAuthenticated(): Promise<void> {
55
let role: string | undefined;
66

7+
const token = await getAuthToken();
8+
if (!token) {
9+
return;
10+
}
11+
712
try {
8-
const isAuthenticated = await getAuthStatus();
13+
const isAuthenticated = await getAuthStatus(token);
914
role = isAuthenticated.role;
1015
} catch (error) {
1116
console.error("Error validating auth:", error);

lib/auth.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,7 @@ export const introspectSchema = z.union([
212212
}),
213213
]);
214214

215-
export async function getAuthStatus(): Promise<AuthStatus> {
216-
const token = await getAuthToken();
217-
if (!token) {
218-
return {
219-
loggedIn: false,
220-
introspectResult: undefined,
221-
};
222-
}
223-
215+
export async function getAuthStatus(token: string): Promise<AuthStatus> {
224216
// get user info
225217
const response = await fetch(buildUri("/api/auth/v2/introspect"), {
226218
method: "POST",

middleware.ts

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getAuthStatus } from "@/lib/auth";
1+
import { getAuthStatus, getAuthToken } from "@/lib/auth";
22
import { NextRequest, NextResponse } from "next/server";
33

44
// Define public routes that don't require authentication
@@ -33,63 +33,85 @@ export async function middleware(request: NextRequest) {
3333
return NextResponse.next();
3434
}
3535

36+
const token = await getAuthToken();
37+
if (!token) {
38+
return unauthorized(request);
39+
}
40+
3641
try {
37-
const { role, loggedIn } = await getAuthStatus();
42+
const { role, loggedIn } = await getAuthStatus(token);
3843

3944
if (!loggedIn) {
40-
// Handle unauthenticated requests
41-
if (isApiRoute(pathname)) {
42-
// Return JSON error for API routes
43-
return NextResponse.json(
44-
{
45-
error: "unauthorized",
46-
error_description: "Authentication required",
47-
},
48-
{ status: 401 },
49-
);
50-
} else {
51-
// Redirect to login for web routes
52-
const loginUrl = new URL("/login", request.url);
53-
loginUrl.searchParams.set("redirect", pathname);
54-
return NextResponse.redirect(loginUrl);
55-
}
45+
return unauthorized(request);
5646
}
5747

5848
if (role !== "admin") {
59-
if (isApiRoute(pathname)) {
60-
return NextResponse.json(
61-
{
62-
error: "forbidden",
63-
error_description: "You must be an admin to access this resource",
64-
},
65-
{ status: 403 },
66-
);
67-
} else {
68-
const loginUrl = new URL("/forbidden", request.url);
69-
return NextResponse.redirect(loginUrl);
70-
}
49+
return forbidden(request);
7150
}
7251
} catch (error) {
7352
console.error("Middleware authentication error:", error);
74-
75-
if (isApiRoute(pathname)) {
76-
return NextResponse.json(
77-
{
78-
error: "server_error",
79-
error_description: "Could not validate authentication",
80-
},
81-
{ status: 500 },
82-
);
83-
} else {
84-
const loginUrl = new URL("/login", request.url);
85-
loginUrl.searchParams.set("error", "server_error");
86-
return NextResponse.redirect(loginUrl);
87-
}
53+
return serverError(request);
8854
}
8955

9056
return NextResponse.next();
9157
}
9258

59+
function unauthorized(request: NextRequest): NextResponse {
60+
const { pathname } = request.nextUrl;
61+
62+
// Handle unauthenticated requests
63+
if (isApiRoute(pathname)) {
64+
// Return JSON error for API routes
65+
return NextResponse.json(
66+
{
67+
error: "unauthorized",
68+
error_description: "Authentication required",
69+
},
70+
{ status: 401 },
71+
);
72+
}
73+
74+
// Redirect to login for web routes
75+
const loginUrl = new URL("/login", request.url);
76+
loginUrl.searchParams.set("redirect", pathname);
77+
return NextResponse.redirect(loginUrl);
78+
}
79+
80+
function forbidden(request: NextRequest): NextResponse {
81+
const { pathname } = request.nextUrl;
82+
83+
if (isApiRoute(pathname)) {
84+
return NextResponse.json(
85+
{
86+
error: "forbidden",
87+
error_description: "You must be an admin to access this resource",
88+
},
89+
{ status: 403 },
90+
);
91+
}
92+
93+
const loginUrl = new URL("/forbidden", request.url);
94+
return NextResponse.redirect(loginUrl);
95+
}
96+
97+
function serverError(request: NextRequest): NextResponse {
98+
const { pathname } = request.nextUrl;
99+
100+
if (isApiRoute(pathname)) {
101+
return NextResponse.json(
102+
{
103+
error: "server_error",
104+
error_description: "Could not validate authentication",
105+
},
106+
{ status: 500 },
107+
);
108+
}
109+
110+
const loginUrl = new URL("/login", request.url);
111+
loginUrl.searchParams.set("error", "server_error");
112+
return NextResponse.redirect(loginUrl);
113+
}
114+
93115
// Configure which routes the middleware should run on
94116
export const config = {
95117
matcher: [

0 commit comments

Comments
 (0)