@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,114 @@
1
+ /**
2
+ * OAuth Hook Manager
3
+ *
4
+ * Manages loading and calling lifecycle hooks for the OAuth plugin
5
+ */
6
+ /**
7
+ * Hook Manager
8
+ * Loads and executes OAuth lifecycle hooks
9
+ */
10
+ export class HookManager {
11
+ hooks = {};
12
+ logger;
13
+ constructor(logger) {
14
+ this.logger = logger;
15
+ }
16
+ /**
17
+ * Register hooks programmatically
18
+ * Allows applications to register hooks directly without using config
19
+ */
20
+ register(hooks) {
21
+ this.hooks = hooks;
22
+ this.logger?.debug?.(`Registered OAuth hooks: ${Object.keys(hooks)
23
+ .filter((key) => hooks[key])
24
+ .join(', ')}`);
25
+ }
26
+ /**
27
+ * Call onLogin hook
28
+ */
29
+ async callOnLogin(oauthUser, tokenResponse, session, request, provider) {
30
+ if (!this.hooks.onLogin)
31
+ return;
32
+ try {
33
+ this.logger?.debug?.(`Calling onLogin hook for provider: ${provider}`);
34
+ const result = await this.hooks.onLogin(oauthUser, tokenResponse, session, request, provider);
35
+ return result;
36
+ }
37
+ catch (error) {
38
+ this.logger?.error?.('onLogin hook failed:', error.message);
39
+ // Don't throw - hooks should not break the OAuth flow
40
+ return;
41
+ }
42
+ }
43
+ /**
44
+ * Call onLogout hook
45
+ */
46
+ async callOnLogout(session, request) {
47
+ if (!this.hooks.onLogout)
48
+ return;
49
+ try {
50
+ this.logger?.debug?.('Calling onLogout hook');
51
+ await this.hooks.onLogout(session, request);
52
+ }
53
+ catch (error) {
54
+ this.logger?.error?.('onLogout hook failed:', error.message);
55
+ // Don't throw - hooks should not break logout
56
+ }
57
+ }
58
+ /**
59
+ * Call onTokenRefresh hook
60
+ */
61
+ async callOnTokenRefresh(session, refreshed, request) {
62
+ if (!this.hooks.onTokenRefresh)
63
+ return;
64
+ try {
65
+ this.logger?.debug?.(`Calling onTokenRefresh hook (refreshed: ${refreshed})`);
66
+ await this.hooks.onTokenRefresh(session, refreshed, request);
67
+ }
68
+ catch (error) {
69
+ this.logger?.error?.('onTokenRefresh hook failed:', error.message);
70
+ // Don't throw - hooks should not break token refresh
71
+ }
72
+ }
73
+ /**
74
+ * Check if a specific hook is registered
75
+ */
76
+ hasHook(hookName) {
77
+ return !!this.hooks[hookName];
78
+ }
79
+ /**
80
+ * Check if any hooks are loaded
81
+ */
82
+ hasHooks() {
83
+ return Object.keys(this.hooks).length > 0;
84
+ }
85
+ /**
86
+ * Call onResolveProvider hook
87
+ *
88
+ * Called when a provider is not found in the static registry.
89
+ * Allows applications to dynamically resolve provider configurations.
90
+ *
91
+ * @param providerName - Provider name from URL path (e.g., "okta-org_abc123")
92
+ * @param logger - Optional logger instance
93
+ * @returns Provider configuration or null if not found
94
+ * @throws Error if resolution fails
95
+ */
96
+ async callResolveProvider(providerName, logger) {
97
+ const hook = this.hooks.onResolveProvider;
98
+ if (!hook)
99
+ return null;
100
+ try {
101
+ this.logger?.debug?.(`Calling onResolveProvider hook for: ${providerName}`);
102
+ const config = await hook(providerName, logger || this.logger);
103
+ if (config) {
104
+ this.logger?.debug?.(`Provider resolved: ${providerName} → ${config.provider}`);
105
+ }
106
+ return config;
107
+ }
108
+ catch (error) {
109
+ this.logger?.error?.('onResolveProvider hook failed:', error.message);
110
+ throw error; // Re-throw for resource to handle (returns 500)
111
+ }
112
+ }
113
+ }
114
+ //# sourceMappingURL=hookManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hookManager.js","sourceRoot":"","sources":["../../src/lib/hookManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Auth0 OAuth Provider Preset
3
+ *
4
+ * Configuration for Auth0 OAuth 2.0 authentication.
5
+ * Requires domain configuration.
6
+ */
7
+ import type { OAuthProviderConfig } from '../../types.ts';
8
+ export declare const auth0Provider: OAuthProviderConfig;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Auth0 OAuth Provider Preset
3
+ *
4
+ * Configuration for Auth0 OAuth 2.0 authentication.
5
+ * Requires domain configuration.
6
+ */
7
+ import { validateDomainSafety, validateDomainAllowlist } from "./validation.js";
8
+ export const auth0Provider = {
9
+ provider: 'auth0',
10
+ clientId: '', // Will be overridden by config
11
+ clientSecret: '', // Will be overridden by config
12
+ authorizationUrl: '', // Will be set by configure()
13
+ tokenUrl: '', // Will be set by configure()
14
+ userInfoUrl: '', // Will be set by configure()
15
+ scope: 'openid profile email',
16
+ usernameClaim: 'email',
17
+ defaultRole: 'user',
18
+ // URLs are configured dynamically based on domain
19
+ configure: (domain) => {
20
+ // Validate domain safety (SSRF protection, private IPs, etc.)
21
+ const hostname = validateDomainSafety(domain, 'Auth0');
22
+ // Validate against Auth0 domain allowlist
23
+ const ALLOWED_AUTH0_DOMAINS = ['.auth0.com', '.us.auth0.com', '.eu.auth0.com', '.au.auth0.com', '.jp.auth0.com'];
24
+ validateDomainAllowlist(hostname, ALLOWED_AUTH0_DOMAINS, 'Auth0');
25
+ return {
26
+ authorizationUrl: `https://${hostname}/authorize`,
27
+ tokenUrl: `https://${hostname}/oauth/token`,
28
+ userInfoUrl: `https://${hostname}/userinfo`,
29
+ jwksUri: `https://${hostname}/.well-known/jwks.json`,
30
+ issuer: `https://${hostname}/`,
31
+ };
32
+ },
33
+ };
34
+ //# sourceMappingURL=auth0.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth0.js","sourceRoot":"","sources":["../../../src/lib/providers/auth0.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,CAAC,MAAM,aAAa,GAAwB;IACjD,QAAQ,EAAE,OAAO;IACjB,QAAQ,EAAE,EAAE,EAAE,+BAA+B;IAC7C,YAAY,EAAE,EAAE,EAAE,+BAA+B;IACjD,gBAAgB,EAAE,EAAE,EAAE,6BAA6B;IACnD,QAAQ,EAAE,EAAE,EAAE,6BAA6B;IAC3C,WAAW,EAAE,EAAE,EAAE,6BAA6B;IAC9C,KAAK,EAAE,sBAAsB;IAC7B,aAAa,EAAE,OAAO;IACtB,WAAW,EAAE,MAAM;IAEnB,kDAAkD;IAClD,SAAS,EAAE,CAAC,MAAc,EAAgC,EAAE;QAC3D,8DAA8D;QAC9D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAEvD,0CAA0C;QAC1C,MAAM,qBAAqB,GAAG,CAAC,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC;QACjH,uBAAuB,CAAC,QAAQ,EAAE,qBAAqB,EAAE,OAAO,CAAC,CAAC;QAElE,OAAO;YACN,gBAAgB,EAAE,WAAW,QAAQ,YAAY;YACjD,QAAQ,EAAE,WAAW,QAAQ,cAAc;YAC3C,WAAW,EAAE,WAAW,QAAQ,WAAW;YAC3C,OAAO,EAAE,WAAW,QAAQ,wBAAwB;YACpD,MAAM,EAAE,WAAW,QAAQ,GAAG;SAC9B,CAAC;IACH,CAAC;CACD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Azure AD OAuth Provider Configuration
3
+ *
4
+ * Supports both single-tenant and multi-tenant configurations
5
+ */
6
+ import type { OAuthProviderConfig } from '../../types.ts';
7
+ export declare const AzureADProvider: OAuthProviderConfig;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Azure AD OAuth Provider Configuration
3
+ *
4
+ * Supports both single-tenant and multi-tenant configurations
5
+ */
6
+ import { validateAzureTenantId } from "./validation.js";
7
+ export const AzureADProvider = {
8
+ provider: 'azure',
9
+ clientId: '', // Will be overridden by config
10
+ clientSecret: '', // Will be overridden by config
11
+ // Default to common endpoint (multi-tenant)
12
+ authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
13
+ tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
14
+ userInfoUrl: 'https://graph.microsoft.com/v1.0/me',
15
+ jwksUri: 'https://login.microsoftonline.com/common/discovery/v2.0/keys',
16
+ issuer: null, // Varies by tenant
17
+ scope: 'openid profile email User.Read',
18
+ usernameClaim: 'email',
19
+ emailClaim: 'email',
20
+ nameClaim: 'displayName',
21
+ // Azure-specific: configure endpoints based on tenant
22
+ configure: (tenantId) => {
23
+ // Validate Azure tenant ID format
24
+ validateAzureTenantId(tenantId);
25
+ return {
26
+ authorizationUrl: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`,
27
+ tokenUrl: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
28
+ jwksUri: `https://login.microsoftonline.com/${tenantId}/discovery/v2.0/keys`,
29
+ issuer: `https://login.microsoftonline.com/${tenantId}/v2.0`,
30
+ };
31
+ },
32
+ };
33
+ //# sourceMappingURL=azure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"azure.js","sourceRoot":"","sources":["../../../src/lib/providers/azure.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,CAAC,MAAM,eAAe,GAAwB;IACnD,QAAQ,EAAE,OAAO;IACjB,QAAQ,EAAE,EAAE,EAAE,+BAA+B;IAC7C,YAAY,EAAE,EAAE,EAAE,+BAA+B;IACjD,4CAA4C;IAC5C,gBAAgB,EAAE,gEAAgE;IAClF,QAAQ,EAAE,4DAA4D;IACtE,WAAW,EAAE,qCAAqC;IAClD,OAAO,EAAE,8DAA8D;IACvE,MAAM,EAAE,IAAI,EAAE,mBAAmB;IACjC,KAAK,EAAE,gCAAgC;IACvC,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,OAAO;IACnB,SAAS,EAAE,aAAa;IAExB,sDAAsD;IACtD,SAAS,EAAE,CAAC,QAAgB,EAAgC,EAAE;QAC7D,kCAAkC;QAClC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAEhC,OAAO;YACN,gBAAgB,EAAE,qCAAqC,QAAQ,wBAAwB;YACvF,QAAQ,EAAE,qCAAqC,QAAQ,oBAAoB;YAC3E,OAAO,EAAE,qCAAqC,QAAQ,sBAAsB;YAC5E,MAAM,EAAE,qCAAqC,QAAQ,OAAO;SAC5D,CAAC;IACH,CAAC;CACD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Generic OAuth Provider Configuration
3
+ *
4
+ * Base configuration for custom OAuth 2.0 providers
5
+ */
6
+ import type { OAuthProviderConfig } from '../../types.ts';
7
+ export declare const genericProvider: OAuthProviderConfig;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Generic OAuth Provider Configuration
3
+ *
4
+ * Base configuration for custom OAuth 2.0 providers
5
+ */
6
+ export const genericProvider = {
7
+ provider: 'generic',
8
+ clientId: '', // Must be provided in config
9
+ clientSecret: '', // Must be provided in config
10
+ authorizationUrl: '', // Must be provided in config
11
+ tokenUrl: '', // Must be provided in config
12
+ userInfoUrl: '', // Must be provided in config
13
+ scope: 'openid profile email',
14
+ usernameClaim: 'email',
15
+ emailClaim: 'email',
16
+ nameClaim: 'name',
17
+ defaultRole: 'user',
18
+ postLoginRedirect: '/',
19
+ };
20
+ //# sourceMappingURL=generic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generic.js","sourceRoot":"","sources":["../../../src/lib/providers/generic.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAC,MAAM,eAAe,GAAwB;IACnD,QAAQ,EAAE,SAAS;IACnB,QAAQ,EAAE,EAAE,EAAE,6BAA6B;IAC3C,YAAY,EAAE,EAAE,EAAE,6BAA6B;IAC/C,gBAAgB,EAAE,EAAE,EAAE,6BAA6B;IACnD,QAAQ,EAAE,EAAE,EAAE,6BAA6B;IAC3C,WAAW,EAAE,EAAE,EAAE,6BAA6B;IAC9C,KAAK,EAAE,sBAAsB;IAC7B,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,OAAO;IACnB,SAAS,EAAE,MAAM;IACjB,WAAW,EAAE,MAAM;IACnB,iBAAiB,EAAE,GAAG;CACtB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * GitHub OAuth Provider Configuration
3
+ *
4
+ * Note: GitHub uses OAuth 2.0, not OIDC, so no ID tokens or JWKS
5
+ */
6
+ import type { OAuthProviderConfig } from '../../types.ts';
7
+ export declare const GitHubProvider: OAuthProviderConfig;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * GitHub OAuth Provider Configuration
3
+ *
4
+ * Note: GitHub uses OAuth 2.0, not OIDC, so no ID tokens or JWKS
5
+ */
6
+ export const GitHubProvider = {
7
+ provider: 'github',
8
+ clientId: '', // Will be overridden by config
9
+ clientSecret: '', // Will be overridden by config
10
+ authorizationUrl: 'https://github.com/login/oauth/authorize',
11
+ tokenUrl: 'https://github.com/login/oauth/access_token',
12
+ userInfoUrl: 'https://api.github.com/user',
13
+ // No JWKS - GitHub doesn't support OIDC
14
+ jwksUri: null,
15
+ issuer: null,
16
+ scope: 'read:user user:email',
17
+ usernameClaim: 'login',
18
+ emailClaim: 'email',
19
+ nameClaim: 'name',
20
+ // Validate token every 15 minutes (GitHub tokens don't expire but can be revoked)
21
+ tokenValidationInterval: 15 * 60 * 1000, // 15 minutes
22
+ // GitHub-specific: validate token by making lightweight API call
23
+ async validateToken(accessToken, logger) {
24
+ try {
25
+ const response = await fetch('https://api.github.com/user', {
26
+ method: 'HEAD', // HEAD request - no body, just status
27
+ headers: {
28
+ Authorization: `Bearer ${accessToken}`,
29
+ Accept: 'application/json',
30
+ },
31
+ });
32
+ const isValid = response.ok;
33
+ if (!isValid) {
34
+ logger?.debug?.(`GitHub token validation failed: ${response.status} ${response.statusText}`);
35
+ }
36
+ return isValid;
37
+ }
38
+ catch (error) {
39
+ logger?.warn?.('GitHub token validation error:', error.message);
40
+ return false; // Assume invalid on error
41
+ }
42
+ },
43
+ // GitHub-specific: need to fetch email separately if not public
44
+ async getUserInfo(accessToken, helpers) {
45
+ // Get basic user info using the base getUserInfo method
46
+ const userInfo = await helpers.getUserInfo(accessToken);
47
+ // If email is not public, fetch from emails endpoint
48
+ if (!userInfo.email) {
49
+ try {
50
+ const emailResponse = await fetch('https://api.github.com/user/emails', {
51
+ headers: {
52
+ Authorization: `Bearer ${accessToken}`,
53
+ Accept: 'application/json',
54
+ },
55
+ });
56
+ if (emailResponse.ok) {
57
+ const emails = (await emailResponse.json());
58
+ const primaryEmail = emails.find((e) => e.primary);
59
+ if (primaryEmail) {
60
+ userInfo.email = primaryEmail.email;
61
+ userInfo.email_verified = primaryEmail.verified;
62
+ }
63
+ }
64
+ }
65
+ catch (error) {
66
+ // Email fetch failed, continue without it
67
+ helpers.logger?.warn?.('Failed to fetch GitHub user emails:', error.message);
68
+ }
69
+ }
70
+ return userInfo;
71
+ },
72
+ };
73
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/lib/providers/github.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAwB;IAClD,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,EAAE,EAAE,+BAA+B;IAC7C,YAAY,EAAE,EAAE,EAAE,+BAA+B;IACjD,gBAAgB,EAAE,0CAA0C;IAC5D,QAAQ,EAAE,6CAA6C;IACvD,WAAW,EAAE,6BAA6B;IAC1C,wCAAwC;IACxC,OAAO,EAAE,IAAI;IACb,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,sBAAsB;IAC7B,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,OAAO;IACnB,SAAS,EAAE,MAAM;IACjB,kFAAkF;IAClF,uBAAuB,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IAEtD,iEAAiE;IACjE,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,MAAY;QACpD,IAAI,CAAC;YACJ,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,6BAA6B,EAAE;gBAC3D,MAAM,EAAE,MAAM,EAAE,sCAAsC;gBACtD,OAAO,EAAE;oBACR,aAAa,EAAE,UAAU,WAAW,EAAE;oBACtC,MAAM,EAAE,kBAAkB;iBAC1B;aACD,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,EAAE,KAAK,EAAE,CAAC,mCAAmC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAC9F,CAAC;YACD,OAAO,OAAO,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,EAAE,IAAI,EAAE,CAAC,gCAAgC,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;YAC3E,OAAO,KAAK,CAAC,CAAC,0BAA0B;QACzC,CAAC;IACF,CAAC;IAED,gEAAgE;IAChE,KAAK,CAAC,WAAW,CAAC,WAAmB,EAAE,OAA2B;QACjE,wDAAwD;QACxD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAExD,qDAAqD;QACrD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC;gBACJ,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,oCAAoC,EAAE;oBACvE,OAAO,EAAE;wBACR,aAAa,EAAE,UAAU,WAAW,EAAE;wBACtC,MAAM,EAAE,kBAAkB;qBAC1B;iBACD,CAAC,CAAC;gBAEH,IAAI,aAAa,CAAC,EAAE,EAAE,CAAC;oBACtB,MAAM,MAAM,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAIxC,CAAC;oBACH,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;oBACnD,IAAI,YAAY,EAAE,CAAC;wBAClB,QAAQ,CAAC,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC;wBACpC,QAAQ,CAAC,cAAc,GAAG,YAAY,CAAC,QAAQ,CAAC;oBACjD,CAAC;gBACF,CAAC;YACF,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,0CAA0C;gBAC1C,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,qCAAqC,EAAG,KAAe,CAAC,OAAO,CAAC,CAAC;YACzF,CAAC;QACF,CAAC;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC;CACD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Google OAuth Provider Configuration
3
+ *
4
+ * Supports OpenID Connect (OIDC) with ID tokens
5
+ */
6
+ import type { OAuthProviderConfig } from '../../types.ts';
7
+ export declare const GoogleProvider: OAuthProviderConfig;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Google OAuth Provider Configuration
3
+ *
4
+ * Supports OpenID Connect (OIDC) with ID tokens
5
+ */
6
+ export const GoogleProvider = {
7
+ provider: 'google',
8
+ clientId: '', // Will be overridden by config
9
+ clientSecret: '', // Will be overridden by config
10
+ authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
11
+ tokenUrl: 'https://oauth2.googleapis.com/token',
12
+ userInfoUrl: 'https://www.googleapis.com/oauth2/v3/userinfo',
13
+ jwksUri: 'https://www.googleapis.com/oauth2/v3/certs',
14
+ issuer: 'https://accounts.google.com',
15
+ scope: 'openid profile email',
16
+ usernameClaim: 'email',
17
+ emailClaim: 'email',
18
+ nameClaim: 'name',
19
+ // Google includes user info in ID token, prefer that
20
+ preferIdToken: true,
21
+ // Additional Google-specific parameters
22
+ additionalParams: {
23
+ access_type: 'offline', // Request refresh token
24
+ prompt: 'consent', // Force consent to get refresh token
25
+ },
26
+ };
27
+ //# sourceMappingURL=google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/lib/providers/google.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAC,MAAM,cAAc,GAAwB;IAClD,QAAQ,EAAE,QAAQ;IAClB,QAAQ,EAAE,EAAE,EAAE,+BAA+B;IAC7C,YAAY,EAAE,EAAE,EAAE,+BAA+B;IACjD,gBAAgB,EAAE,8CAA8C;IAChE,QAAQ,EAAE,qCAAqC;IAC/C,WAAW,EAAE,+CAA+C;IAC5D,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,6BAA6B;IACrC,KAAK,EAAE,sBAAsB;IAC7B,aAAa,EAAE,OAAO;IACtB,UAAU,EAAE,OAAO;IACnB,SAAS,EAAE,MAAM;IACjB,qDAAqD;IACrD,aAAa,EAAE,IAAI;IACnB,wCAAwC;IACxC,gBAAgB,EAAE;QACjB,WAAW,EAAE,SAAS,EAAE,wBAAwB;QAChD,MAAM,EAAE,SAAS,EAAE,qCAAqC;KACxD;CACD,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * OAuth Provider Registry
3
+ */
4
+ import type { OAuthProviderConfig } from '../../types.ts';
5
+ export declare const providers: Record<string, OAuthProviderConfig>;
6
+ /**
7
+ * Get a pre-configured provider by name
8
+ */
9
+ export declare function getProvider(name: string): OAuthProviderConfig | null;
10
+ /**
11
+ * Register a custom provider
12
+ */
13
+ export declare function registerProvider(name: string, config: OAuthProviderConfig): void;
14
+ /**
15
+ * Get all registered provider names
16
+ */
17
+ export declare function getProviderNames(): string[];
@@ -0,0 +1,49 @@
1
+ /**
2
+ * OAuth Provider Registry
3
+ */
4
+ import { GitHubProvider } from "./github.js";
5
+ import { GoogleProvider } from "./google.js";
6
+ import { AzureADProvider } from "./azure.js";
7
+ import { auth0Provider } from "./auth0.js";
8
+ import { OktaProvider } from "./okta.js";
9
+ import { genericProvider } from "./generic.js";
10
+ // Auto-register all providers
11
+ const providerModules = {
12
+ github: GitHubProvider,
13
+ google: GoogleProvider,
14
+ azure: AzureADProvider,
15
+ auth0: auth0Provider,
16
+ okta: OktaProvider,
17
+ generic: genericProvider,
18
+ };
19
+ export const providers = {
20
+ ...providerModules,
21
+ // Aliases
22
+ microsoft: AzureADProvider,
23
+ };
24
+ /**
25
+ * Get a pre-configured provider by name
26
+ */
27
+ export function getProvider(name) {
28
+ const provider = providers[name?.toLowerCase()];
29
+ if (!provider) {
30
+ // Return null to allow custom provider configuration
31
+ return null;
32
+ }
33
+ // Return a shallow copy to avoid direct mutations
34
+ // Note: Functions (getUserInfo, configure, validateToken) are preserved by reference
35
+ return { ...provider };
36
+ }
37
+ /**
38
+ * Register a custom provider
39
+ */
40
+ export function registerProvider(name, config) {
41
+ providers[name] = config;
42
+ }
43
+ /**
44
+ * Get all registered provider names
45
+ */
46
+ export function getProviderNames() {
47
+ return Object.keys(providers);
48
+ }
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/providers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,8BAA8B;AAC9B,MAAM,eAAe,GAAG;IACvB,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,cAAc;IACtB,KAAK,EAAE,eAAe;IACtB,KAAK,EAAE,aAAa;IACpB,IAAI,EAAE,YAAY;IAClB,OAAO,EAAE,eAAe;CACxB,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAwC;IAC7D,GAAG,eAAe;IAClB,UAAU;IACV,SAAS,EAAE,eAAe;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;IAEhD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,qDAAqD;QACrD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,kDAAkD;IAClD,qFAAqF;IACrF,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAA2B;IACzE,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC/B,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Okta OAuth Provider Configuration
3
+ *
4
+ * Supports Okta's OAuth 2.0 / OIDC implementation
5
+ * Requires domain configuration (e.g., 'dev-12345.okta.com')
6
+ */
7
+ import type { OAuthProviderConfig } from '../../types.ts';
8
+ export declare const OktaProvider: OAuthProviderConfig;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Okta OAuth Provider Configuration
3
+ *
4
+ * Supports Okta's OAuth 2.0 / OIDC implementation
5
+ * Requires domain configuration (e.g., 'dev-12345.okta.com')
6
+ */
7
+ import { validateDomainSafety, validateDomainAllowlist } from "./validation.js";
8
+ export const OktaProvider = {
9
+ provider: 'okta',
10
+ clientId: '', // Will be overridden by config
11
+ clientSecret: '', // Will be overridden by config
12
+ authorizationUrl: '', // Will be set by configure()
13
+ tokenUrl: '', // Will be set by configure()
14
+ userInfoUrl: '', // Will be set by configure()
15
+ jwksUri: '', // Will be set by configure()
16
+ issuer: '', // Will be set by configure()
17
+ scope: 'openid profile email groups',
18
+ usernameClaim: 'preferred_username',
19
+ emailClaim: 'email',
20
+ nameClaim: 'name',
21
+ // Use 'groups' claim for role mapping (optional)
22
+ roleClaim: 'groups',
23
+ defaultRole: 'user',
24
+ // Okta includes user info in ID token, prefer that
25
+ preferIdToken: true,
26
+ // Okta-specific: configure endpoints based on domain
27
+ configure: (domain) => {
28
+ // Validate domain safety (SSRF protection, private IPs, etc.)
29
+ const hostname = validateDomainSafety(domain, 'Okta');
30
+ // Validate against Okta domain allowlist
31
+ const ALLOWED_OKTA_DOMAINS = ['.okta.com', '.okta-emea.com', '.oktapreview.com'];
32
+ validateDomainAllowlist(hostname, ALLOWED_OKTA_DOMAINS, 'Okta');
33
+ // Use /oauth2/v1 (org authorization server - most compatible)
34
+ // For /oauth2/default or custom auth servers, set authorizationUrl/tokenUrl/userInfoUrl directly in config
35
+ const authServerPath = '/oauth2/v1';
36
+ return {
37
+ authorizationUrl: `https://${hostname}${authServerPath}/authorize`,
38
+ tokenUrl: `https://${hostname}${authServerPath}/token`,
39
+ userInfoUrl: `https://${hostname}${authServerPath}/userinfo`,
40
+ jwksUri: `https://${hostname}${authServerPath}/keys`,
41
+ issuer: `https://${hostname}${authServerPath}`,
42
+ };
43
+ },
44
+ };
45
+ //# sourceMappingURL=okta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"okta.js","sourceRoot":"","sources":["../../../src/lib/providers/okta.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAEhF,MAAM,CAAC,MAAM,YAAY,GAAwB;IAChD,QAAQ,EAAE,MAAM;IAChB,QAAQ,EAAE,EAAE,EAAE,+BAA+B;IAC7C,YAAY,EAAE,EAAE,EAAE,+BAA+B;IACjD,gBAAgB,EAAE,EAAE,EAAE,6BAA6B;IACnD,QAAQ,EAAE,EAAE,EAAE,6BAA6B;IAC3C,WAAW,EAAE,EAAE,EAAE,6BAA6B;IAC9C,OAAO,EAAE,EAAE,EAAE,6BAA6B;IAC1C,MAAM,EAAE,EAAE,EAAE,6BAA6B;IACzC,KAAK,EAAE,6BAA6B;IACpC,aAAa,EAAE,oBAAoB;IACnC,UAAU,EAAE,OAAO;IACnB,SAAS,EAAE,MAAM;IACjB,iDAAiD;IACjD,SAAS,EAAE,QAAQ;IACnB,WAAW,EAAE,MAAM;IACnB,mDAAmD;IACnD,aAAa,EAAE,IAAI;IAEnB,qDAAqD;IACrD,SAAS,EAAE,CAAC,MAAc,EAAgC,EAAE;QAC3D,8DAA8D;QAC9D,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEtD,yCAAyC;QACzC,MAAM,oBAAoB,GAAG,CAAC,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;QACjF,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,MAAM,CAAC,CAAC;QAEhE,8DAA8D;QAC9D,2GAA2G;QAC3G,MAAM,cAAc,GAAG,YAAY,CAAC;QAEpC,OAAO;YACN,gBAAgB,EAAE,WAAW,QAAQ,GAAG,cAAc,YAAY;YAClE,QAAQ,EAAE,WAAW,QAAQ,GAAG,cAAc,QAAQ;YACtD,WAAW,EAAE,WAAW,QAAQ,GAAG,cAAc,WAAW;YAC5D,OAAO,EAAE,WAAW,QAAQ,GAAG,cAAc,OAAO;YACpD,MAAM,EAAE,WAAW,QAAQ,GAAG,cAAc,EAAE;SAC9C,CAAC;IACH,CAAC;CACD,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Shared validation utilities for OAuth providers
3
+ *
4
+ * Security-first validation helpers to prevent SSRF, injection attacks,
5
+ * and other common OAuth configuration vulnerabilities.
6
+ */
7
+ /**
8
+ * Validates that a domain string is safe from common attacks
9
+ *
10
+ * Prevents SSRF attacks by blocking private IPs, localhost, cloud metadata endpoints,
11
+ * and non-HTTP protocols.
12
+ *
13
+ * @param domain - Domain string to validate (e.g., 'example.okta.com' or 'https://example.okta.com')
14
+ * @param providerName - Name of provider for error messages
15
+ * @returns Validated hostname (without protocol)
16
+ * @throws Error if domain is invalid or unsafe
17
+ */
18
+ export declare function validateDomainSafety(domain: string, providerName: string): string;
19
+ /**
20
+ * Validates that a domain matches an allowlist of permitted suffixes
21
+ *
22
+ * Use after validateDomainSafety() to ensure domains match expected patterns
23
+ * (e.g., *.okta.com, *.auth0.com)
24
+ *
25
+ * @param hostname - Validated hostname (from validateDomainSafety)
26
+ * @param allowedSuffixes - Array of allowed domain suffixes (e.g., ['.okta.com', '.okta-emea.com'])
27
+ * @param providerName - Name of provider for error messages
28
+ * @throws Error if hostname doesn't match any allowed suffix
29
+ */
30
+ export declare function validateDomainAllowlist(hostname: string, allowedSuffixes: string[], providerName: string): void;
31
+ /**
32
+ * Validates email domain format
33
+ *
34
+ * Prevents injection attacks by blocking CRLF, null bytes, and control characters.
35
+ *
36
+ * @param emailDomain - Email domain to validate (e.g., 'example.com')
37
+ * @throws Error if domain contains dangerous characters
38
+ */
39
+ export declare function validateEmailDomain(emailDomain: string): void;
40
+ /**
41
+ * Validates tenant ID format
42
+ *
43
+ * Ensures tenant IDs are safe for URLs and file paths. Enforces length limits
44
+ * and character restrictions.
45
+ *
46
+ * @param tenantId - Tenant ID to validate
47
+ * @throws Error if tenant ID is invalid or unsafe
48
+ */
49
+ export declare function validateTenantId(tenantId: string): void;
50
+ /**
51
+ * Sanitizes tenant name for safe HTML output
52
+ *
53
+ * Prevents XSS attacks by HTML-escaping special characters.
54
+ *
55
+ * @param name - Tenant name to sanitize
56
+ * @returns HTML-escaped tenant name
57
+ */
58
+ export declare function sanitizeTenantName(name: string): string;
59
+ /**
60
+ * Validates Azure tenant ID format
61
+ *
62
+ * Valid formats: GUID, 'common', 'organizations', or 'consumers'
63
+ *
64
+ * @param tenantId - Azure tenant ID to validate
65
+ * @throws Error if tenant ID is invalid
66
+ */
67
+ export declare function validateAzureTenantId(tenantId: string): void;