@growth-labs/auth 0.7.0 → 0.7.2

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 (43) hide show
  1. package/dist/index.d.ts.map +1 -1
  2. package/dist/index.js +4 -1
  3. package/dist/index.js.map +1 -1
  4. package/package.json +7 -2
  5. package/src/client/login-page.ts +12 -0
  6. package/src/cloudflare-workers.d.ts +3 -0
  7. package/src/config-store.ts +70 -0
  8. package/src/index.ts +177 -0
  9. package/src/middleware/auth.ts +88 -0
  10. package/src/options.ts +75 -0
  11. package/src/renderers.ts +182 -0
  12. package/src/routes/api/code-request.ts +33 -0
  13. package/src/routes/api/code-verify.ts +35 -0
  14. package/src/routes/api/password-reset-confirm.ts +36 -0
  15. package/src/routes/api/password-reset-request.ts +32 -0
  16. package/src/routes/api/password-verify.ts +35 -0
  17. package/src/routes/api/shared.ts +130 -0
  18. package/src/routes/callback.ts +105 -0
  19. package/src/routes/flow.ts +53 -0
  20. package/src/routes/forgot-password.ts +31 -0
  21. package/src/routes/login.ts +130 -0
  22. package/src/routes/logout.ts +59 -0
  23. package/src/routes/password.ts +27 -0
  24. package/src/routes/reset-password.ts +33 -0
  25. package/src/routes/verify-code.ts +28 -0
  26. package/src/runtime-bridge.ts +15 -0
  27. package/src/runtime.ts +5 -0
  28. package/src/server.ts +185 -0
  29. package/src/types.ts +158 -0
  30. package/src/utils/analytics.ts +56 -0
  31. package/src/utils/client-secret.ts +21 -0
  32. package/src/utils/cookies.ts +134 -0
  33. package/src/utils/encoding.ts +5 -0
  34. package/src/utils/env-marker.ts +39 -0
  35. package/src/utils/identity-cookie.ts +138 -0
  36. package/src/utils/identity.ts +240 -0
  37. package/src/utils/index.ts +19 -0
  38. package/src/utils/issuer.ts +7 -0
  39. package/src/utils/openauth.ts +163 -0
  40. package/src/utils/pkce.ts +16 -0
  41. package/src/utils/state.ts +20 -0
  42. package/src/utils/tokens.ts +128 -0
  43. package/src/virtual.d.ts +5 -0
@@ -0,0 +1,128 @@
1
+ import { createLocalJWKSet, jwtVerify } from 'jose'
2
+ import type { TokenRefreshResult } from '../types.js'
3
+ import { createClientSecretBasicAuthHeader } from './client-secret.js'
4
+
5
+ type JWKSFunction = ReturnType<typeof createLocalJWKSet>
6
+
7
+ const jwksCache = new Map<string, JWKSFunction>()
8
+
9
+ async function getJWKS(issuer: string): Promise<JWKSFunction> {
10
+ let jwks = jwksCache.get(issuer)
11
+ if (jwks) return jwks
12
+
13
+ const response = await fetch(`${issuer}/.well-known/jwks.json`)
14
+ if (!response.ok) throw new Error(`JWKS fetch failed: ${response.status}`)
15
+ const data = (await response.json()) as { keys: JsonWebKey[] }
16
+ jwks = createLocalJWKSet(data)
17
+ jwksCache.set(issuer, jwks)
18
+ return jwks
19
+ }
20
+
21
+ export interface VerifiedClaims {
22
+ sub: string
23
+ email: string
24
+ name?: string | null
25
+ image?: string
26
+ }
27
+
28
+ export interface TokenPayloadClaims extends VerifiedClaims {
29
+ isNewUser: boolean
30
+ }
31
+
32
+ export function extractTokenClaims(payload: Record<string, unknown>): TokenPayloadClaims {
33
+ const properties = (payload.properties ?? {}) as Record<string, unknown>
34
+ const topLevelIsNewUser = payload.isNewUser
35
+
36
+ return {
37
+ sub: payload.sub as string,
38
+ email: (properties.email ?? payload.email) as string,
39
+ name: (properties.name ?? payload.name) as string | undefined,
40
+ image: (properties.image ?? payload.image) as string | undefined,
41
+ isNewUser: Boolean(properties.isNewUser ?? topLevelIsNewUser),
42
+ }
43
+ }
44
+
45
+ export async function verifyAccessToken(
46
+ issuer: string,
47
+ token: string,
48
+ ): Promise<VerifiedClaims | null> {
49
+ try {
50
+ const jwks = await getJWKS(issuer)
51
+ const { payload } = await jwtVerify(token, jwks, { issuer })
52
+ const claims = extractTokenClaims(payload as Record<string, unknown>)
53
+ return {
54
+ sub: claims.sub,
55
+ email: claims.email,
56
+ name: claims.name,
57
+ image: claims.image,
58
+ }
59
+ } catch (err) {
60
+ console.error('verifyAccessToken error:', err)
61
+ return null
62
+ }
63
+ }
64
+
65
+ export async function refreshTokens(
66
+ issuer: string,
67
+ refreshToken: string,
68
+ clientId?: string,
69
+ clientSecret?: string,
70
+ resource?: string,
71
+ ): Promise<TokenRefreshResult | null> {
72
+ try {
73
+ const params = new URLSearchParams({
74
+ grant_type: 'refresh_token',
75
+ refresh_token: refreshToken,
76
+ })
77
+ if (clientId) params.set('client_id', clientId)
78
+ if (resource) params.set('resource', resource)
79
+
80
+ const headers: Record<string, string> = {
81
+ 'Content-Type': 'application/x-www-form-urlencoded',
82
+ }
83
+ if (clientId && clientSecret) {
84
+ headers.Authorization = createClientSecretBasicAuthHeader(clientId, clientSecret)
85
+ }
86
+
87
+ const response = await fetch(`${issuer}/token`, {
88
+ method: 'POST',
89
+ headers,
90
+ body: params.toString(),
91
+ })
92
+
93
+ if (!response.ok) return null
94
+
95
+ const data = (await response.json()) as {
96
+ access_token: string
97
+ refresh_token: string
98
+ }
99
+
100
+ const claims = extractTokenClaims(decodeJwtPayload(data.access_token))
101
+
102
+ return {
103
+ accessToken: data.access_token,
104
+ refreshToken: data.refresh_token,
105
+ claims: {
106
+ sub: claims.sub,
107
+ email: claims.email,
108
+ name: claims.name,
109
+ image: claims.image,
110
+ },
111
+ }
112
+ } catch {
113
+ return null
114
+ }
115
+ }
116
+
117
+ export function decodeJwtPayload(jwt: string): Record<string, unknown> {
118
+ const parts = jwt.split('.')
119
+ if (parts.length !== 3) return {}
120
+ const payload = parts[1].replace(/-/g, '+').replace(/_/g, '/')
121
+ const padded = payload.padEnd(payload.length + ((4 - (payload.length % 4)) % 4), '=')
122
+ return JSON.parse(atob(padded))
123
+ }
124
+
125
+ /** @internal Test-only helper. Not exported from @growth-labs/auth/utils. */
126
+ export function _resetJwksCache(): void {
127
+ jwksCache.clear()
128
+ }
@@ -0,0 +1,5 @@
1
+ declare module 'virtual:growth-labs/auth/renderers' {
2
+ import type { ResolvedAuthRenderers } from './types.js'
3
+
4
+ export const renderers: ResolvedAuthRenderers
5
+ }