@flink-app/oidc-plugin 0.13.0

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 (112) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +846 -0
  4. package/dist/OidcInternalContext.d.ts +15 -0
  5. package/dist/OidcInternalContext.d.ts.map +1 -0
  6. package/dist/OidcInternalContext.js +2 -0
  7. package/dist/OidcPlugin.d.ts +77 -0
  8. package/dist/OidcPlugin.d.ts.map +1 -0
  9. package/dist/OidcPlugin.js +274 -0
  10. package/dist/OidcPluginContext.d.ts +73 -0
  11. package/dist/OidcPluginContext.d.ts.map +1 -0
  12. package/dist/OidcPluginContext.js +2 -0
  13. package/dist/OidcPluginOptions.d.ts +267 -0
  14. package/dist/OidcPluginOptions.d.ts.map +1 -0
  15. package/dist/OidcPluginOptions.js +2 -0
  16. package/dist/OidcProviderConfig.d.ts +77 -0
  17. package/dist/OidcProviderConfig.d.ts.map +1 -0
  18. package/dist/OidcProviderConfig.js +2 -0
  19. package/dist/handlers/CallbackOidc.d.ts +38 -0
  20. package/dist/handlers/CallbackOidc.d.ts.map +1 -0
  21. package/dist/handlers/CallbackOidc.js +219 -0
  22. package/dist/handlers/InitiateOidc.d.ts +35 -0
  23. package/dist/handlers/InitiateOidc.d.ts.map +1 -0
  24. package/dist/handlers/InitiateOidc.js +91 -0
  25. package/dist/index.d.ts +27 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +40 -0
  28. package/dist/providers/OidcProvider.d.ts +90 -0
  29. package/dist/providers/OidcProvider.d.ts.map +1 -0
  30. package/dist/providers/OidcProvider.js +208 -0
  31. package/dist/providers/ProviderRegistry.d.ts +55 -0
  32. package/dist/providers/ProviderRegistry.d.ts.map +1 -0
  33. package/dist/providers/ProviderRegistry.js +94 -0
  34. package/dist/repos/OidcConnectionRepo.d.ts +75 -0
  35. package/dist/repos/OidcConnectionRepo.d.ts.map +1 -0
  36. package/dist/repos/OidcConnectionRepo.js +122 -0
  37. package/dist/repos/OidcSessionRepo.d.ts +57 -0
  38. package/dist/repos/OidcSessionRepo.d.ts.map +1 -0
  39. package/dist/repos/OidcSessionRepo.js +91 -0
  40. package/dist/schemas/CallbackRequest.d.ts +37 -0
  41. package/dist/schemas/CallbackRequest.d.ts.map +1 -0
  42. package/dist/schemas/CallbackRequest.js +2 -0
  43. package/dist/schemas/InitiateRequest.d.ts +17 -0
  44. package/dist/schemas/InitiateRequest.d.ts.map +1 -0
  45. package/dist/schemas/InitiateRequest.js +2 -0
  46. package/dist/schemas/OidcConnection.d.ts +69 -0
  47. package/dist/schemas/OidcConnection.d.ts.map +1 -0
  48. package/dist/schemas/OidcConnection.js +2 -0
  49. package/dist/schemas/OidcProfile.d.ts +69 -0
  50. package/dist/schemas/OidcProfile.d.ts.map +1 -0
  51. package/dist/schemas/OidcProfile.js +2 -0
  52. package/dist/schemas/OidcSession.d.ts +46 -0
  53. package/dist/schemas/OidcSession.d.ts.map +1 -0
  54. package/dist/schemas/OidcSession.js +2 -0
  55. package/dist/schemas/OidcTokenSet.d.ts +42 -0
  56. package/dist/schemas/OidcTokenSet.d.ts.map +1 -0
  57. package/dist/schemas/OidcTokenSet.js +2 -0
  58. package/dist/utils/claims-mapper.d.ts +46 -0
  59. package/dist/utils/claims-mapper.d.ts.map +1 -0
  60. package/dist/utils/claims-mapper.js +104 -0
  61. package/dist/utils/encryption-utils.d.ts +32 -0
  62. package/dist/utils/encryption-utils.d.ts.map +1 -0
  63. package/dist/utils/encryption-utils.js +82 -0
  64. package/dist/utils/error-utils.d.ts +65 -0
  65. package/dist/utils/error-utils.d.ts.map +1 -0
  66. package/dist/utils/error-utils.js +150 -0
  67. package/dist/utils/response-utils.d.ts +18 -0
  68. package/dist/utils/response-utils.d.ts.map +1 -0
  69. package/dist/utils/response-utils.js +42 -0
  70. package/dist/utils/state-utils.d.ts +36 -0
  71. package/dist/utils/state-utils.d.ts.map +1 -0
  72. package/dist/utils/state-utils.js +66 -0
  73. package/examples/basic-oidc.ts +151 -0
  74. package/examples/multi-provider.ts +146 -0
  75. package/package.json +44 -0
  76. package/spec/handlers/InitiateOidc.spec.ts +62 -0
  77. package/spec/helpers/reporter.ts +34 -0
  78. package/spec/helpers/test-helpers.ts +108 -0
  79. package/spec/plugin/OidcPlugin.spec.ts +126 -0
  80. package/spec/providers/ProviderRegistry.spec.ts +197 -0
  81. package/spec/repos/OidcConnectionRepo.spec.ts +257 -0
  82. package/spec/repos/OidcSessionRepo.spec.ts +196 -0
  83. package/spec/support/jasmine.json +7 -0
  84. package/spec/utils/claims-mapper.spec.ts +257 -0
  85. package/spec/utils/encryption-utils.spec.ts +126 -0
  86. package/spec/utils/error-utils.spec.ts +107 -0
  87. package/spec/utils/state-utils.spec.ts +102 -0
  88. package/src/OidcInternalContext.ts +15 -0
  89. package/src/OidcPlugin.ts +290 -0
  90. package/src/OidcPluginContext.ts +76 -0
  91. package/src/OidcPluginOptions.ts +286 -0
  92. package/src/OidcProviderConfig.ts +87 -0
  93. package/src/handlers/CallbackOidc.ts +257 -0
  94. package/src/handlers/InitiateOidc.ts +110 -0
  95. package/src/index.ts +38 -0
  96. package/src/providers/OidcProvider.ts +237 -0
  97. package/src/providers/ProviderRegistry.ts +107 -0
  98. package/src/repos/OidcConnectionRepo.ts +132 -0
  99. package/src/repos/OidcSessionRepo.ts +99 -0
  100. package/src/schemas/CallbackRequest.ts +41 -0
  101. package/src/schemas/InitiateRequest.ts +17 -0
  102. package/src/schemas/OidcConnection.ts +80 -0
  103. package/src/schemas/OidcProfile.ts +79 -0
  104. package/src/schemas/OidcSession.ts +52 -0
  105. package/src/schemas/OidcTokenSet.ts +47 -0
  106. package/src/utils/claims-mapper.ts +114 -0
  107. package/src/utils/encryption-utils.ts +92 -0
  108. package/src/utils/error-utils.ts +167 -0
  109. package/src/utils/response-utils.ts +41 -0
  110. package/src/utils/state-utils.ts +66 -0
  111. package/tsconfig.dist.json +9 -0
  112. package/tsconfig.json +20 -0
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ /**
3
+ * OIDC Initiate Handler
4
+ *
5
+ * Initiates the OIDC authorization code flow by:
6
+ * 1. Validating the provider is supported and configured
7
+ * 2. Generating cryptographically secure state, code_verifier, and nonce
8
+ * 3. Creating an OIDC session to track the flow
9
+ * 4. Building the provider's authorization URL with PKCE
10
+ * 5. Redirecting the user to the provider for authorization
11
+ *
12
+ * Route: GET /oidc/:provider/initiate?redirectUri={optional_redirect_url}
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.Route = void 0;
16
+ const flink_1 = require("@flink-app/flink");
17
+ const state_utils_1 = require("../utils/state-utils");
18
+ const error_utils_1 = require("../utils/error-utils");
19
+ const openid_client_1 = require("openid-client");
20
+ /**
21
+ * Route configuration
22
+ * This handler is registered programmatically by the plugin
23
+ */
24
+ exports.Route = {
25
+ path: "/oidc/:provider/initiate",
26
+ method: flink_1.HttpMethod.get,
27
+ };
28
+ /**
29
+ * OIDC Initiate Handler
30
+ *
31
+ * Starts the OIDC flow by generating security parameters, creating a session,
32
+ * and redirecting to the OIDC provider's authorization URL.
33
+ */
34
+ const InitiateOidc = async ({ ctx, req }) => {
35
+ const { provider } = req.params;
36
+ const { redirectUri } = req.query;
37
+ try {
38
+ // Validate provider name format
39
+ (0, error_utils_1.validateProvider)(provider);
40
+ // Get provider registry from context
41
+ const providerRegistry = ctx.oidcProviderRegistry;
42
+ if (!providerRegistry) {
43
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.PROVIDER_NOT_CONFIGURED, "OIDC plugin not properly initialized");
44
+ }
45
+ // Get OIDC provider instance (loads dynamically if needed)
46
+ const oidcProvider = await providerRegistry.getProvider(provider);
47
+ // Get plugin options
48
+ const { options } = ctx.plugins.oidc;
49
+ // Determine redirect URI (use provided or default to callback URL)
50
+ const staticProviderConfig = options.providers[provider];
51
+ const finalRedirectUri = redirectUri || staticProviderConfig?.callbackUrl || `${req.protocol}://${req.get("host")}/oidc/${provider}/callback`;
52
+ // Generate cryptographically secure parameters
53
+ const state = (0, state_utils_1.generateState)();
54
+ const sessionId = (0, state_utils_1.generateSessionId)();
55
+ const nonce = (0, state_utils_1.generateNonce)();
56
+ const codeVerifier = openid_client_1.generators.codeVerifier();
57
+ // Store session for state validation in callback
58
+ await ctx.repos.oidcSessionRepo.create({
59
+ sessionId,
60
+ state,
61
+ codeVerifier,
62
+ nonce,
63
+ provider,
64
+ redirectUri: finalRedirectUri,
65
+ createdAt: new Date(),
66
+ });
67
+ // Build authorization URL with PKCE and nonce
68
+ const authorizationUrl = await oidcProvider.getAuthorizationUrl({
69
+ state,
70
+ codeVerifier,
71
+ nonce,
72
+ });
73
+ // Redirect user to provider's authorization page
74
+ return {
75
+ status: 302,
76
+ headers: {
77
+ Location: authorizationUrl,
78
+ },
79
+ data: {},
80
+ };
81
+ }
82
+ catch (error) {
83
+ // Handle validation errors
84
+ if (error.code && Object.values(error_utils_1.OidcErrorCodes).includes(error.code)) {
85
+ return (0, flink_1.badRequest)(error.message);
86
+ }
87
+ // Handle unexpected errors
88
+ return (0, flink_1.internalServerError)(error.message || "Failed to initiate OIDC flow");
89
+ }
90
+ };
91
+ exports.default = InitiateOidc;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @flink-app/oidc-plugin
3
+ *
4
+ * OIDC authentication plugin for Flink Framework
5
+ *
6
+ * Provides OpenID Connect authentication with generic IdP support,
7
+ * JWT integration via jwt-auth-plugin, JIT user provisioning,
8
+ * and optional token storage for API access.
9
+ */
10
+ export { oidcPlugin } from "./OidcPlugin";
11
+ export { OidcPluginOptions, OidcError, AuthSuccessCallbackResponse, AuthErrorCallbackResponse } from "./OidcPluginOptions";
12
+ export { OidcProviderConfig } from "./OidcProviderConfig";
13
+ export { OidcPluginContext } from "./OidcPluginContext";
14
+ export { default as OidcProfile } from "./schemas/OidcProfile";
15
+ export { default as OidcTokenSet } from "./schemas/OidcTokenSet";
16
+ export { default as OidcSession } from "./schemas/OidcSession";
17
+ export { default as OidcConnection } from "./schemas/OidcConnection";
18
+ export { default as InitiateRequest } from "./schemas/InitiateRequest";
19
+ export { default as CallbackRequest } from "./schemas/CallbackRequest";
20
+ export { OidcProvider } from "./providers/OidcProvider";
21
+ export { ProviderRegistry } from "./providers/ProviderRegistry";
22
+ export { generateState, generateSessionId, generateNonce, validateState } from "./utils/state-utils";
23
+ export { encryptToken, decryptToken, validateEncryptionSecret } from "./utils/encryption-utils";
24
+ export { mapClaimsToProfile, extractCustomClaims } from "./utils/claims-mapper";
25
+ export { formatTokenResponse } from "./utils/response-utils";
26
+ export { createOidcError, validateProvider, handleProviderError, OidcErrorCodes } from "./utils/error-utils";
27
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC3H,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGvE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACrG,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * @flink-app/oidc-plugin
4
+ *
5
+ * OIDC authentication plugin for Flink Framework
6
+ *
7
+ * Provides OpenID Connect authentication with generic IdP support,
8
+ * JWT integration via jwt-auth-plugin, JIT user provisioning,
9
+ * and optional token storage for API access.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.OidcErrorCodes = exports.handleProviderError = exports.validateProvider = exports.createOidcError = exports.formatTokenResponse = exports.extractCustomClaims = exports.mapClaimsToProfile = exports.validateEncryptionSecret = exports.decryptToken = exports.encryptToken = exports.validateState = exports.generateNonce = exports.generateSessionId = exports.generateState = exports.ProviderRegistry = exports.OidcProvider = exports.oidcPlugin = void 0;
13
+ // Main plugin factory
14
+ var OidcPlugin_1 = require("./OidcPlugin");
15
+ Object.defineProperty(exports, "oidcPlugin", { enumerable: true, get: function () { return OidcPlugin_1.oidcPlugin; } });
16
+ // Provider classes (for advanced usage)
17
+ var OidcProvider_1 = require("./providers/OidcProvider");
18
+ Object.defineProperty(exports, "OidcProvider", { enumerable: true, get: function () { return OidcProvider_1.OidcProvider; } });
19
+ var ProviderRegistry_1 = require("./providers/ProviderRegistry");
20
+ Object.defineProperty(exports, "ProviderRegistry", { enumerable: true, get: function () { return ProviderRegistry_1.ProviderRegistry; } });
21
+ // Utility functions (for custom implementations)
22
+ var state_utils_1 = require("./utils/state-utils");
23
+ Object.defineProperty(exports, "generateState", { enumerable: true, get: function () { return state_utils_1.generateState; } });
24
+ Object.defineProperty(exports, "generateSessionId", { enumerable: true, get: function () { return state_utils_1.generateSessionId; } });
25
+ Object.defineProperty(exports, "generateNonce", { enumerable: true, get: function () { return state_utils_1.generateNonce; } });
26
+ Object.defineProperty(exports, "validateState", { enumerable: true, get: function () { return state_utils_1.validateState; } });
27
+ var encryption_utils_1 = require("./utils/encryption-utils");
28
+ Object.defineProperty(exports, "encryptToken", { enumerable: true, get: function () { return encryption_utils_1.encryptToken; } });
29
+ Object.defineProperty(exports, "decryptToken", { enumerable: true, get: function () { return encryption_utils_1.decryptToken; } });
30
+ Object.defineProperty(exports, "validateEncryptionSecret", { enumerable: true, get: function () { return encryption_utils_1.validateEncryptionSecret; } });
31
+ var claims_mapper_1 = require("./utils/claims-mapper");
32
+ Object.defineProperty(exports, "mapClaimsToProfile", { enumerable: true, get: function () { return claims_mapper_1.mapClaimsToProfile; } });
33
+ Object.defineProperty(exports, "extractCustomClaims", { enumerable: true, get: function () { return claims_mapper_1.extractCustomClaims; } });
34
+ var response_utils_1 = require("./utils/response-utils");
35
+ Object.defineProperty(exports, "formatTokenResponse", { enumerable: true, get: function () { return response_utils_1.formatTokenResponse; } });
36
+ var error_utils_1 = require("./utils/error-utils");
37
+ Object.defineProperty(exports, "createOidcError", { enumerable: true, get: function () { return error_utils_1.createOidcError; } });
38
+ Object.defineProperty(exports, "validateProvider", { enumerable: true, get: function () { return error_utils_1.validateProvider; } });
39
+ Object.defineProperty(exports, "handleProviderError", { enumerable: true, get: function () { return error_utils_1.handleProviderError; } });
40
+ Object.defineProperty(exports, "OidcErrorCodes", { enumerable: true, get: function () { return error_utils_1.OidcErrorCodes; } });
@@ -0,0 +1,90 @@
1
+ import { UserinfoResponse } from "openid-client";
2
+ import { OidcProviderConfig } from "../OidcProviderConfig";
3
+ import OidcProfile from "../schemas/OidcProfile";
4
+ import OidcTokenSet from "../schemas/OidcTokenSet";
5
+ /**
6
+ * Generic OIDC Provider implementation using openid-client
7
+ *
8
+ * Supports both OIDC discovery and manual configuration.
9
+ * Handles the complete OIDC flow including:
10
+ * - Authorization URL generation with PKCE
11
+ * - Token exchange (code → tokens)
12
+ * - ID token validation
13
+ * - UserInfo endpoint fetching
14
+ * - Claims mapping to profile
15
+ */
16
+ export declare class OidcProvider {
17
+ private config;
18
+ private issuer;
19
+ private client;
20
+ private initialized;
21
+ constructor(config: OidcProviderConfig);
22
+ /**
23
+ * Initialize the provider by discovering or creating the OIDC client
24
+ *
25
+ * Uses OIDC discovery if discoveryUrl is provided, otherwise uses
26
+ * manual endpoint configuration.
27
+ *
28
+ * This is async and should be called before using the provider.
29
+ */
30
+ initialize(): Promise<void>;
31
+ /**
32
+ * Generate authorization URL with PKCE and nonce
33
+ *
34
+ * @param params - Authorization parameters
35
+ * @returns Authorization URL to redirect user to
36
+ */
37
+ getAuthorizationUrl(params: {
38
+ state: string;
39
+ codeVerifier: string;
40
+ nonce: string;
41
+ }): Promise<string>;
42
+ /**
43
+ * Exchange authorization code for tokens
44
+ *
45
+ * Performs the OAuth 2.0 token exchange and validates the ID token.
46
+ *
47
+ * @param params - Token exchange parameters
48
+ * @returns Token set with access token, ID token, and claims
49
+ */
50
+ exchangeCodeForToken(params: {
51
+ code: string;
52
+ codeVerifier: string;
53
+ state: string;
54
+ nonce: string;
55
+ }): Promise<OidcTokenSet>;
56
+ /**
57
+ * Get user profile from UserInfo endpoint
58
+ *
59
+ * Fetches additional user claims from the UserInfo endpoint.
60
+ * Merges with claims from ID token.
61
+ *
62
+ * @param accessToken - Access token from token exchange
63
+ * @returns UserInfo response
64
+ */
65
+ getUserInfo(accessToken: string): Promise<UserinfoResponse>;
66
+ /**
67
+ * Build complete user profile from tokens
68
+ *
69
+ * Combines claims from ID token and UserInfo endpoint,
70
+ * applies custom claim mapping, and returns normalized profile.
71
+ *
72
+ * @param tokenSet - Token set from exchange
73
+ * @param includeUserInfo - Whether to fetch UserInfo endpoint
74
+ * @returns Normalized user profile
75
+ */
76
+ buildProfile(tokenSet: OidcTokenSet, includeUserInfo?: boolean): Promise<OidcProfile>;
77
+ /**
78
+ * Ensure provider is initialized before use
79
+ *
80
+ * @throws Error if not initialized
81
+ */
82
+ private ensureInitialized;
83
+ /**
84
+ * Get issuer metadata (after initialization)
85
+ *
86
+ * @returns Issuer metadata
87
+ */
88
+ getIssuerMetadata(): any;
89
+ }
90
+ //# sourceMappingURL=OidcProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OidcProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,WAAW,MAAM,wBAAwB,CAAC;AACjD,OAAO,YAAY,MAAM,yBAAyB,CAAC;AAInD;;;;;;;;;;GAUG;AACH,qBAAa,YAAY;IACrB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAkB;gBAEzB,MAAM,EAAE,kBAAkB;IAItC;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA+CjC;;;;;OAKG;IACG,mBAAmB,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAiB1G;;;;;;;OAOG;IACG,oBAAoB,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC;IAqC/H;;;;;;;;OAQG;IACG,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAajE;;;;;;;;;OASG;IACG,YAAY,CAAC,QAAQ,EAAE,YAAY,EAAE,eAAe,GAAE,OAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IA2BjG;;;;OAIG;YACW,iBAAiB;IAU/B;;;;OAIG;IACH,iBAAiB,IAAI,GAAG;CAM3B"}
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OidcProvider = void 0;
4
+ const openid_client_1 = require("openid-client");
5
+ const claims_mapper_1 = require("../utils/claims-mapper");
6
+ const error_utils_1 = require("../utils/error-utils");
7
+ /**
8
+ * Generic OIDC Provider implementation using openid-client
9
+ *
10
+ * Supports both OIDC discovery and manual configuration.
11
+ * Handles the complete OIDC flow including:
12
+ * - Authorization URL generation with PKCE
13
+ * - Token exchange (code → tokens)
14
+ * - ID token validation
15
+ * - UserInfo endpoint fetching
16
+ * - Claims mapping to profile
17
+ */
18
+ class OidcProvider {
19
+ constructor(config) {
20
+ this.issuer = null;
21
+ this.client = null;
22
+ this.initialized = false;
23
+ this.config = config;
24
+ }
25
+ /**
26
+ * Initialize the provider by discovering or creating the OIDC client
27
+ *
28
+ * Uses OIDC discovery if discoveryUrl is provided, otherwise uses
29
+ * manual endpoint configuration.
30
+ *
31
+ * This is async and should be called before using the provider.
32
+ */
33
+ async initialize() {
34
+ if (this.initialized) {
35
+ return;
36
+ }
37
+ try {
38
+ // Option 1: OIDC Discovery
39
+ if (this.config.discoveryUrl) {
40
+ this.issuer = await openid_client_1.Issuer.discover(this.config.discoveryUrl);
41
+ }
42
+ // Option 2: Manual configuration
43
+ else {
44
+ // Validate required endpoints for manual config
45
+ if (!this.config.authorizationEndpoint || !this.config.tokenEndpoint || !this.config.jwksUri) {
46
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.PROVIDER_NOT_CONFIGURED, "Provider must have either discoveryUrl or manual endpoints (authorizationEndpoint, tokenEndpoint, jwksUri)", { provider: this.config.issuer });
47
+ }
48
+ this.issuer = new openid_client_1.Issuer({
49
+ issuer: this.config.issuer,
50
+ authorization_endpoint: this.config.authorizationEndpoint,
51
+ token_endpoint: this.config.tokenEndpoint,
52
+ userinfo_endpoint: this.config.userinfoEndpoint,
53
+ jwks_uri: this.config.jwksUri,
54
+ });
55
+ }
56
+ // Create OIDC client
57
+ this.client = new this.issuer.Client({
58
+ client_id: this.config.clientId,
59
+ client_secret: this.config.clientSecret,
60
+ redirect_uris: [this.config.callbackUrl],
61
+ response_types: ["code"],
62
+ });
63
+ this.initialized = true;
64
+ }
65
+ catch (error) {
66
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.DISCOVERY_FAILED, `Failed to initialize OIDC provider: ${error.message}`, {
67
+ issuer: this.config.issuer,
68
+ originalError: error.message,
69
+ });
70
+ }
71
+ }
72
+ /**
73
+ * Generate authorization URL with PKCE and nonce
74
+ *
75
+ * @param params - Authorization parameters
76
+ * @returns Authorization URL to redirect user to
77
+ */
78
+ async getAuthorizationUrl(params) {
79
+ await this.ensureInitialized();
80
+ const codeChallenge = openid_client_1.generators.codeChallenge(params.codeVerifier);
81
+ const scope = this.config.scope?.join(" ") || "openid email profile";
82
+ const authUrl = this.client.authorizationUrl({
83
+ scope,
84
+ state: params.state,
85
+ code_challenge: codeChallenge,
86
+ code_challenge_method: "S256",
87
+ nonce: params.nonce,
88
+ });
89
+ return authUrl;
90
+ }
91
+ /**
92
+ * Exchange authorization code for tokens
93
+ *
94
+ * Performs the OAuth 2.0 token exchange and validates the ID token.
95
+ *
96
+ * @param params - Token exchange parameters
97
+ * @returns Token set with access token, ID token, and claims
98
+ */
99
+ async exchangeCodeForToken(params) {
100
+ await this.ensureInitialized();
101
+ try {
102
+ const tokenSet = await this.client.callback(this.config.callbackUrl, {
103
+ code: params.code,
104
+ state: params.state,
105
+ }, {
106
+ code_verifier: params.codeVerifier,
107
+ state: params.state,
108
+ nonce: params.nonce,
109
+ });
110
+ // Extract claims from ID token (already validated by openid-client)
111
+ const claims = tokenSet.claims();
112
+ return {
113
+ accessToken: tokenSet.access_token,
114
+ idToken: tokenSet.id_token,
115
+ refreshToken: tokenSet.refresh_token,
116
+ tokenType: tokenSet.token_type || "Bearer",
117
+ expiresIn: tokenSet.expires_in,
118
+ scope: tokenSet.scope,
119
+ claims,
120
+ };
121
+ }
122
+ catch (error) {
123
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.TOKEN_EXCHANGE_FAILED, `Token exchange failed: ${error.message}`, {
124
+ originalError: error.message,
125
+ errorCode: error.error,
126
+ });
127
+ }
128
+ }
129
+ /**
130
+ * Get user profile from UserInfo endpoint
131
+ *
132
+ * Fetches additional user claims from the UserInfo endpoint.
133
+ * Merges with claims from ID token.
134
+ *
135
+ * @param accessToken - Access token from token exchange
136
+ * @returns UserInfo response
137
+ */
138
+ async getUserInfo(accessToken) {
139
+ await this.ensureInitialized();
140
+ try {
141
+ const userinfo = await this.client.userinfo(accessToken);
142
+ return userinfo;
143
+ }
144
+ catch (error) {
145
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.USERINFO_FAILED, `UserInfo request failed: ${error.message}`, {
146
+ originalError: error.message,
147
+ });
148
+ }
149
+ }
150
+ /**
151
+ * Build complete user profile from tokens
152
+ *
153
+ * Combines claims from ID token and UserInfo endpoint,
154
+ * applies custom claim mapping, and returns normalized profile.
155
+ *
156
+ * @param tokenSet - Token set from exchange
157
+ * @param includeUserInfo - Whether to fetch UserInfo endpoint
158
+ * @returns Normalized user profile
159
+ */
160
+ async buildProfile(tokenSet, includeUserInfo = true) {
161
+ let claims = { ...tokenSet.claims };
162
+ // Optionally fetch additional claims from UserInfo endpoint
163
+ if (includeUserInfo && this.config.userinfoEndpoint) {
164
+ try {
165
+ const userinfo = await this.getUserInfo(tokenSet.accessToken);
166
+ // Merge UserInfo claims with ID token claims
167
+ claims = { ...claims, ...userinfo };
168
+ }
169
+ catch (error) {
170
+ // UserInfo is optional - continue with ID token claims only
171
+ console.warn("Failed to fetch UserInfo, using ID token claims only:", error);
172
+ }
173
+ }
174
+ // Apply custom claim mapping if configured
175
+ if (this.config.claimMapping) {
176
+ const customClaims = (0, claims_mapper_1.extractCustomClaims)(claims, this.config.claimMapping);
177
+ claims = { ...claims, ...customClaims };
178
+ }
179
+ // Map to normalized profile
180
+ const profile = (0, claims_mapper_1.mapClaimsToProfile)(claims);
181
+ return profile;
182
+ }
183
+ /**
184
+ * Ensure provider is initialized before use
185
+ *
186
+ * @throws Error if not initialized
187
+ */
188
+ async ensureInitialized() {
189
+ if (!this.initialized) {
190
+ await this.initialize();
191
+ }
192
+ if (!this.client) {
193
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.PROVIDER_NOT_CONFIGURED, "OIDC client not initialized");
194
+ }
195
+ }
196
+ /**
197
+ * Get issuer metadata (after initialization)
198
+ *
199
+ * @returns Issuer metadata
200
+ */
201
+ getIssuerMetadata() {
202
+ if (!this.issuer) {
203
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.PROVIDER_NOT_CONFIGURED, "Provider not initialized");
204
+ }
205
+ return this.issuer.metadata;
206
+ }
207
+ }
208
+ exports.OidcProvider = OidcProvider;
@@ -0,0 +1,55 @@
1
+ import { OidcProvider } from "./OidcProvider";
2
+ import { OidcProviderConfig } from "../OidcProviderConfig";
3
+ /**
4
+ * Provider registry for managing OIDC provider instances
5
+ *
6
+ * Handles:
7
+ * - Static provider configuration
8
+ * - Dynamic provider loading from database
9
+ * - Provider instance caching
10
+ * - Lazy initialization
11
+ */
12
+ export declare class ProviderRegistry {
13
+ private staticProviders;
14
+ private providerInstances;
15
+ private providerLoader?;
16
+ constructor(staticProviders: Record<string, OidcProviderConfig>, providerLoader?: (providerName: string) => Promise<OidcProviderConfig | null>);
17
+ /**
18
+ * Get provider instance by name
19
+ *
20
+ * Looks up provider in the following order:
21
+ * 1. Cached instance
22
+ * 2. Static configuration
23
+ * 3. Dynamic loader (if configured)
24
+ *
25
+ * Providers are lazy-initialized on first use and cached.
26
+ *
27
+ * @param providerName - Provider identifier
28
+ * @returns Initialized OIDC provider instance
29
+ * @throws Error if provider not found or initialization fails
30
+ */
31
+ getProvider(providerName: string): Promise<OidcProvider>;
32
+ /**
33
+ * Check if provider exists in static configuration or can be loaded dynamically
34
+ *
35
+ * @param providerName - Provider identifier
36
+ * @returns true if provider exists, false otherwise
37
+ */
38
+ hasProvider(providerName: string): boolean;
39
+ /**
40
+ * Clear provider cache
41
+ *
42
+ * Forces re-initialization of providers on next access.
43
+ * Useful when provider configurations change.
44
+ *
45
+ * @param providerName - Optional provider to clear (clears all if not specified)
46
+ */
47
+ clearCache(providerName?: string): void;
48
+ /**
49
+ * Get list of configured provider names
50
+ *
51
+ * @returns Array of provider names from static configuration
52
+ */
53
+ getProviderNames(): string[];
54
+ }
55
+ //# sourceMappingURL=ProviderRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProviderRegistry.d.ts","sourceRoot":"","sources":["../../src/providers/ProviderRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG3D;;;;;;;;GAQG;AACH,qBAAa,gBAAgB;IACzB,OAAO,CAAC,eAAe,CAAqC;IAC5D,OAAO,CAAC,iBAAiB,CAAwC;IACjE,OAAO,CAAC,cAAc,CAAC,CAA+D;gBAGlF,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACnD,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAMjF;;;;;;;;;;;;;OAaG;IACG,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAgC9D;;;;;OAKG;IACH,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAI1C;;;;;;;OAOG;IACH,UAAU,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvC;;;;OAIG;IACH,gBAAgB,IAAI,MAAM,EAAE;CAG/B"}
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProviderRegistry = void 0;
4
+ const OidcProvider_1 = require("./OidcProvider");
5
+ const error_utils_1 = require("../utils/error-utils");
6
+ /**
7
+ * Provider registry for managing OIDC provider instances
8
+ *
9
+ * Handles:
10
+ * - Static provider configuration
11
+ * - Dynamic provider loading from database
12
+ * - Provider instance caching
13
+ * - Lazy initialization
14
+ */
15
+ class ProviderRegistry {
16
+ constructor(staticProviders, providerLoader) {
17
+ this.providerInstances = new Map();
18
+ this.staticProviders = staticProviders;
19
+ this.providerLoader = providerLoader;
20
+ }
21
+ /**
22
+ * Get provider instance by name
23
+ *
24
+ * Looks up provider in the following order:
25
+ * 1. Cached instance
26
+ * 2. Static configuration
27
+ * 3. Dynamic loader (if configured)
28
+ *
29
+ * Providers are lazy-initialized on first use and cached.
30
+ *
31
+ * @param providerName - Provider identifier
32
+ * @returns Initialized OIDC provider instance
33
+ * @throws Error if provider not found or initialization fails
34
+ */
35
+ async getProvider(providerName) {
36
+ // Check cache first
37
+ const cachedProvider = this.providerInstances.get(providerName);
38
+ if (cachedProvider) {
39
+ return cachedProvider;
40
+ }
41
+ // Try static configuration
42
+ let config = this.staticProviders[providerName] || null;
43
+ // Try dynamic loader if not in static config
44
+ if (!config && this.providerLoader) {
45
+ config = await this.providerLoader(providerName);
46
+ }
47
+ if (!config) {
48
+ throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.PROVIDER_NOT_CONFIGURED, `OIDC provider '${providerName}' is not configured`, {
49
+ providerName,
50
+ availableProviders: Object.keys(this.staticProviders),
51
+ });
52
+ }
53
+ // Create and initialize provider
54
+ const provider = new OidcProvider_1.OidcProvider(config);
55
+ await provider.initialize();
56
+ // Cache the instance
57
+ this.providerInstances.set(providerName, provider);
58
+ return provider;
59
+ }
60
+ /**
61
+ * Check if provider exists in static configuration or can be loaded dynamically
62
+ *
63
+ * @param providerName - Provider identifier
64
+ * @returns true if provider exists, false otherwise
65
+ */
66
+ hasProvider(providerName) {
67
+ return providerName in this.staticProviders || !!this.providerLoader;
68
+ }
69
+ /**
70
+ * Clear provider cache
71
+ *
72
+ * Forces re-initialization of providers on next access.
73
+ * Useful when provider configurations change.
74
+ *
75
+ * @param providerName - Optional provider to clear (clears all if not specified)
76
+ */
77
+ clearCache(providerName) {
78
+ if (providerName) {
79
+ this.providerInstances.delete(providerName);
80
+ }
81
+ else {
82
+ this.providerInstances.clear();
83
+ }
84
+ }
85
+ /**
86
+ * Get list of configured provider names
87
+ *
88
+ * @returns Array of provider names from static configuration
89
+ */
90
+ getProviderNames() {
91
+ return Object.keys(this.staticProviders);
92
+ }
93
+ }
94
+ exports.ProviderRegistry = ProviderRegistry;