@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.
- package/LICENSE +201 -0
- package/README.md +219 -0
- package/assets/test.html +321 -0
- package/config.yaml +23 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +241 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/CSRFTokenManager.d.ts +32 -0
- package/dist/lib/CSRFTokenManager.js +90 -0
- package/dist/lib/CSRFTokenManager.js.map +1 -0
- package/dist/lib/OAuthProvider.d.ts +59 -0
- package/dist/lib/OAuthProvider.js +370 -0
- package/dist/lib/OAuthProvider.js.map +1 -0
- package/dist/lib/config.d.ts +31 -0
- package/dist/lib/config.js +138 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/handlers.d.ts +56 -0
- package/dist/lib/handlers.js +386 -0
- package/dist/lib/handlers.js.map +1 -0
- package/dist/lib/hookManager.d.ts +52 -0
- package/dist/lib/hookManager.js +114 -0
- package/dist/lib/hookManager.js.map +1 -0
- package/dist/lib/providers/auth0.d.ts +8 -0
- package/dist/lib/providers/auth0.js +34 -0
- package/dist/lib/providers/auth0.js.map +1 -0
- package/dist/lib/providers/azure.d.ts +7 -0
- package/dist/lib/providers/azure.js +33 -0
- package/dist/lib/providers/azure.js.map +1 -0
- package/dist/lib/providers/generic.d.ts +7 -0
- package/dist/lib/providers/generic.js +20 -0
- package/dist/lib/providers/generic.js.map +1 -0
- package/dist/lib/providers/github.d.ts +7 -0
- package/dist/lib/providers/github.js +73 -0
- package/dist/lib/providers/github.js.map +1 -0
- package/dist/lib/providers/google.d.ts +7 -0
- package/dist/lib/providers/google.js +27 -0
- package/dist/lib/providers/google.js.map +1 -0
- package/dist/lib/providers/index.d.ts +17 -0
- package/dist/lib/providers/index.js +49 -0
- package/dist/lib/providers/index.js.map +1 -0
- package/dist/lib/providers/okta.d.ts +8 -0
- package/dist/lib/providers/okta.js +45 -0
- package/dist/lib/providers/okta.js.map +1 -0
- package/dist/lib/providers/validation.d.ts +67 -0
- package/dist/lib/providers/validation.js +156 -0
- package/dist/lib/providers/validation.js.map +1 -0
- package/dist/lib/resource.d.ts +102 -0
- package/dist/lib/resource.js +368 -0
- package/dist/lib/resource.js.map +1 -0
- package/dist/lib/sessionValidator.d.ts +38 -0
- package/dist/lib/sessionValidator.js +162 -0
- package/dist/lib/sessionValidator.js.map +1 -0
- package/dist/lib/tenantManager.d.ts +102 -0
- package/dist/lib/tenantManager.js +177 -0
- package/dist/lib/tenantManager.js.map +1 -0
- package/dist/lib/withOAuthValidation.d.ts +64 -0
- package/dist/lib/withOAuthValidation.js +188 -0
- package/dist/lib/withOAuthValidation.js.map +1 -0
- package/dist/types.d.ts +326 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +89 -0
- 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,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,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,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,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,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;
|