@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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +145 -0
  3. package/dist/cjs/auth.d.ts +3 -0
  4. package/dist/cjs/auth.js +17 -0
  5. package/dist/cjs/auth.js.map +1 -0
  6. package/dist/cjs/authkit-callback-route.d.ts +3 -0
  7. package/dist/cjs/authkit-callback-route.js +58 -0
  8. package/dist/cjs/authkit-callback-route.js.map +1 -0
  9. package/dist/cjs/button.d.ts +3 -0
  10. package/dist/cjs/button.js +25 -0
  11. package/dist/cjs/button.js.map +1 -0
  12. package/dist/cjs/cookie.d.ts +8 -0
  13. package/dist/cjs/cookie.js +13 -0
  14. package/dist/cjs/cookie.js.map +1 -0
  15. package/dist/cjs/env-variables.d.ts +5 -0
  16. package/dist/cjs/env-variables.js +22 -0
  17. package/dist/cjs/env-variables.js.map +1 -0
  18. package/dist/cjs/get-authorization-url.d.ts +2 -0
  19. package/dist/cjs/get-authorization-url.js +15 -0
  20. package/dist/cjs/get-authorization-url.js.map +1 -0
  21. package/dist/cjs/impersonation.d.ts +6 -0
  22. package/dist/cjs/impersonation.js +119 -0
  23. package/dist/cjs/impersonation.js.map +1 -0
  24. package/dist/cjs/index.d.ts +6 -0
  25. package/dist/cjs/index.js +15 -0
  26. package/dist/cjs/index.js.map +1 -0
  27. package/dist/cjs/interfaces.d.ts +33 -0
  28. package/dist/cjs/interfaces.js +3 -0
  29. package/dist/cjs/interfaces.js.map +1 -0
  30. package/dist/cjs/middleware.d.ts +6 -0
  31. package/dist/cjs/middleware.js +11 -0
  32. package/dist/cjs/middleware.js.map +1 -0
  33. package/dist/cjs/min-max-button.d.ts +7 -0
  34. package/dist/cjs/min-max-button.js +15 -0
  35. package/dist/cjs/min-max-button.js.map +1 -0
  36. package/dist/cjs/session.d.ts +12 -0
  37. package/dist/cjs/session.js +123 -0
  38. package/dist/cjs/session.js.map +1 -0
  39. package/dist/cjs/workos.d.ts +3 -0
  40. package/dist/cjs/workos.js +10 -0
  41. package/dist/cjs/workos.js.map +1 -0
  42. package/package.json +55 -0
  43. package/src/auth.ts +15 -0
  44. package/src/authkit-callback-route.ts +69 -0
  45. package/src/button.tsx +32 -0
  46. package/src/cookie.ts +9 -0
  47. package/src/env-variables.ts +18 -0
  48. package/src/get-authorization-url.ts +13 -0
  49. package/src/impersonation.tsx +157 -0
  50. package/src/index.ts +17 -0
  51. package/src/interfaces.ts +37 -0
  52. package/src/middleware.ts +12 -0
  53. package/src/min-max-button.tsx +23 -0
  54. package/src/session.ts +137 -0
  55. 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 };
package/src/workos.ts ADDED
@@ -0,0 +1,7 @@
1
+ import WorkOS from '@workos-inc/node';
2
+ import { WORKOS_API_KEY } from './env-variables.js';
3
+
4
+ // Initialize the WorkOS client
5
+ const workos = new WorkOS(WORKOS_API_KEY);
6
+
7
+ export { workos };