-
Notifications
You must be signed in to change notification settings - Fork 330
/
Copy pathindex.ts
136 lines (115 loc) · 4.26 KB
/
index.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { AuthStatus, Base, createGetToken, createSignedOutState } from '@clerk/backend-core';
import { NextFetchEvent, NextRequest, NextResponse } from 'next/server';
import { ClerkAPI } from './ClerkAPI';
import {
NextMiddlewareResult,
WithEdgeMiddlewareAuthCallback,
WithEdgeMiddlewareAuthMiddlewareResult,
WithEdgeMiddlewareAuthOptions,
} from './types';
import { injectAuthIntoRequest } from './utils';
/**
*
* Required implementations for the runtime:
* 1. Import Key
* 2. Verify Signature
* 3. Decode Base64
* 4. ClerkAPI export with fetcher implementation
* 5. Fetch Interstitial
*
*/
const importKey = async (jwk: JsonWebKey, algorithm: Algorithm) => {
return await crypto.subtle.importKey('jwk', jwk, algorithm, true, ['verify']);
};
const verifySignature = async (algorithm: Algorithm, key: CryptoKey, signature: Uint8Array, data: Uint8Array) => {
return await crypto.subtle.verify(algorithm, key, signature, data);
};
const decodeBase64 = (base64: string) => atob(base64);
/** Base initialization */
const vercelEdgeBase = new Base(importKey, verifySignature, decodeBase64);
/** Export standalone verifySessionToken */
export const verifySessionToken = vercelEdgeBase.verifySessionToken;
/** Export ClerkBackendAPI API client */
const allowlistIdentifiers = ClerkAPI.allowlistIdentifiers;
const clients = ClerkAPI.clients;
const emails = ClerkAPI.emails;
const invitations = ClerkAPI.invitations;
const organizations = ClerkAPI.organizations;
const sessions = ClerkAPI.sessions;
const smsMessages = ClerkAPI.smsMessages;
const users = ClerkAPI.users;
// Export sub-api objects
export { allowlistIdentifiers, clients, emails, invitations, organizations, sessions, smsMessages, users };
async function fetchInterstitial() {
const response = await ClerkAPI.fetchInterstitial<Response>();
return response.text();
}
export function withEdgeMiddlewareAuth<
CallbackReturn extends NextMiddlewareResult | Promise<NextMiddlewareResult>,
Options extends WithEdgeMiddlewareAuthOptions,
>(
handler: WithEdgeMiddlewareAuthCallback<CallbackReturn, Options>,
options?: Options,
): WithEdgeMiddlewareAuthMiddlewareResult<CallbackReturn, Options>;
export function withEdgeMiddlewareAuth(
handler: any,
options: any = {
loadSession: false,
loadUser: false,
},
): any {
return async function clerkAuth(req: NextRequest, event: NextFetchEvent) {
const { loadUser, loadSession, jwtKey, authorizedParties } = options;
const cookieToken = req.cookies['__session'];
const headerToken = req.headers.get('authorization');
const { status, interstitial, sessionClaims, errorReason } = await vercelEdgeBase.getAuthState({
cookieToken,
headerToken,
clientUat: req.cookies['__client_uat'],
origin: req.headers.get('origin'),
host: req.headers.get('host') as string,
userAgent: req.headers.get('user-agent'),
forwardedPort: req.headers.get('x-forwarded-port'),
forwardedHost: req.headers.get('x-forwarded-host'),
referrer: req.headers.get('referrer'),
authorizedParties,
jwtKey,
fetchInterstitial,
});
if (status === AuthStatus.Interstitial) {
return new NextResponse(interstitial, {
headers: { 'Content-Type': 'text/html', 'Auth-Result': errorReason || '' },
status: 401,
});
}
if (status === AuthStatus.SignedOut) {
const response = (await handler(
injectAuthIntoRequest(req, createSignedOutState()),
event,
)) as NextMiddlewareResult;
response?.headers.set('Auth-Result', errorReason || '');
return response;
}
const sessionId = sessionClaims!.sid;
const userId = sessionClaims!.sub;
const [user, session] = await Promise.all([
loadUser ? ClerkAPI.users.getUser(userId) : Promise.resolve(undefined),
loadSession ? ClerkAPI.sessions.getSession(sessionId) : Promise.resolve(undefined),
]);
const getToken = createGetToken({
sessionId,
cookieToken,
headerToken: headerToken || '',
fetcher: (...args) => ClerkAPI.sessions.getToken(...args),
});
const authRequest = injectAuthIntoRequest(req, {
user,
session,
sessionId,
userId,
getToken,
claims: sessionClaims as Record<string, unknown>,
});
return handler(authRequest, event);
};
}