@workos-inc/authkit-nextjs 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +145 -0
- package/dist/cjs/auth.d.ts +3 -0
- package/dist/cjs/auth.js +17 -0
- package/dist/cjs/auth.js.map +1 -0
- package/dist/cjs/authkit-callback-route.d.ts +3 -0
- package/dist/cjs/authkit-callback-route.js +58 -0
- package/dist/cjs/authkit-callback-route.js.map +1 -0
- package/dist/cjs/button.d.ts +3 -0
- package/dist/cjs/button.js +25 -0
- package/dist/cjs/button.js.map +1 -0
- package/dist/cjs/cookie.d.ts +8 -0
- package/dist/cjs/cookie.js +13 -0
- package/dist/cjs/cookie.js.map +1 -0
- package/dist/cjs/env-variables.d.ts +5 -0
- package/dist/cjs/env-variables.js +22 -0
- package/dist/cjs/env-variables.js.map +1 -0
- package/dist/cjs/get-authorization-url.d.ts +2 -0
- package/dist/cjs/get-authorization-url.js +15 -0
- package/dist/cjs/get-authorization-url.js.map +1 -0
- package/dist/cjs/impersonation.d.ts +6 -0
- package/dist/cjs/impersonation.js +119 -0
- package/dist/cjs/impersonation.js.map +1 -0
- package/dist/cjs/index.d.ts +6 -0
- package/dist/cjs/index.js +15 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interfaces.d.ts +33 -0
- package/dist/cjs/interfaces.js +3 -0
- package/dist/cjs/interfaces.js.map +1 -0
- package/dist/cjs/middleware.d.ts +6 -0
- package/dist/cjs/middleware.js +11 -0
- package/dist/cjs/middleware.js.map +1 -0
- package/dist/cjs/min-max-button.d.ts +7 -0
- package/dist/cjs/min-max-button.js +15 -0
- package/dist/cjs/min-max-button.js.map +1 -0
- package/dist/cjs/session.d.ts +12 -0
- package/dist/cjs/session.js +123 -0
- package/dist/cjs/session.js.map +1 -0
- package/dist/cjs/workos.d.ts +3 -0
- package/dist/cjs/workos.js +10 -0
- package/dist/cjs/workos.js.map +1 -0
- package/package.json +55 -0
- package/src/auth.ts +15 -0
- package/src/authkit-callback-route.ts +69 -0
- package/src/button.tsx +32 -0
- package/src/cookie.ts +9 -0
- package/src/env-variables.ts +18 -0
- package/src/get-authorization-url.ts +13 -0
- package/src/impersonation.tsx +157 -0
- package/src/index.ts +17 -0
- package/src/interfaces.ts +37 -0
- package/src/middleware.ts +12 -0
- package/src/min-max-button.tsx +23 -0
- package/src/session.ts +137 -0
- package/src/workos.ts +7 -0
package/src/session.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { redirect } from 'next/navigation';
|
|
2
|
+
import { cookies, headers } from 'next/headers';
|
|
3
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
4
|
+
import { jwtVerify, createRemoteJWKSet, decodeJwt } from 'jose';
|
|
5
|
+
import { sealData, unsealData } from 'iron-session';
|
|
6
|
+
import { cookieName, cookieOptions } from './cookie.js';
|
|
7
|
+
import { workos } from './workos.js';
|
|
8
|
+
import { WORKOS_CLIENT_ID, WORKOS_COOKIE_PASSWORD } from './env-variables.js';
|
|
9
|
+
import { getAuthorizationUrl } from './get-authorization-url.js';
|
|
10
|
+
import { AccessToken, NoUserInfo, Session, UserInfo } from './interfaces.js';
|
|
11
|
+
|
|
12
|
+
const sessionHeaderName = 'x-workos-session';
|
|
13
|
+
|
|
14
|
+
const JWKS = createRemoteJWKSet(new URL(workos.userManagement.getJwksUrl(WORKOS_CLIENT_ID)));
|
|
15
|
+
|
|
16
|
+
async function encryptSession(session: Session) {
|
|
17
|
+
return sealData(session, { password: WORKOS_COOKIE_PASSWORD });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function updateSession(request: NextRequest, debug: boolean) {
|
|
21
|
+
const session = await getSessionFromCookie();
|
|
22
|
+
|
|
23
|
+
// If no session, just continue
|
|
24
|
+
if (!session) {
|
|
25
|
+
return NextResponse.next();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const hasValidSession = await verifyAccessToken(session.accessToken);
|
|
29
|
+
|
|
30
|
+
const newRequestHeaders = new Headers(request.headers);
|
|
31
|
+
|
|
32
|
+
if (hasValidSession) {
|
|
33
|
+
if (debug) console.log('Session is valid');
|
|
34
|
+
// set the x-workos-session header according to the current cookie value
|
|
35
|
+
newRequestHeaders.set(sessionHeaderName, cookies().get(cookieName)!.value);
|
|
36
|
+
return NextResponse.next({
|
|
37
|
+
headers: newRequestHeaders,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
if (debug) console.log('Session invalid. Attempting refresh', session.refreshToken);
|
|
43
|
+
|
|
44
|
+
// If the session is invalid (i.e. the access token has expired) attempt to re-authenticate with the refresh token
|
|
45
|
+
const { accessToken, refreshToken } = await workos.userManagement.authenticateWithRefreshToken({
|
|
46
|
+
clientId: WORKOS_CLIENT_ID,
|
|
47
|
+
refreshToken: session.refreshToken,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if (debug) console.log('Refresh successful:', refreshToken);
|
|
51
|
+
|
|
52
|
+
// Encrypt session with new access and refresh tokens
|
|
53
|
+
const encryptedSession = await encryptSession({
|
|
54
|
+
accessToken,
|
|
55
|
+
refreshToken,
|
|
56
|
+
user: session.user,
|
|
57
|
+
impersonator: session.impersonator,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
newRequestHeaders.set(sessionHeaderName, encryptedSession);
|
|
61
|
+
|
|
62
|
+
const response = NextResponse.next({
|
|
63
|
+
request: {
|
|
64
|
+
headers: newRequestHeaders,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
// update the cookie
|
|
68
|
+
response.cookies.set(cookieName, encryptedSession, cookieOptions);
|
|
69
|
+
return response;
|
|
70
|
+
} catch (e) {
|
|
71
|
+
console.warn('Failed to refresh', e);
|
|
72
|
+
const response = NextResponse.next();
|
|
73
|
+
response.cookies.delete(cookieName);
|
|
74
|
+
return response;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function getUser(options?: { ensureSignedIn: false }): Promise<UserInfo | NoUserInfo>;
|
|
79
|
+
|
|
80
|
+
async function getUser(options: { ensureSignedIn: true }): Promise<UserInfo>;
|
|
81
|
+
|
|
82
|
+
async function getUser({ ensureSignedIn = false } = {}) {
|
|
83
|
+
const session = await getSessionFromHeader();
|
|
84
|
+
if (!session) {
|
|
85
|
+
if (ensureSignedIn) {
|
|
86
|
+
const returnPathname = headers().get('next-url') ?? undefined;
|
|
87
|
+
redirect(await getAuthorizationUrl(returnPathname));
|
|
88
|
+
}
|
|
89
|
+
return { user: null };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const { sid: sessionId, org_id: organizationId, role } = decodeJwt<AccessToken>(session.accessToken);
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
sessionId,
|
|
96
|
+
user: session.user,
|
|
97
|
+
organizationId,
|
|
98
|
+
role,
|
|
99
|
+
impersonator: session.impersonator,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function terminateSession() {
|
|
104
|
+
const { sessionId } = await getUser();
|
|
105
|
+
if (sessionId) {
|
|
106
|
+
redirect(workos.userManagement.getLogoutUrl({ sessionId }));
|
|
107
|
+
}
|
|
108
|
+
redirect('/');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function verifyAccessToken(accessToken: string) {
|
|
112
|
+
try {
|
|
113
|
+
await jwtVerify(accessToken, JWKS);
|
|
114
|
+
return true;
|
|
115
|
+
} catch (e) {
|
|
116
|
+
console.warn('Failed to verify session:', e);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function getSessionFromCookie() {
|
|
122
|
+
const cookie = cookies().get(cookieName);
|
|
123
|
+
if (cookie) {
|
|
124
|
+
return unsealData<Session>(cookie.value, {
|
|
125
|
+
password: WORKOS_COOKIE_PASSWORD,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function getSessionFromHeader(): Promise<Session | undefined> {
|
|
131
|
+
const authHeader = headers().get(sessionHeaderName);
|
|
132
|
+
if (!authHeader) return;
|
|
133
|
+
|
|
134
|
+
return unsealData<Session>(authHeader, { password: WORKOS_COOKIE_PASSWORD });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export { encryptSession, updateSession, getUser, terminateSession };
|