@harperfast/oauth 1.2.1

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 (63) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +219 -0
  3. package/assets/test.html +321 -0
  4. package/config.yaml +23 -0
  5. package/dist/index.d.ts +43 -0
  6. package/dist/index.js +241 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/lib/CSRFTokenManager.d.ts +32 -0
  9. package/dist/lib/CSRFTokenManager.js +90 -0
  10. package/dist/lib/CSRFTokenManager.js.map +1 -0
  11. package/dist/lib/OAuthProvider.d.ts +59 -0
  12. package/dist/lib/OAuthProvider.js +370 -0
  13. package/dist/lib/OAuthProvider.js.map +1 -0
  14. package/dist/lib/config.d.ts +31 -0
  15. package/dist/lib/config.js +138 -0
  16. package/dist/lib/config.js.map +1 -0
  17. package/dist/lib/handlers.d.ts +56 -0
  18. package/dist/lib/handlers.js +386 -0
  19. package/dist/lib/handlers.js.map +1 -0
  20. package/dist/lib/hookManager.d.ts +52 -0
  21. package/dist/lib/hookManager.js +114 -0
  22. package/dist/lib/hookManager.js.map +1 -0
  23. package/dist/lib/providers/auth0.d.ts +8 -0
  24. package/dist/lib/providers/auth0.js +34 -0
  25. package/dist/lib/providers/auth0.js.map +1 -0
  26. package/dist/lib/providers/azure.d.ts +7 -0
  27. package/dist/lib/providers/azure.js +33 -0
  28. package/dist/lib/providers/azure.js.map +1 -0
  29. package/dist/lib/providers/generic.d.ts +7 -0
  30. package/dist/lib/providers/generic.js +20 -0
  31. package/dist/lib/providers/generic.js.map +1 -0
  32. package/dist/lib/providers/github.d.ts +7 -0
  33. package/dist/lib/providers/github.js +73 -0
  34. package/dist/lib/providers/github.js.map +1 -0
  35. package/dist/lib/providers/google.d.ts +7 -0
  36. package/dist/lib/providers/google.js +27 -0
  37. package/dist/lib/providers/google.js.map +1 -0
  38. package/dist/lib/providers/index.d.ts +17 -0
  39. package/dist/lib/providers/index.js +49 -0
  40. package/dist/lib/providers/index.js.map +1 -0
  41. package/dist/lib/providers/okta.d.ts +8 -0
  42. package/dist/lib/providers/okta.js +45 -0
  43. package/dist/lib/providers/okta.js.map +1 -0
  44. package/dist/lib/providers/validation.d.ts +67 -0
  45. package/dist/lib/providers/validation.js +156 -0
  46. package/dist/lib/providers/validation.js.map +1 -0
  47. package/dist/lib/resource.d.ts +102 -0
  48. package/dist/lib/resource.js +368 -0
  49. package/dist/lib/resource.js.map +1 -0
  50. package/dist/lib/sessionValidator.d.ts +38 -0
  51. package/dist/lib/sessionValidator.js +162 -0
  52. package/dist/lib/sessionValidator.js.map +1 -0
  53. package/dist/lib/tenantManager.d.ts +102 -0
  54. package/dist/lib/tenantManager.js +177 -0
  55. package/dist/lib/tenantManager.js.map +1 -0
  56. package/dist/lib/withOAuthValidation.d.ts +64 -0
  57. package/dist/lib/withOAuthValidation.js +188 -0
  58. package/dist/lib/withOAuthValidation.js.map +1 -0
  59. package/dist/types.d.ts +326 -0
  60. package/dist/types.js +5 -0
  61. package/dist/types.js.map +1 -0
  62. package/package.json +89 -0
  63. package/schema/oauth.graphql +21 -0
@@ -0,0 +1,90 @@
1
+ /**
2
+ * CSRF Token Manager for OAuth flows
3
+ *
4
+ * Manages CSRF protection tokens that prevent cross-site request forgery
5
+ * during OAuth authorization flows. Tokens are stored in Harper table
6
+ * for distributed access across workers and cluster nodes.
7
+ */
8
+ // Lazy-load the CSRF token table
9
+ let csrfTable;
10
+ function getCSRFTable() {
11
+ if (!csrfTable) {
12
+ // Check if oauth database and table exist
13
+ if (!databases?.oauth?.csrf_tokens) {
14
+ throw new Error('OAuth CSRF tokens table (oauth.csrf_tokens) not found. ' +
15
+ 'Please ensure the OAuth plugin is properly installed with its schema.');
16
+ }
17
+ csrfTable = databases.oauth.csrf_tokens;
18
+ }
19
+ return csrfTable;
20
+ }
21
+ /**
22
+ * Reset the cached CSRF table reference (for testing only)
23
+ * @internal
24
+ */
25
+ export function resetCSRFTableCache() {
26
+ csrfTable = undefined;
27
+ }
28
+ export class CSRFTokenManager {
29
+ logger;
30
+ constructor(logger) {
31
+ this.logger = logger;
32
+ }
33
+ /**
34
+ * Store CSRF token with metadata
35
+ * Table expiration is handled by Harper (10 minutes)
36
+ */
37
+ async set(token, data) {
38
+ const table = getCSRFTable();
39
+ try {
40
+ await table.put({
41
+ token_id: token,
42
+ data: JSON.stringify(data),
43
+ created_at: Date.now(),
44
+ });
45
+ this.logger?.debug?.(`Stored CSRF token: ${token}`);
46
+ }
47
+ catch (error) {
48
+ this.logger?.error?.('Failed to store CSRF token:', error);
49
+ throw error;
50
+ }
51
+ }
52
+ /**
53
+ * Retrieve CSRF token
54
+ * Harper automatically handles expiration via table-level setting
55
+ */
56
+ async get(token) {
57
+ const table = getCSRFTable();
58
+ try {
59
+ const record = await table.get(token);
60
+ if (!record || !record.data) {
61
+ this.logger?.debug?.(`CSRF token not found: ${token}`);
62
+ return null;
63
+ }
64
+ const data = JSON.parse(record.data);
65
+ this.logger?.debug?.(`Retrieved CSRF token: ${token}`);
66
+ return data;
67
+ }
68
+ catch (error) {
69
+ this.logger?.error?.('Failed to retrieve CSRF token:', error);
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * Delete CSRF token (after successful verification)
75
+ */
76
+ async delete(token) {
77
+ const table = getCSRFTable();
78
+ try {
79
+ await table.delete(token);
80
+ this.logger?.debug?.(`Deleted CSRF token: ${token}`);
81
+ }
82
+ catch (error) {
83
+ // Not critical if delete fails (expiration will clean it up)
84
+ this.logger?.warn?.('Failed to delete CSRF token:', error);
85
+ }
86
+ }
87
+ }
88
+ // Singleton instance that can be shared across providers
89
+ export const csrfTokenManager = new CSRFTokenManager();
90
+ //# sourceMappingURL=CSRFTokenManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CSRFTokenManager.js","sourceRoot":"","sources":["../../src/lib/CSRFTokenManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,iCAAiC;AACjC,IAAI,SAAgB,CAAC;AAErB,SAAS,YAAY;IACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,0CAA0C;QAC1C,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CACd,yDAAyD;gBACxD,uEAAuE,CACxE,CAAC;QACH,CAAC;QACD,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC;IACzC,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB;IAClC,SAAS,GAAG,SAAgB,CAAC;AAC9B,CAAC;AAED,MAAM,OAAO,gBAAgB;IACpB,MAAM,CAAU;IAExB,YAAY,MAAe;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,KAAa,EAAE,IAAmB;QAC3C,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAE7B,IAAI,CAAC;YACJ,MAAM,KAAK,CAAC,GAAG,CAAC;gBACf,QAAQ,EAAE,KAAK;gBACf,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAC1B,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;YAEH,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,sBAAsB,KAAK,EAAE,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YAC3D,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,KAAa;QACtB,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAE7B,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YAEtC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;gBACvD,OAAO,IAAI,CAAC;YACb,CAAC;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;QACb,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,KAAa;QACzB,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;QAE7B,IAAI,CAAC;YACJ,MAAM,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,uBAAuB,KAAK,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,6DAA6D;YAC7D,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QAC5D,CAAC;IACF,CAAC;CACD;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * OAuth Provider Base Class
3
+ *
4
+ * Handles OAuth 2.0 authentication flow with any compliant provider
5
+ */
6
+ import type { OAuthProviderConfig, Logger, CSRFTokenData, TokenResponse, OAuthUser, IOAuthProvider } from '../types.ts';
7
+ export declare class OAuthProvider implements IOAuthProvider {
8
+ config: OAuthProviderConfig;
9
+ logger?: Logger;
10
+ private jwksClient?;
11
+ constructor(config: OAuthProviderConfig, logger?: Logger);
12
+ private initializeJwksClient;
13
+ private validateConfig;
14
+ /**
15
+ * Generate authorization URL for OAuth login
16
+ */
17
+ getAuthorizationUrl(state: string, redirectUri?: string): string;
18
+ /**
19
+ * Exchange authorization code for access token
20
+ */
21
+ exchangeCodeForToken(code: string, redirectUri?: string): Promise<TokenResponse>;
22
+ /**
23
+ * Get user info using access token
24
+ */
25
+ getUserInfo(accessToken: string, idTokenClaims?: any): Promise<any>;
26
+ /**
27
+ * Fetch user info from the provider's userinfo endpoint
28
+ */
29
+ fetchUserInfo(accessToken: string): Promise<any>;
30
+ /**
31
+ * Verify ID token with proper signature verification using JWKS
32
+ */
33
+ verifyIdToken(idToken: string): Promise<any>;
34
+ /**
35
+ * Verify ID token claims without signature verification
36
+ * Used as fallback when JWKS is not available
37
+ */
38
+ private verifyIdTokenClaims;
39
+ /**
40
+ * Map OAuth user info to Harper user object
41
+ */
42
+ mapUserToHarper(userInfo: any): OAuthUser;
43
+ /**
44
+ * Extract a claim from user info (supports nested paths)
45
+ */
46
+ private extractClaim;
47
+ /**
48
+ * Generate and store CSRF token for protection
49
+ */
50
+ generateCSRFToken(metadata?: Record<string, any>): Promise<string>;
51
+ /**
52
+ * Verify and consume CSRF token
53
+ */
54
+ verifyCSRFToken(token: string): Promise<CSRFTokenData | null>;
55
+ /**
56
+ * Refresh an access token using a refresh token
57
+ */
58
+ refreshAccessToken(refreshToken: string): Promise<TokenResponse>;
59
+ }
@@ -0,0 +1,370 @@
1
+ /**
2
+ * OAuth Provider Base Class
3
+ *
4
+ * Handles OAuth 2.0 authentication flow with any compliant provider
5
+ */
6
+ import crypto from 'node:crypto';
7
+ import jwt from 'jsonwebtoken';
8
+ import jwksClient from 'jwks-rsa';
9
+ import { csrfTokenManager } from "./CSRFTokenManager.js";
10
+ export class OAuthProvider {
11
+ config;
12
+ logger;
13
+ jwksClient;
14
+ constructor(config, logger) {
15
+ this.config = config;
16
+ this.logger = logger;
17
+ // Pass logger to the singleton csrfTokenManager if not already set
18
+ if (!csrfTokenManager['logger']) {
19
+ csrfTokenManager['logger'] = logger;
20
+ }
21
+ this.validateConfig();
22
+ this.initializeJwksClient();
23
+ }
24
+ initializeJwksClient() {
25
+ // Only initialize if we have a JWKS URI
26
+ if (this.config.jwksUri) {
27
+ this.jwksClient = jwksClient({
28
+ jwksUri: this.config.jwksUri,
29
+ cache: true, // Cache keys to avoid repeated fetches
30
+ cacheMaxEntries: 5, // Max number of keys to cache
31
+ cacheMaxAge: 10 * 60 * 60 * 1000, // 10 hours
32
+ rateLimit: true, // Rate limit to prevent abuse
33
+ jwksRequestsPerMinute: 10,
34
+ // Timeout for JWKS fetch
35
+ timeout: 5000,
36
+ });
37
+ this.logger?.info?.(`JWKS client initialized for ${this.config.provider}`);
38
+ }
39
+ else if (this.config.provider !== 'generic') {
40
+ this.logger?.warn?.(`No JWKS URI configured for ${this.config.provider} - ID token signatures will not be verified`);
41
+ }
42
+ }
43
+ validateConfig() {
44
+ const required = ['clientId', 'clientSecret', 'authorizationUrl', 'tokenUrl', 'userInfoUrl'];
45
+ const missing = required.filter((key) => !this.config[key]);
46
+ if (missing.length > 0) {
47
+ throw new Error(`OAuth configuration missing required fields: ${missing.join(', ')}`);
48
+ }
49
+ }
50
+ /**
51
+ * Generate authorization URL for OAuth login
52
+ */
53
+ getAuthorizationUrl(state, redirectUri) {
54
+ const params = new URLSearchParams({
55
+ client_id: this.config.clientId,
56
+ redirect_uri: redirectUri || this.config.redirectUri || '',
57
+ response_type: 'code',
58
+ scope: this.config.scope || '',
59
+ state: state,
60
+ });
61
+ // Add provider-specific parameters
62
+ if (this.config.additionalParams) {
63
+ Object.entries(this.config.additionalParams).forEach(([key, value]) => {
64
+ params.set(key, value);
65
+ });
66
+ }
67
+ return `${this.config.authorizationUrl}?${params}`;
68
+ }
69
+ /**
70
+ * Exchange authorization code for access token
71
+ */
72
+ async exchangeCodeForToken(code, redirectUri) {
73
+ const params = new URLSearchParams({
74
+ grant_type: 'authorization_code',
75
+ code: code,
76
+ redirect_uri: redirectUri || this.config.redirectUri || '',
77
+ client_id: this.config.clientId,
78
+ client_secret: this.config.clientSecret,
79
+ });
80
+ const response = await fetch(this.config.tokenUrl, {
81
+ method: 'POST',
82
+ headers: {
83
+ 'Content-Type': 'application/x-www-form-urlencoded',
84
+ 'Accept': 'application/json',
85
+ },
86
+ body: params.toString(),
87
+ });
88
+ if (!response.ok) {
89
+ const contentType = response.headers.get('content-type');
90
+ if (contentType?.includes('application/json')) {
91
+ try {
92
+ const errorBody = await response.json();
93
+ const detail = errorBody.error_description || errorBody.error || response.statusText;
94
+ throw new Error(`Token exchange failed: ${detail}`);
95
+ }
96
+ catch (parseError) {
97
+ if (parseError instanceof Error && parseError.message.startsWith('Token exchange failed'))
98
+ throw parseError;
99
+ // JSON parse failed despite content-type header — fall through to generic error
100
+ }
101
+ }
102
+ // Drain unconsumed body to free the underlying socket (undici connection pool)
103
+ await response.body?.cancel();
104
+ throw new Error(`Token exchange failed: provider returned ${response.status} ${response.statusText}`);
105
+ }
106
+ const contentType = response.headers.get('content-type');
107
+ if (contentType?.includes('application/json')) {
108
+ return response.json();
109
+ }
110
+ else {
111
+ // Some providers (like GitHub) return form-encoded data
112
+ const text = await response.text();
113
+ const tokenParams = new URLSearchParams(text);
114
+ return Object.fromEntries(tokenParams);
115
+ }
116
+ }
117
+ /**
118
+ * Get user info using access token
119
+ */
120
+ async getUserInfo(accessToken, idTokenClaims = null) {
121
+ // Check if provider has custom getUserInfo implementation
122
+ if (typeof this.config.getUserInfo === 'function') {
123
+ const helpers = {
124
+ getUserInfo: this.fetchUserInfo.bind(this),
125
+ logger: this.logger,
126
+ };
127
+ return this.config.getUserInfo.call(this, accessToken, helpers);
128
+ }
129
+ // If we have verified ID token claims and config says to prefer them
130
+ if (idTokenClaims && this.config.preferIdToken !== false) {
131
+ this.logger?.debug?.('Using verified ID token claims for user info');
132
+ // Some providers don't include email in ID token, fetch it separately
133
+ if (!idTokenClaims.email && this.config.fetchEmail) {
134
+ try {
135
+ const additionalInfo = await this.fetchUserInfo(accessToken);
136
+ return { ...idTokenClaims, ...additionalInfo };
137
+ }
138
+ catch (error) {
139
+ this.logger?.warn?.('Failed to fetch additional user info:', error.message);
140
+ }
141
+ }
142
+ return idTokenClaims;
143
+ }
144
+ // Fetch from userinfo endpoint
145
+ return this.fetchUserInfo(accessToken);
146
+ }
147
+ /**
148
+ * Fetch user info from the provider's userinfo endpoint
149
+ */
150
+ async fetchUserInfo(accessToken) {
151
+ const response = await fetch(this.config.userInfoUrl, {
152
+ headers: {
153
+ Authorization: `Bearer ${accessToken}`,
154
+ Accept: 'application/json',
155
+ },
156
+ });
157
+ if (!response.ok) {
158
+ throw new Error(`Failed to fetch user info: ${response.statusText}`);
159
+ }
160
+ return response.json();
161
+ }
162
+ /**
163
+ * Verify ID token with proper signature verification using JWKS
164
+ */
165
+ async verifyIdToken(idToken) {
166
+ // First decode to get the header and payload
167
+ const decoded = jwt.decode(idToken, { complete: true });
168
+ if (!decoded || !decoded.payload || !decoded.header) {
169
+ throw new Error('Invalid ID token format');
170
+ }
171
+ // If we have a JWKS client, verify the signature
172
+ if (this.jwksClient) {
173
+ try {
174
+ // Get the signing key from JWKS
175
+ const kid = decoded.header.kid;
176
+ if (!kid) {
177
+ throw new Error('ID token missing key ID (kid) in header');
178
+ }
179
+ // This fetches the key from JWKS endpoint (with caching)
180
+ const key = await this.jwksClient.getSigningKey(kid);
181
+ const publicKey = key.getPublicKey();
182
+ // Verify signature and claims
183
+ const verified = jwt.verify(idToken, publicKey, {
184
+ algorithms: ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512'],
185
+ audience: this.config.clientId,
186
+ issuer: this.config.issuer || undefined,
187
+ clockTolerance: 60, // Allow 60 seconds clock skew
188
+ });
189
+ this.logger?.debug?.('ID token signature verified successfully');
190
+ return verified;
191
+ }
192
+ catch (error) {
193
+ // Signature verification failed - this is a security issue
194
+ this.logger?.error?.('ID token signature verification failed:', error.message);
195
+ throw new Error(`ID token verification failed: ${error.message}`);
196
+ }
197
+ }
198
+ else {
199
+ // No JWKS client - fall back to claims validation only
200
+ this.logger?.warn?.('JWKS not configured - verifying claims only, not signature');
201
+ return this.verifyIdTokenClaims(decoded.payload);
202
+ }
203
+ }
204
+ /**
205
+ * Verify ID token claims without signature verification
206
+ * Used as fallback when JWKS is not available
207
+ */
208
+ verifyIdTokenClaims(payload) {
209
+ const now = Math.floor(Date.now() / 1000);
210
+ // Critical validations
211
+ if (!payload.exp || payload.exp < now) {
212
+ throw new Error('ID token expired');
213
+ }
214
+ if (!payload.iat || payload.iat > now + 60) {
215
+ throw new Error('ID token issued in the future');
216
+ }
217
+ if (!payload.aud) {
218
+ throw new Error('ID token missing audience');
219
+ }
220
+ const audience = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
221
+ if (!audience.includes(this.config.clientId)) {
222
+ throw new Error(`ID token audience mismatch`);
223
+ }
224
+ if (this.config.issuer && payload.iss !== this.config.issuer) {
225
+ throw new Error(`ID token issuer mismatch`);
226
+ }
227
+ if (!payload.sub) {
228
+ throw new Error('ID token missing subject');
229
+ }
230
+ return payload;
231
+ }
232
+ /**
233
+ * Map OAuth user info to Harper user object
234
+ */
235
+ mapUserToHarper(userInfo) {
236
+ const username = this.extractClaim(userInfo, this.config.usernameClaim);
237
+ if (!username) {
238
+ throw new Error(`Username claim '${this.config.usernameClaim}' not found in user info`);
239
+ }
240
+ const role = this.extractClaim(userInfo, this.config.roleClaim) || this.config.defaultRole || 'user';
241
+ return {
242
+ username,
243
+ role,
244
+ provider: this.config.provider,
245
+ providerUserId: userInfo.sub || userInfo.id || userInfo.user_id,
246
+ email: userInfo.email,
247
+ name: userInfo.name || userInfo.display_name || userInfo.full_name,
248
+ metadata: {
249
+ oauthProvider: this.config.provider,
250
+ oauthClaims: userInfo,
251
+ },
252
+ };
253
+ }
254
+ /**
255
+ * Extract a claim from user info (supports nested paths)
256
+ */
257
+ extractClaim(userInfo, claimPath) {
258
+ if (!claimPath)
259
+ return null;
260
+ // Support nested paths like "profile.email"
261
+ const parts = claimPath.split('.');
262
+ let value = userInfo;
263
+ for (const part of parts) {
264
+ if (value && typeof value === 'object') {
265
+ value = value[part];
266
+ }
267
+ else {
268
+ return null;
269
+ }
270
+ }
271
+ return value;
272
+ }
273
+ /**
274
+ * Generate and store CSRF token for protection
275
+ */
276
+ async generateCSRFToken(metadata = {}) {
277
+ const token = crypto.randomBytes(32).toString('hex');
278
+ const tokenData = {
279
+ timestamp: Date.now(),
280
+ ...metadata,
281
+ };
282
+ // Store token (Harper handles expiration via table-level setting)
283
+ await csrfTokenManager.set(token, tokenData);
284
+ return token;
285
+ }
286
+ /**
287
+ * Verify and consume CSRF token
288
+ */
289
+ async verifyCSRFToken(token) {
290
+ // Always use distributed storage
291
+ const tokenData = await csrfTokenManager.get(token);
292
+ if (tokenData) {
293
+ // Delete for one-time use
294
+ await csrfTokenManager.delete(token);
295
+ }
296
+ if (!tokenData) {
297
+ return null;
298
+ }
299
+ return tokenData;
300
+ }
301
+ /**
302
+ * Refresh an access token using a refresh token
303
+ */
304
+ async refreshAccessToken(refreshToken) {
305
+ if (!refreshToken) {
306
+ throw new Error('Refresh token is required');
307
+ }
308
+ const params = new URLSearchParams({
309
+ grant_type: 'refresh_token',
310
+ refresh_token: refreshToken,
311
+ client_id: this.config.clientId,
312
+ client_secret: this.config.clientSecret,
313
+ });
314
+ // Some providers require scope to be included in refresh
315
+ if (this.config.scope) {
316
+ params.append('scope', this.config.scope);
317
+ }
318
+ const response = await fetch(this.config.tokenUrl, {
319
+ method: 'POST',
320
+ headers: {
321
+ 'Content-Type': 'application/x-www-form-urlencoded',
322
+ 'Accept': 'application/json',
323
+ },
324
+ body: params.toString(),
325
+ });
326
+ if (!response.ok) {
327
+ const contentType = response.headers.get('content-type');
328
+ let detail = `${response.status} ${response.statusText}`;
329
+ if (contentType?.includes('application/json')) {
330
+ try {
331
+ const errorBody = await response.json();
332
+ detail = errorBody.error_description || errorBody.error || response.statusText;
333
+ }
334
+ catch {
335
+ // JSON parse failed despite content-type header — use status/statusText
336
+ }
337
+ }
338
+ // Drain unconsumed body to free the underlying socket (undici connection pool)
339
+ await response.body?.cancel();
340
+ this.logger?.error?.('Token refresh HTTP error:', {
341
+ status: response.status,
342
+ statusText: response.statusText,
343
+ detail,
344
+ });
345
+ throw new Error(`Token refresh failed: ${detail}`);
346
+ }
347
+ const contentType = response.headers.get('content-type');
348
+ let tokenData;
349
+ if (contentType?.includes('application/json')) {
350
+ tokenData = await response.json();
351
+ }
352
+ else {
353
+ // Some providers return form-encoded data
354
+ const text = await response.text();
355
+ const tokenParams = new URLSearchParams(text);
356
+ tokenData = Object.fromEntries(tokenParams);
357
+ }
358
+ // Check if response contains an error (some providers return 200 with error object)
359
+ if (tokenData.error) {
360
+ this.logger?.error?.('Token refresh returned error in response:', {
361
+ error: tokenData.error,
362
+ error_description: tokenData.error_description,
363
+ error_uri: tokenData.error_uri,
364
+ });
365
+ throw new Error(`Token refresh failed: ${tokenData.error_description || tokenData.error}`);
366
+ }
367
+ return tokenData;
368
+ }
369
+ }
370
+ //# sourceMappingURL=OAuthProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OAuthProvider.js","sourceRoot":"","sources":["../../src/lib/OAuthProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * OAuth Configuration
3
+ *
4
+ * Provider configuration and initialization utilities
5
+ */
6
+ import type { OAuthProviderConfig, OAuthPluginConfig, ProviderRegistry, Logger } from '../types.ts';
7
+ /**
8
+ * Expand environment variable in a string value
9
+ *
10
+ * If the value is a string in the format `${VAR_NAME}`, it will be replaced
11
+ * with the value of the environment variable. Non-string values are returned unchanged.
12
+ *
13
+ * @example
14
+ * expandEnvVar('${MY_VAR}') // Returns process.env.MY_VAR or '${MY_VAR}' if undefined
15
+ * expandEnvVar('literal') // Returns 'literal'
16
+ * expandEnvVar(123) // Returns 123
17
+ * expandEnvVar(true) // Returns true
18
+ */
19
+ export declare function expandEnvVar(value: any): any;
20
+ /**
21
+ * Build configuration for a specific provider
22
+ */
23
+ export declare function buildProviderConfig(providerConfig: Record<string, any>, providerName: string, pluginDefaults?: Partial<OAuthProviderConfig>): OAuthProviderConfig;
24
+ /**
25
+ * Extract plugin-level defaults from options
26
+ */
27
+ export declare function extractPluginDefaults(options: OAuthPluginConfig): Partial<OAuthProviderConfig>;
28
+ /**
29
+ * Initialize OAuth providers from configuration
30
+ */
31
+ export declare function initializeProviders(options: OAuthPluginConfig, logger?: Logger): ProviderRegistry;