@growth-labs/auth 0.1.3

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 (78) hide show
  1. package/README.md +103 -0
  2. package/dist/client/login-page.d.ts +2 -0
  3. package/dist/client/login-page.d.ts.map +1 -0
  4. package/dist/client/login-page.js +13 -0
  5. package/dist/client/login-page.js.map +1 -0
  6. package/dist/config-store.d.ts +4 -0
  7. package/dist/config-store.d.ts.map +1 -0
  8. package/dist/config-store.js +15 -0
  9. package/dist/config-store.js.map +1 -0
  10. package/dist/index.d.ts +25 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +56 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/middleware/auth.d.ts +6 -0
  15. package/dist/middleware/auth.d.ts.map +1 -0
  16. package/dist/middleware/auth.js +68 -0
  17. package/dist/middleware/auth.js.map +1 -0
  18. package/dist/options.d.ts +70 -0
  19. package/dist/options.d.ts.map +1 -0
  20. package/dist/options.js +33 -0
  21. package/dist/options.js.map +1 -0
  22. package/dist/routes/callback.d.ts +9 -0
  23. package/dist/routes/callback.d.ts.map +1 -0
  24. package/dist/routes/callback.js +48 -0
  25. package/dist/routes/callback.js.map +1 -0
  26. package/dist/routes/forgot-password.d.ts +7 -0
  27. package/dist/routes/forgot-password.d.ts.map +1 -0
  28. package/dist/routes/forgot-password.js +62 -0
  29. package/dist/routes/forgot-password.js.map +1 -0
  30. package/dist/routes/login.d.ts +7 -0
  31. package/dist/routes/login.d.ts.map +1 -0
  32. package/dist/routes/login.js +80 -0
  33. package/dist/routes/login.js.map +1 -0
  34. package/dist/routes/logout.d.ts +8 -0
  35. package/dist/routes/logout.d.ts.map +1 -0
  36. package/dist/routes/logout.js +26 -0
  37. package/dist/routes/logout.js.map +1 -0
  38. package/dist/routes/reset-password.d.ts +7 -0
  39. package/dist/routes/reset-password.d.ts.map +1 -0
  40. package/dist/routes/reset-password.js +57 -0
  41. package/dist/routes/reset-password.js.map +1 -0
  42. package/dist/types.d.ts +41 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +2 -0
  45. package/dist/types.js.map +1 -0
  46. package/dist/utils/analytics.d.ts +7 -0
  47. package/dist/utils/analytics.d.ts.map +1 -0
  48. package/dist/utils/analytics.js +44 -0
  49. package/dist/utils/analytics.js.map +1 -0
  50. package/dist/utils/cookies.d.ts +17 -0
  51. package/dist/utils/cookies.d.ts.map +1 -0
  52. package/dist/utils/cookies.js +69 -0
  53. package/dist/utils/cookies.js.map +1 -0
  54. package/dist/utils/encoding.d.ts +2 -0
  55. package/dist/utils/encoding.d.ts.map +1 -0
  56. package/dist/utils/encoding.js +7 -0
  57. package/dist/utils/encoding.js.map +1 -0
  58. package/dist/utils/index.d.ts +6 -0
  59. package/dist/utils/index.d.ts.map +1 -0
  60. package/dist/utils/index.js +5 -0
  61. package/dist/utils/index.js.map +1 -0
  62. package/dist/utils/openauth.d.ts +29 -0
  63. package/dist/utils/openauth.d.ts.map +1 -0
  64. package/dist/utils/openauth.js +106 -0
  65. package/dist/utils/openauth.js.map +1 -0
  66. package/dist/utils/pkce.d.ts +5 -0
  67. package/dist/utils/pkce.d.ts.map +1 -0
  68. package/dist/utils/pkce.js +10 -0
  69. package/dist/utils/pkce.js.map +1 -0
  70. package/dist/utils/state.d.ts +3 -0
  71. package/dist/utils/state.d.ts.map +1 -0
  72. package/dist/utils/state.js +20 -0
  73. package/dist/utils/state.js.map +1 -0
  74. package/dist/utils/tokens.d.ts +12 -0
  75. package/dist/utils/tokens.d.ts.map +1 -0
  76. package/dist/utils/tokens.js +73 -0
  77. package/dist/utils/tokens.js.map +1 -0
  78. package/package.json +59 -0
@@ -0,0 +1,80 @@
1
+ import { loginPageScript } from '../client/login-page.js';
2
+ import { getConfig } from '../config-store.js';
3
+ import { setAuthFlowCookies } from '../utils/cookies.js';
4
+ import { createAuthFlow, getAuthorizationUrl, getPasswordLoginUrl, } from '../utils/openauth.js';
5
+ function _shouldShowForgotLink(options) {
6
+ return options.providers.includes('password');
7
+ }
8
+ export async function GET(context) {
9
+ const options = getConfig();
10
+ const redirectPath = context.url.searchParams.get('redirect') || '/';
11
+ const error = context.url.searchParams.get('error');
12
+ const reset = context.url.searchParams.get('reset');
13
+ const authFlow = await createAuthFlow(context);
14
+ const google = options.providers.includes('google')
15
+ ? await getAuthorizationUrl(context, 'google', redirectPath, authFlow)
16
+ : null;
17
+ const emailCode = options.providers.includes('email-code')
18
+ ? await getAuthorizationUrl(context, 'code', redirectPath, authFlow)
19
+ : null;
20
+ const html = renderLoginPage(options, { google, emailCode, redirectPath, error, reset, authFlow });
21
+ const response = new Response(html, {
22
+ headers: { 'Content-Type': 'text/html; charset=utf-8' },
23
+ });
24
+ setAuthFlowCookies(response, options, authFlow.verifier, authFlow.state, redirectPath);
25
+ return response;
26
+ }
27
+ function renderLoginPage(options, data) {
28
+ const { loginPage, providers } = options;
29
+ const hasPassword = providers.includes('password');
30
+ const passwordUrl = getPasswordLoginUrl({ url: new URL(options.issuer) });
31
+ return `<!DOCTYPE html>
32
+ <html lang="en">
33
+ <head>
34
+ <meta charset="utf-8">
35
+ <meta name="viewport" content="width=device-width, initial-scale=1">
36
+ <title>${loginPage.title}</title>
37
+ <style>
38
+ body { font-family: system-ui, sans-serif; max-width: 400px; margin: 80px auto; padding: 0 20px; }
39
+ h1 { text-align: center; }
40
+ .logo { display: block; margin: 0 auto 16px; max-height: 48px; }
41
+ .btn { display: block; width: 100%; padding: 12px; margin: 8px 0; border: 1px solid #ccc; border-radius: 6px; font-size: 16px; cursor: pointer; text-align: center; text-decoration: none; box-sizing: border-box; }
42
+ .btn-google { background: #4285f4; color: white; border: none; }
43
+ .divider { text-align: center; margin: 20px 0; color: #888; }
44
+ input[type="email"], input[type="password"] { display: block; width: 100%; padding: 10px; margin: 8px 0; border: 1px solid #ccc; border-radius: 6px; font-size: 16px; box-sizing: border-box; }
45
+ .error { color: #c00; text-align: center; margin: 12px 0; }
46
+ .success { color: #080; text-align: center; margin: 12px 0; }
47
+ .brand { text-align: center; color: #666; margin-bottom: 4px; }
48
+ .forgot-link { display: block; text-align: right; font-size: 14px; margin: -4px 0 8px; color: #555; }
49
+ </style>
50
+ </head>
51
+ <body>
52
+ ${loginPage.logoUrl ? `<img src="${loginPage.logoUrl}" alt="${loginPage.brandName || ''}" class="logo">` : ''}
53
+ ${loginPage.brandName ? `<p class="brand">${loginPage.brandName}</p>` : ''}
54
+ <h1>${loginPage.title}</h1>
55
+ ${data.reset ? '<p class="success">Password reset successfully. Sign in with your new password.</p>' : ''}
56
+ ${data.error ? '<p class="error">Authentication failed. Please try again.</p>' : ''}
57
+ ${data.google ? `<a href="${data.google.url}" class="btn btn-google" data-provider="google">Sign in with Google</a>` : ''}
58
+ ${data.google && (hasPassword || data.emailCode) ? '<div class="divider">or</div>' : ''}
59
+ ${data.emailCode
60
+ ? `<a href="${data.emailCode.url}" class="btn" data-provider="email-code">Sign in with email</a>`
61
+ : ''}
62
+ ${hasPassword
63
+ ? `
64
+ <form method="POST" action="${passwordUrl}">
65
+ <input type="email" name="email" placeholder="Email address" required>
66
+ <input type="password" name="password" placeholder="Password" required>
67
+ <a href="${options.forgotPasswordPath}" class="forgot-link">Forgot password?</a>
68
+ <input type="hidden" name="redirect_uri" value="${data.authFlow.redirectUri}">
69
+ <input type="hidden" name="client_id" value="${data.authFlow.clientId}">
70
+ <input type="hidden" name="state" value="${data.authFlow.state}">
71
+ <input type="hidden" name="code_challenge" value="${data.authFlow.challenge}">
72
+ <input type="hidden" name="code_challenge_method" value="S256">
73
+ <button type="submit" class="btn" data-provider="password">Sign in with password</button>
74
+ </form>`
75
+ : ''}
76
+ <script>${loginPageScript()}</script>
77
+ </body>
78
+ </html>`;
79
+ }
80
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/routes/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface LogoutContext {
2
+ request: Request;
3
+ url: URL;
4
+ waitUntil?: (promise: Promise<unknown>) => void;
5
+ }
6
+ export declare function GET(context: LogoutContext): Promise<Response>;
7
+ export {};
8
+ //# sourceMappingURL=logout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAIA,UAAU,aAAa;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;IACR,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CAC/C;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0BnE"}
@@ -0,0 +1,26 @@
1
+ import { getConfig } from '../config-store.js';
2
+ import { clearCookie, clearTokenCookies, getCookie } from '../utils/cookies.js';
3
+ import { revokeToken } from '../utils/openauth.js';
4
+ export async function GET(context) {
5
+ const options = getConfig();
6
+ const refreshToken = getCookie(context.request, `${options.cookiePrefix}_rt`);
7
+ const clientId = options.clientId || context.url.hostname;
8
+ // Revoke at issuer (non-blocking)
9
+ if (refreshToken) {
10
+ const promise = revokeToken(refreshToken, clientId);
11
+ context.waitUntil?.(promise);
12
+ }
13
+ // Build redirect response
14
+ const redirectUrl = new URL(options.logoutRedirect, context.url.origin).toString();
15
+ const response = Response.redirect(redirectUrl, 302);
16
+ // Mutable copy for clearing cookies
17
+ const mutableResponse = new Response(response.body, {
18
+ status: response.status,
19
+ statusText: response.statusText,
20
+ headers: new Headers(response.headers),
21
+ });
22
+ clearTokenCookies(mutableResponse, options);
23
+ clearCookie(mutableResponse, `${options.cookiePrefix}_pkce`);
24
+ return mutableResponse;
25
+ }
26
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/routes/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/E,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAQlD,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAAsB;IAC/C,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAC3B,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,YAAY,KAAK,CAAC,CAAA;IAC7E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAA;IAEzD,kCAAkC;IAClC,IAAI,YAAY,EAAE,CAAC;QAClB,MAAM,OAAO,GAAG,WAAW,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAA;QACnD,OAAO,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;IAED,0BAA0B;IAC1B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;IAClF,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IAEpD,oCAAoC;IACpC,MAAM,eAAe,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE;QACnD,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,OAAO,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;KACtC,CAAC,CAAA;IAEF,iBAAiB,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAC3C,WAAW,CAAC,eAAe,EAAE,GAAG,OAAO,CAAC,YAAY,OAAO,CAAC,CAAA;IAE5D,OAAO,eAAe,CAAA;AACvB,CAAC"}
@@ -0,0 +1,7 @@
1
+ interface ResetPasswordContext {
2
+ request: Request;
3
+ url: URL;
4
+ }
5
+ export declare function GET(context: ResetPasswordContext): Promise<Response>;
6
+ export {};
7
+ //# sourceMappingURL=reset-password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-password.d.ts","sourceRoot":"","sources":["../../src/routes/reset-password.ts"],"names":[],"mappings":"AAGA,UAAU,oBAAoB;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;CACR;AAED,wBAAsB,GAAG,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkB1E"}
@@ -0,0 +1,57 @@
1
+ import { getConfig } from '../config-store.js';
2
+ import { getResetPasswordUrl } from '../utils/openauth.js';
3
+ export async function GET(context) {
4
+ const options = getConfig();
5
+ if (!options.providers.includes('password')) {
6
+ return new Response('Not found', { status: 404 });
7
+ }
8
+ const token = context.url.searchParams.get('token');
9
+ if (!token) {
10
+ return new Response('Missing reset token', { status: 400 });
11
+ }
12
+ const error = context.url.searchParams.get('error');
13
+ const html = renderResetPasswordPage(options, context.url, { token, error });
14
+ return new Response(html, {
15
+ headers: { 'Content-Type': 'text/html; charset=utf-8' },
16
+ });
17
+ }
18
+ function renderResetPasswordPage(options, url, data) {
19
+ const { loginPage } = options;
20
+ const actionUrl = getResetPasswordUrl();
21
+ const redirectUri = new URL(`${options.loginPath}?reset=true`, url.origin).toString();
22
+ return `<!DOCTYPE html>
23
+ <html lang="en">
24
+ <head>
25
+ <meta charset="utf-8">
26
+ <meta name="viewport" content="width=device-width, initial-scale=1">
27
+ <title>Reset password</title>
28
+ <style>
29
+ body { font-family: system-ui, sans-serif; max-width: 400px; margin: 80px auto; padding: 0 20px; }
30
+ h1 { text-align: center; }
31
+ .logo { display: block; margin: 0 auto 16px; max-height: 48px; }
32
+ .btn { display: block; width: 100%; padding: 12px; margin: 8px 0; border: 1px solid #ccc; border-radius: 6px; font-size: 16px; cursor: pointer; text-align: center; text-decoration: none; box-sizing: border-box; }
33
+ input[type="password"] { display: block; width: 100%; padding: 10px; margin: 8px 0; border: 1px solid #ccc; border-radius: 6px; font-size: 16px; box-sizing: border-box; }
34
+ .error { color: #c00; text-align: center; margin: 12px 0; }
35
+ .brand { text-align: center; color: #666; margin-bottom: 4px; }
36
+ .back-link { display: block; text-align: center; margin-top: 16px; font-size: 14px; color: #555; }
37
+ p.hint { text-align: center; color: #666; font-size: 14px; }
38
+ </style>
39
+ </head>
40
+ <body>
41
+ ${loginPage.logoUrl ? `<img src="${loginPage.logoUrl}" alt="${loginPage.brandName || ''}" class="logo">` : ''}
42
+ ${loginPage.brandName ? `<p class="brand">${loginPage.brandName}</p>` : ''}
43
+ <h1>Reset password</h1>
44
+ ${data.error ? '<p class="error">This reset link is invalid or has expired. Please request a new one.</p>' : ''}
45
+ <p class="hint">Enter your new password.</p>
46
+ <form method="POST" action="${actionUrl}">
47
+ <input type="password" name="password" placeholder="New password" required minlength="8">
48
+ <input type="password" name="password_confirmation" placeholder="Confirm password" required minlength="8">
49
+ <input type="hidden" name="token" value="${data.token}">
50
+ <input type="hidden" name="redirect_uri" value="${redirectUri}">
51
+ <button type="submit" class="btn">Reset password</button>
52
+ </form>
53
+ <a href="${options.loginPath}" class="back-link">Back to sign in</a>
54
+ </body>
55
+ </html>`;
56
+ }
57
+ //# sourceMappingURL=reset-password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-password.js","sourceRoot":"","sources":["../../src/routes/reset-password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAO1D,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAA6B;IACtD,MAAM,OAAO,GAAG,SAAS,EAAE,CAAA;IAE3B,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAClD,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,IAAI,QAAQ,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;IAC5D,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACnD,MAAM,IAAI,GAAG,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;IAE5E,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;QACzB,OAAO,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE;KACvD,CAAC,CAAA;AACH,CAAC;AAOD,SAAS,uBAAuB,CAC/B,OAAqC,EACrC,GAAQ,EACR,IAA2B;IAE3B,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAA;IAC7B,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAA;IACvC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,SAAS,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAA;IAErF,OAAO;;;;;;;;;;;;;;;;;;;IAmBJ,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,SAAS,CAAC,OAAO,UAAU,SAAS,CAAC,SAAS,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE;IAC3G,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,oBAAoB,SAAS,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,EAAE;;IAExE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,2FAA2F,CAAC,CAAC,CAAC,EAAE;;gCAEjF,SAAS;;;+CAGM,IAAI,CAAC,KAAK;sDACH,WAAW;;;aAGpD,OAAO,CAAC,SAAS;;QAEtB,CAAA;AACR,CAAC"}
@@ -0,0 +1,41 @@
1
+ export interface AuthenticatedUser {
2
+ id: string;
3
+ email: string;
4
+ name?: string;
5
+ image?: string;
6
+ authenticated: true;
7
+ }
8
+ export interface UnauthenticatedUser {
9
+ authenticated: false;
10
+ }
11
+ export type User = AuthenticatedUser | UnauthenticatedUser;
12
+ export interface TokenRefreshResult {
13
+ accessToken: string;
14
+ refreshToken: string;
15
+ claims: {
16
+ sub: string;
17
+ email: string;
18
+ name?: string;
19
+ image?: string;
20
+ };
21
+ }
22
+ export interface TokenExchangeResult {
23
+ accessToken: string;
24
+ refreshToken: string;
25
+ isNewUser: boolean;
26
+ provider: string;
27
+ claims: {
28
+ sub: string;
29
+ email: string;
30
+ name?: string;
31
+ image?: string;
32
+ };
33
+ }
34
+ declare global {
35
+ namespace App {
36
+ interface Locals {
37
+ user: User;
38
+ }
39
+ }
40
+ }
41
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,KAAK,CAAA;CACpB;AAED,MAAM,MAAM,IAAI,GAAG,iBAAiB,GAAG,mBAAmB,CAAA;AAE1D,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE;QACP,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACD;AAED,MAAM,WAAW,mBAAmB;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE;QACP,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACD;AAGD,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,GAAG,CAAC;QACb,UAAU,MAAM;YACf,IAAI,EAAE,IAAI,CAAA;SACV;KACD;CACD"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ export declare function emitAuthEvent(context: unknown, eventName: string, data: Record<string, string>): Promise<void>;
2
+ export declare function analyticsAvailable(context: {
3
+ locals?: Record<string, unknown>;
4
+ }): boolean;
5
+ export declare function trackAuthEvent(context: unknown, eventName: string, data?: Record<string, string>): Promise<void>;
6
+ export declare function _resetAnalytics(): void;
7
+ //# sourceMappingURL=analytics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/utils/analytics.ts"],"names":[],"mappings":"AA6BA,wBAAsB,aAAa,CAClC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,OAAO,CAEzF;AAED,wBAAsB,cAAc,CACnC,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAC/B,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,eAAe,IAAI,IAAI,CAGtC"}
@@ -0,0 +1,44 @@
1
+ let trackFn = null;
2
+ let resolved = false;
3
+ const ANALYTICS_UTILS_MODULE = '@growth-labs/analytics/utils';
4
+ async function importOptionalModule(modulePath) {
5
+ try {
6
+ return (await import(/* @vite-ignore */ modulePath));
7
+ }
8
+ catch {
9
+ return null;
10
+ }
11
+ }
12
+ async function resolveAnalytics() {
13
+ if (resolved)
14
+ return;
15
+ resolved = true;
16
+ const mod = await importOptionalModule(ANALYTICS_UTILS_MODULE);
17
+ let candidate;
18
+ try {
19
+ candidate = mod?.trackServerEvent;
20
+ }
21
+ catch {
22
+ candidate = undefined;
23
+ }
24
+ if (typeof candidate === 'function') {
25
+ trackFn = candidate;
26
+ }
27
+ }
28
+ export async function emitAuthEvent(context, eventName, data) {
29
+ await resolveAnalytics();
30
+ if (!trackFn)
31
+ return;
32
+ return trackFn(context, eventName, data);
33
+ }
34
+ export function analyticsAvailable(context) {
35
+ return typeof context.locals?.analyticsConfig !== 'undefined';
36
+ }
37
+ export async function trackAuthEvent(context, eventName, data = {}) {
38
+ return emitAuthEvent(context, eventName, data);
39
+ }
40
+ export function _resetAnalytics() {
41
+ trackFn = null;
42
+ resolved = false;
43
+ }
44
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/utils/analytics.ts"],"names":[],"mappings":"AAEA,IAAI,OAAO,GAAmB,IAAI,CAAA;AAClC,IAAI,QAAQ,GAAG,KAAK,CAAA;AACpB,MAAM,sBAAsB,GAAG,8BAA8B,CAAA;AAE7D,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IACrD,IAAI,CAAC;QACJ,OAAO,CAAC,MAAM,MAAM,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAA4B,CAAA;IAChF,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAA;IACZ,CAAC;AACF,CAAC;AAED,KAAK,UAAU,gBAAgB;IAC9B,IAAI,QAAQ;QAAE,OAAM;IACpB,QAAQ,GAAG,IAAI,CAAA;IACf,MAAM,GAAG,GAAG,MAAM,oBAAoB,CAAC,sBAAsB,CAAC,CAAA;IAC9D,IAAI,SAAkB,CAAA;IACtB,IAAI,CAAC;QACJ,SAAS,GAAG,GAAG,EAAE,gBAAgB,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACR,SAAS,GAAG,SAAS,CAAA;IACtB,CAAC;IACD,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACrC,OAAO,GAAG,SAAoB,CAAA;IAC/B,CAAC;AACF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAClC,OAAgB,EAChB,SAAiB,EACjB,IAA4B;IAE5B,MAAM,gBAAgB,EAAE,CAAA;IACxB,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,OAAO,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAA6C;IAC/E,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,eAAe,KAAK,WAAW,CAAA;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CACnC,OAAgB,EAChB,SAAiB,EACjB,OAA+B,EAAE;IAEjC,OAAO,aAAa,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;AAC/C,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,OAAO,GAAG,IAAI,CAAA;IACd,QAAQ,GAAG,KAAK,CAAA;AACjB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { ResolvedAuthOptions } from '../options.js';
2
+ export interface CookieAttributes {
3
+ path?: string;
4
+ maxAge?: number;
5
+ httpOnly?: boolean;
6
+ secure?: boolean;
7
+ sameSite?: 'strict' | 'lax' | 'none';
8
+ domain?: string;
9
+ }
10
+ export declare function getCookie(request: Request, name: string): string | null;
11
+ export declare function setCookie(response: Response, name: string, value: string, attributes?: CookieAttributes): void;
12
+ export declare function clearCookie(response: Response, name: string, domain?: string): void;
13
+ export declare function setTokenCookies(response: Response, options: ResolvedAuthOptions, accessToken: string, refreshToken: string): void;
14
+ export declare function clearTokenCookies(response: Response, options: ResolvedAuthOptions): void;
15
+ export declare function clearAuthFlowCookies(response: Response, options: ResolvedAuthOptions): void;
16
+ export declare function setAuthFlowCookies(response: Response, options: ResolvedAuthOptions, verifier: string, state: string, redirectPath: string): void;
17
+ //# sourceMappingURL=cookies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/utils/cookies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAExD,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKvE;AAED,wBAAgB,SAAS,CACxB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,gBAAqB,GAC/B,IAAI,CASN;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAMnF;AAED,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,EAC5B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GAClB,IAAI,CAgBN;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAGxF;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAI3F;AAED,wBAAgB,kBAAkB,CACjC,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,mBAAmB,EAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,GAClB,IAAI,CAWN"}
@@ -0,0 +1,69 @@
1
+ export function getCookie(request, name) {
2
+ const header = request.headers.get('cookie');
3
+ if (!header)
4
+ return null;
5
+ const match = header.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
6
+ return match ? decodeURIComponent(match[1]) : null;
7
+ }
8
+ export function setCookie(response, name, value, attributes = {}) {
9
+ const parts = [`${name}=${encodeURIComponent(value)}`];
10
+ if (attributes.path)
11
+ parts.push(`Path=${attributes.path}`);
12
+ if (attributes.maxAge !== undefined)
13
+ parts.push(`Max-Age=${attributes.maxAge}`);
14
+ if (attributes.httpOnly)
15
+ parts.push('HttpOnly');
16
+ if (attributes.secure)
17
+ parts.push('Secure');
18
+ if (attributes.sameSite)
19
+ parts.push(`SameSite=${attributes.sameSite}`);
20
+ if (attributes.domain)
21
+ parts.push(`Domain=${attributes.domain}`);
22
+ response.headers.append('Set-Cookie', parts.join('; '));
23
+ }
24
+ export function clearCookie(response, name, domain) {
25
+ setCookie(response, name, '', {
26
+ path: '/',
27
+ maxAge: 0,
28
+ ...(domain && { domain }),
29
+ });
30
+ }
31
+ export function setTokenCookies(response, options, accessToken, refreshToken) {
32
+ const base = {
33
+ path: '/',
34
+ httpOnly: true,
35
+ secure: true,
36
+ sameSite: 'lax',
37
+ ...(options.sessionCookieDomain && { domain: options.sessionCookieDomain }),
38
+ };
39
+ setCookie(response, `${options.cookiePrefix}_at`, accessToken, {
40
+ ...base,
41
+ maxAge: options.accessTokenMaxAge,
42
+ });
43
+ setCookie(response, `${options.cookiePrefix}_rt`, refreshToken, {
44
+ ...base,
45
+ maxAge: options.refreshTokenMaxAge,
46
+ });
47
+ }
48
+ export function clearTokenCookies(response, options) {
49
+ clearCookie(response, `${options.cookiePrefix}_at`, options.sessionCookieDomain);
50
+ clearCookie(response, `${options.cookiePrefix}_rt`, options.sessionCookieDomain);
51
+ }
52
+ export function clearAuthFlowCookies(response, options) {
53
+ clearCookie(response, `${options.cookiePrefix}_pkce`);
54
+ clearCookie(response, `${options.cookiePrefix}_state`);
55
+ clearCookie(response, `${options.cookiePrefix}_redirect`);
56
+ }
57
+ export function setAuthFlowCookies(response, options, verifier, state, redirectPath) {
58
+ const attrs = {
59
+ path: '/',
60
+ httpOnly: true,
61
+ secure: true,
62
+ sameSite: 'lax',
63
+ maxAge: 600,
64
+ };
65
+ setCookie(response, `${options.cookiePrefix}_pkce`, verifier, attrs);
66
+ setCookie(response, `${options.cookiePrefix}_state`, state, attrs);
67
+ setCookie(response, `${options.cookiePrefix}_redirect`, redirectPath, attrs);
68
+ }
69
+ //# sourceMappingURL=cookies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookies.js","sourceRoot":"","sources":["../../src/utils/cookies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function base64url(bytes: Uint8Array): string;
2
+ //# sourceMappingURL=encoding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/utils/encoding.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAInD"}
@@ -0,0 +1,7 @@
1
+ export function base64url(bytes) {
2
+ let binary = '';
3
+ for (const byte of bytes)
4
+ binary += String.fromCharCode(byte);
5
+ return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
6
+ }
7
+ //# sourceMappingURL=encoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../src/utils/encoding.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,KAAiB;IAC1C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAC7D,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;AAChF,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { emitAuthEvent, trackAuthEvent } from './analytics.js';
2
+ export { getAuthorizationUrl, getMagicLinkUrl, getPasswordLoginUrl } from './openauth.js';
3
+ export { generatePKCE } from './pkce.js';
4
+ export { generateState, verifyState } from './state.js';
5
+ export type { VerifiedClaims } from './tokens.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACvD,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
@@ -0,0 +1,5 @@
1
+ export { emitAuthEvent, trackAuthEvent } from './analytics.js';
2
+ export { getAuthorizationUrl, getMagicLinkUrl, getPasswordLoginUrl } from './openauth.js';
3
+ export { generatePKCE } from './pkce.js';
4
+ export { generateState, verifyState } from './state.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1,29 @@
1
+ import type { TokenExchangeResult } from '../types.js';
2
+ export interface AuthFlow {
3
+ verifier: string;
4
+ challenge: string;
5
+ state: string;
6
+ clientId: string;
7
+ redirectUri: string;
8
+ }
9
+ export declare function createAuthFlow(context: {
10
+ url: URL;
11
+ }): Promise<AuthFlow>;
12
+ export declare function getAuthorizationUrl(context: {
13
+ url: URL;
14
+ }, provider: string, _redirectPath: string, authFlow?: AuthFlow): Promise<{
15
+ url: string;
16
+ pkceVerifier: string;
17
+ state: string;
18
+ }>;
19
+ export declare function getPasswordLoginUrl(_context: {
20
+ url: URL;
21
+ }): string;
22
+ export declare function getMagicLinkUrl(_context: {
23
+ url: URL;
24
+ }): string;
25
+ export declare function getForgotPasswordUrl(): string;
26
+ export declare function getResetPasswordUrl(): string;
27
+ export declare function exchangeCode(callbackUrl: URL, code: string, codeVerifier: string): Promise<TokenExchangeResult | null>;
28
+ export declare function revokeToken(refreshToken: string, clientId?: string): Promise<void>;
29
+ //# sourceMappingURL=openauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openauth.d.ts","sourceRoot":"","sources":["../../src/utils/openauth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAKtD,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAY7E;AAED,wBAAsB,mBAAmB,CACxC,OAAO,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,EACrB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB/D;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAGlE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,MAAM,CAG9D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAG7C;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;AAED,wBAAsB,YAAY,CACjC,WAAW,EAAE,GAAG,EAChB,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CA4CrC;AAED,wBAAsB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAexF"}
@@ -0,0 +1,106 @@
1
+ import { getConfig } from '../config-store.js';
2
+ import { generatePKCE } from './pkce.js';
3
+ import { generateState } from './state.js';
4
+ import { decodeJwtPayload } from './tokens.js';
5
+ export async function createAuthFlow(context) {
6
+ const options = getConfig();
7
+ const { verifier, challenge } = await generatePKCE();
8
+ const state = generateState();
9
+ return {
10
+ verifier,
11
+ challenge,
12
+ state,
13
+ clientId: options.clientId || context.url.hostname,
14
+ redirectUri: new URL(options.callbackPath, context.url.origin).toString(),
15
+ };
16
+ }
17
+ export async function getAuthorizationUrl(context, provider, _redirectPath, authFlow) {
18
+ const options = getConfig();
19
+ const flow = authFlow ?? (await createAuthFlow(context));
20
+ const params = new URLSearchParams({
21
+ response_type: 'code',
22
+ client_id: flow.clientId,
23
+ redirect_uri: flow.redirectUri,
24
+ scope: 'openid email profile',
25
+ state: flow.state,
26
+ code_challenge: flow.challenge,
27
+ code_challenge_method: 'S256',
28
+ provider,
29
+ });
30
+ return {
31
+ url: `${options.issuer}/authorize?${params}`,
32
+ pkceVerifier: flow.verifier,
33
+ state: flow.state,
34
+ };
35
+ }
36
+ export function getPasswordLoginUrl(_context) {
37
+ const options = getConfig();
38
+ return `${options.issuer}/authorize/password`;
39
+ }
40
+ export function getMagicLinkUrl(_context) {
41
+ const options = getConfig();
42
+ return `${options.issuer}/authorize/email-code`;
43
+ }
44
+ export function getForgotPasswordUrl() {
45
+ const options = getConfig();
46
+ return `${options.issuer}/forgot-password`;
47
+ }
48
+ export function getResetPasswordUrl() {
49
+ const options = getConfig();
50
+ return `${options.issuer}/reset-password`;
51
+ }
52
+ export async function exchangeCode(callbackUrl, code, codeVerifier) {
53
+ const options = getConfig();
54
+ const clientId = options.clientId || callbackUrl.hostname;
55
+ const redirectUri = new URL(options.callbackPath, callbackUrl.origin).toString();
56
+ try {
57
+ const response = await fetch(`${options.issuer}/token`, {
58
+ method: 'POST',
59
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
60
+ body: new URLSearchParams({
61
+ grant_type: 'authorization_code',
62
+ code,
63
+ code_verifier: codeVerifier,
64
+ redirect_uri: redirectUri,
65
+ client_id: clientId,
66
+ }).toString(),
67
+ });
68
+ if (!response.ok)
69
+ return null;
70
+ const data = (await response.json());
71
+ const claims = decodeJwtPayload(data.access_token);
72
+ return {
73
+ accessToken: data.access_token,
74
+ refreshToken: data.refresh_token,
75
+ isNewUser: data.is_new_user || false,
76
+ provider: data.provider || 'unknown',
77
+ claims: {
78
+ sub: claims.sub,
79
+ email: claims.email,
80
+ name: claims.name,
81
+ image: claims.image,
82
+ },
83
+ };
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ export async function revokeToken(refreshToken, clientId) {
90
+ const options = getConfig();
91
+ try {
92
+ await fetch(`${options.issuer}/revoke`, {
93
+ method: 'POST',
94
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
95
+ body: new URLSearchParams({
96
+ token: refreshToken,
97
+ token_type_hint: 'refresh_token',
98
+ ...(clientId && { client_id: clientId }),
99
+ }).toString(),
100
+ });
101
+ }
102
+ catch {
103
+ // Fire and forget — ignore errors
104
+ }
105
+ }
106
+ //# sourceMappingURL=openauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openauth.js","sourceRoot":"","sources":["../../src/utils/openauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function generatePKCE(): Promise<{
2
+ verifier: string;
3
+ challenge: string;
4
+ }>;
5
+ //# sourceMappingURL=pkce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../src/utils/pkce.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CASrF"}