-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmiddleware.ts
107 lines (94 loc) · 2.8 KB
/
middleware.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
import {
defaultSessionData,
ironSessionOptions,
isTokenExpired,
} from '@/lib/auth';
import { sealData, unsealData } from 'iron-session';
import { SessionData } from '@/lib/types';
import { refreshAccessToken } from '@/app/actions/login';
import { Roles } from '@osu-tournament-rating/otr-api-client';
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const session = await middlewareGetSession(req, res);
// Redirect users that aren't logged in
if (!session.isLogged || !session.user?.scopes?.includes(Roles.Whitelist)) {
// Pass through the existing response headers in case cookies are set
return NextResponse.redirect(new URL('/unauthorized', req.url), {
headers: res.headers,
});
}
return res;
}
async function middlewareGetSession(req: NextRequest, res: NextResponse) {
// Decode session from cookie
const sessionCookieValue = req.cookies.get(
ironSessionOptions.cookieName
)?.value;
const session = sessionCookieValue
? await unsealData<SessionData>(sessionCookieValue, ironSessionOptions)
: defaultSessionData;
// Access token is valid
if (
!session.accessToken ||
(session.accessToken && !isTokenExpired(session.accessToken))
) {
return session;
}
// Refresh token is expired
if (
!session.refreshToken ||
(session.refreshToken && isTokenExpired(session.refreshToken))
) {
middlewareLogout(res);
return session;
}
// Refresh access token
try {
const newAccessToken = await refreshAccessToken(session.refreshToken);
// Didn't receive a new access token, logout
if (!newAccessToken) {
session.isLogged = false;
middlewareLogout(res);
return session;
}
// Save new access token
session.accessToken = newAccessToken;
await middlewareSaveSession(session, res);
} catch {
session.isLogged = false;
middlewareLogout(res);
}
return session;
}
async function middlewareSaveSession(
sessionData: SessionData,
res: NextResponse
) {
const encodedSessionData = await sealData(sessionData, ironSessionOptions);
res.cookies.set(
ironSessionOptions.cookieName,
encodedSessionData,
ironSessionOptions.cookieOptions
);
}
function middlewareLogout(res: NextResponse) {
if (res.cookies.has(ironSessionOptions.cookieName)) {
res.cookies.delete(ironSessionOptions.cookieName);
}
}
export const config = {
matcher: [
/*
* Match all paths except:
* - '/api/*' API routes
* - '/auth'
* - '/unauthorized' Has its own access control
* - '/_next/*' Next.js internals
* - '/static/*' Static assets
* - '/favicon.ico' Static assets
*/
'/((?!api|auth|unauthorized|_next|static|favicon.ico).*)',
],
};