@flink-app/oidc-plugin 1.0.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,15 @@
1
+ import { FlinkContext } from "@flink-app/flink";
2
+ import { OidcPluginContext } from "./OidcPluginContext";
3
+ import OidcSessionRepo from "./repos/OidcSessionRepo";
4
+ import OidcConnectionRepo from "./repos/OidcConnectionRepo";
5
+ /**
6
+ * Internal context type for OIDC plugin
7
+ * Extends the app's context with OIDC-specific repositories
8
+ */
9
+ export interface OidcInternalContext extends FlinkContext, OidcPluginContext {
10
+ repos: FlinkContext["repos"] & {
11
+ oidcSessionRepo: OidcSessionRepo;
12
+ oidcConnectionRepo: OidcConnectionRepo;
13
+ };
14
+ }
15
+ //# sourceMappingURL=OidcInternalContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcInternalContext.d.ts","sourceRoot":"","sources":["../src/OidcInternalContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,eAAe,MAAM,yBAAyB,CAAC;AACtD,OAAO,kBAAkB,MAAM,4BAA4B,CAAC;AAE5D;;;GAGG;AACH,MAAM,WAAW,mBAAoB,SAAQ,YAAY,EAAE,iBAAiB;IACxE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG;QAC3B,eAAe,EAAE,eAAe,CAAC;QACjC,kBAAkB,EAAE,kBAAkB,CAAC;KAC1C,CAAC;CACL"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,77 @@
1
+ import { FlinkPlugin } from "@flink-app/flink";
2
+ import { OidcPluginOptions } from "./OidcPluginOptions";
3
+ /**
4
+ * OIDC Plugin Factory Function
5
+ *
6
+ * Creates a Flink plugin for OIDC authentication with generic IdP support.
7
+ * Integrates with JWT Auth Plugin for token generation.
8
+ *
9
+ * @param options - OIDC plugin configuration options
10
+ * @returns FlinkPlugin instance
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { jwtAuthPlugin } from '@flink-app/jwt-auth-plugin';
15
+ * import { oidcPlugin } from '@flink-app/oidc-plugin';
16
+ *
17
+ * const app = new FlinkApp({
18
+ * auth: jwtAuthPlugin({
19
+ * secret: process.env.JWT_SECRET!,
20
+ * getUser: async (tokenData) => {
21
+ * return ctx.repos.userRepo.getById(tokenData.userId);
22
+ * },
23
+ * rolePermissions: {
24
+ * user: ['read:own'],
25
+ * admin: ['read:all', 'write:all']
26
+ * }
27
+ * }),
28
+ *
29
+ * plugins: [
30
+ * oidcPlugin({
31
+ * providers: {
32
+ * acme: {
33
+ * issuer: 'https://idp.acme.com',
34
+ * clientId: process.env.OIDC_CLIENT_ID!,
35
+ * clientSecret: process.env.OIDC_CLIENT_SECRET!,
36
+ * callbackUrl: 'https://myapp.com/oidc/acme/callback',
37
+ * discoveryUrl: 'https://idp.acme.com/.well-known/openid-configuration'
38
+ * }
39
+ * },
40
+ * onAuthSuccess: async ({ profile, claims, provider }, ctx) => {
41
+ * // Find or create user (JIT provisioning)
42
+ * let user = await ctx.repos.userRepo.getOne({
43
+ * 'oidcConnections.subject': claims.sub,
44
+ * 'oidcConnections.issuer': claims.iss
45
+ * });
46
+ *
47
+ * if (!user) {
48
+ * user = await ctx.repos.userRepo.create({
49
+ * email: claims.email,
50
+ * name: claims.name,
51
+ * oidcConnections: [{
52
+ * issuer: claims.iss,
53
+ * subject: claims.sub,
54
+ * provider
55
+ * }]
56
+ * });
57
+ * }
58
+ *
59
+ * // Generate JWT token
60
+ * const token = await ctx.plugins.jwtAuth.createToken(
61
+ * { userId: user._id, email: user.email },
62
+ * ['user']
63
+ * );
64
+ *
65
+ * return {
66
+ * user,
67
+ * token,
68
+ * redirectUrl: '/dashboard'
69
+ * };
70
+ * }
71
+ * })
72
+ * ]
73
+ * });
74
+ * ```
75
+ */
76
+ export declare function oidcPlugin(options: OidcPluginOptions): FlinkPlugin;
77
+ //# sourceMappingURL=OidcPlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcPlugin.d.ts","sourceRoot":"","sources":["../src/OidcPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,WAAW,EAAO,MAAM,kBAAkB,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAWxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,WAAW,CA2MlE"}
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.oidcPlugin = oidcPlugin;
30
+ const flink_1 = require("@flink-app/flink");
31
+ const OidcSessionRepo_1 = __importDefault(require("./repos/OidcSessionRepo"));
32
+ const OidcConnectionRepo_1 = __importDefault(require("./repos/OidcConnectionRepo"));
33
+ const encryption_utils_1 = require("./utils/encryption-utils");
34
+ const ProviderRegistry_1 = require("./providers/ProviderRegistry");
35
+ const InitiateOidc = __importStar(require("./handlers/InitiateOidc"));
36
+ const CallbackOidc = __importStar(require("./handlers/CallbackOidc"));
37
+ /**
38
+ * OIDC Plugin Factory Function
39
+ *
40
+ * Creates a Flink plugin for OIDC authentication with generic IdP support.
41
+ * Integrates with JWT Auth Plugin for token generation.
42
+ *
43
+ * @param options - OIDC plugin configuration options
44
+ * @returns FlinkPlugin instance
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * import { jwtAuthPlugin } from '@flink-app/jwt-auth-plugin';
49
+ * import { oidcPlugin } from '@flink-app/oidc-plugin';
50
+ *
51
+ * const app = new FlinkApp({
52
+ * auth: jwtAuthPlugin({
53
+ * secret: process.env.JWT_SECRET!,
54
+ * getUser: async (tokenData) => {
55
+ * return ctx.repos.userRepo.getById(tokenData.userId);
56
+ * },
57
+ * rolePermissions: {
58
+ * user: ['read:own'],
59
+ * admin: ['read:all', 'write:all']
60
+ * }
61
+ * }),
62
+ *
63
+ * plugins: [
64
+ * oidcPlugin({
65
+ * providers: {
66
+ * acme: {
67
+ * issuer: 'https://idp.acme.com',
68
+ * clientId: process.env.OIDC_CLIENT_ID!,
69
+ * clientSecret: process.env.OIDC_CLIENT_SECRET!,
70
+ * callbackUrl: 'https://myapp.com/oidc/acme/callback',
71
+ * discoveryUrl: 'https://idp.acme.com/.well-known/openid-configuration'
72
+ * }
73
+ * },
74
+ * onAuthSuccess: async ({ profile, claims, provider }, ctx) => {
75
+ * // Find or create user (JIT provisioning)
76
+ * let user = await ctx.repos.userRepo.getOne({
77
+ * 'oidcConnections.subject': claims.sub,
78
+ * 'oidcConnections.issuer': claims.iss
79
+ * });
80
+ *
81
+ * if (!user) {
82
+ * user = await ctx.repos.userRepo.create({
83
+ * email: claims.email,
84
+ * name: claims.name,
85
+ * oidcConnections: [{
86
+ * issuer: claims.iss,
87
+ * subject: claims.sub,
88
+ * provider
89
+ * }]
90
+ * });
91
+ * }
92
+ *
93
+ * // Generate JWT token
94
+ * const token = await ctx.plugins.jwtAuth.createToken(
95
+ * { userId: user._id, email: user.email },
96
+ * ['user']
97
+ * );
98
+ *
99
+ * return {
100
+ * user,
101
+ * token,
102
+ * redirectUrl: '/dashboard'
103
+ * };
104
+ * }
105
+ * })
106
+ * ]
107
+ * });
108
+ * ```
109
+ */
110
+ function oidcPlugin(options) {
111
+ // Validation
112
+ if (!options.providers || Object.keys(options.providers).length === 0) {
113
+ throw new Error("OIDC Plugin: At least one provider must be configured");
114
+ }
115
+ // Validate provider configurations
116
+ const configuredProviders = Object.keys(options.providers);
117
+ for (const providerName of configuredProviders) {
118
+ const providerConfig = options.providers[providerName];
119
+ if (!providerConfig)
120
+ continue;
121
+ if (!providerConfig.issuer) {
122
+ throw new Error(`OIDC Plugin: ${providerName} issuer is required`);
123
+ }
124
+ if (!providerConfig.clientId) {
125
+ throw new Error(`OIDC Plugin: ${providerName} clientId is required`);
126
+ }
127
+ if (!providerConfig.clientSecret) {
128
+ throw new Error(`OIDC Plugin: ${providerName} clientSecret is required`);
129
+ }
130
+ if (!providerConfig.callbackUrl) {
131
+ throw new Error(`OIDC Plugin: ${providerName} callbackUrl is required`);
132
+ }
133
+ // Validate that either discoveryUrl or manual endpoints are provided
134
+ if (!providerConfig.discoveryUrl) {
135
+ if (!providerConfig.authorizationEndpoint || !providerConfig.tokenEndpoint || !providerConfig.jwksUri) {
136
+ throw new Error(`OIDC Plugin: ${providerName} must have either discoveryUrl or manual endpoints ` +
137
+ `(authorizationEndpoint, tokenEndpoint, jwksUri)`);
138
+ }
139
+ }
140
+ }
141
+ if (!options.onAuthSuccess) {
142
+ throw new Error("OIDC Plugin: onAuthSuccess callback is required");
143
+ }
144
+ // Determine encryption key
145
+ let encryptionKey = options.encryptionKey;
146
+ if (!encryptionKey) {
147
+ // Derive from first configured provider's client secret
148
+ const firstProvider = configuredProviders[0];
149
+ const firstProviderConfig = options.providers[firstProvider];
150
+ if (firstProviderConfig) {
151
+ encryptionKey = firstProviderConfig.clientSecret;
152
+ flink_1.log.warn("OIDC Plugin: No encryption key provided, deriving from client secret. " + "For better security, provide a dedicated encryptionKey in options.");
153
+ }
154
+ }
155
+ if (!encryptionKey || encryptionKey.length < 32) {
156
+ throw new Error("OIDC Plugin: Encryption key must be at least 32 characters");
157
+ }
158
+ // Validate encryption key
159
+ (0, encryption_utils_1.validateEncryptionSecret)(encryptionKey);
160
+ let flinkApp;
161
+ let sessionRepo;
162
+ let connectionRepo;
163
+ let providerRegistry;
164
+ /**
165
+ * Plugin initialization
166
+ */
167
+ async function init(app, db) {
168
+ flink_1.log.info("Initializing OIDC Plugin...");
169
+ flinkApp = app;
170
+ try {
171
+ if (!db) {
172
+ throw new Error("OIDC Plugin: Database connection is required");
173
+ }
174
+ // Initialize repositories
175
+ const sessionsCollectionName = options.sessionsCollectionName || "oidc_sessions";
176
+ const connectionsCollectionName = options.connectionsCollectionName || "oidc_connections";
177
+ sessionRepo = new OidcSessionRepo_1.default(sessionsCollectionName, db);
178
+ connectionRepo = new OidcConnectionRepo_1.default(connectionsCollectionName, db);
179
+ flinkApp.addRepo("oidcSessionRepo", sessionRepo);
180
+ flinkApp.addRepo("oidcConnectionRepo", connectionRepo);
181
+ // Create TTL index for session expiration
182
+ const sessionTTL = options.sessionTTL || 600; // Default 10 minutes
183
+ await db.collection(sessionsCollectionName).createIndex({ createdAt: 1 }, { expireAfterSeconds: sessionTTL });
184
+ flink_1.log.info(`OIDC Plugin: Created TTL index on ${sessionsCollectionName} with ${sessionTTL}s expiration`);
185
+ // Initialize provider registry
186
+ providerRegistry = new ProviderRegistry_1.ProviderRegistry(options.providers, options.providerLoader);
187
+ // Store provider registry in app context for handlers to access
188
+ flinkApp.ctx.oidcProviderRegistry = providerRegistry;
189
+ // Register OIDC handlers
190
+ // Only register handlers if registerRoutes is enabled (default: true)
191
+ if (options.registerRoutes !== false) {
192
+ flinkApp.addHandler(InitiateOidc);
193
+ flinkApp.addHandler(CallbackOidc);
194
+ }
195
+ flink_1.log.info(`OIDC Plugin initialized with providers: ${configuredProviders.join(", ")}`);
196
+ }
197
+ catch (error) {
198
+ flink_1.log.error("Failed to initialize OIDC Plugin:", error);
199
+ throw error;
200
+ }
201
+ }
202
+ /**
203
+ * Get OIDC connection for a user
204
+ */
205
+ async function getConnection(userId, provider) {
206
+ if (!connectionRepo) {
207
+ throw new Error("OIDC Plugin: Plugin not initialized");
208
+ }
209
+ const connection = await connectionRepo.findByUserAndProvider(userId, provider);
210
+ if (!connection) {
211
+ return null;
212
+ }
213
+ // Decrypt tokens before returning
214
+ if (connection.accessToken && encryptionKey) {
215
+ connection.accessToken = (0, encryption_utils_1.decryptToken)(connection.accessToken, encryptionKey);
216
+ }
217
+ if (connection.idToken && encryptionKey) {
218
+ connection.idToken = (0, encryption_utils_1.decryptToken)(connection.idToken, encryptionKey);
219
+ }
220
+ if (connection.refreshToken && encryptionKey) {
221
+ connection.refreshToken = (0, encryption_utils_1.decryptToken)(connection.refreshToken, encryptionKey);
222
+ }
223
+ return connection;
224
+ }
225
+ /**
226
+ * Get all OIDC connections for a user
227
+ */
228
+ async function getConnections(userId) {
229
+ if (!connectionRepo) {
230
+ throw new Error("OIDC Plugin: Plugin not initialized");
231
+ }
232
+ const connections = await connectionRepo.findByUserId(userId);
233
+ // Decrypt tokens in each connection
234
+ return connections.map((connection) => {
235
+ if (connection.accessToken && encryptionKey) {
236
+ connection.accessToken = (0, encryption_utils_1.decryptToken)(connection.accessToken, encryptionKey);
237
+ }
238
+ if (connection.idToken && encryptionKey) {
239
+ connection.idToken = (0, encryption_utils_1.decryptToken)(connection.idToken, encryptionKey);
240
+ }
241
+ if (connection.refreshToken && encryptionKey) {
242
+ connection.refreshToken = (0, encryption_utils_1.decryptToken)(connection.refreshToken, encryptionKey);
243
+ }
244
+ return connection;
245
+ });
246
+ }
247
+ /**
248
+ * Delete OIDC connection for a user
249
+ */
250
+ async function deleteConnection(userId, provider) {
251
+ if (!connectionRepo) {
252
+ throw new Error("OIDC Plugin: Plugin not initialized");
253
+ }
254
+ await connectionRepo.deleteByUserAndProvider(userId, provider);
255
+ flink_1.log.info(`OIDC Plugin: Deleted ${provider} connection for user ${userId}`);
256
+ }
257
+ /**
258
+ * Plugin context exposed via ctx.plugins.oidc
259
+ */
260
+ const pluginCtx = {
261
+ getConnection,
262
+ getConnections,
263
+ deleteConnection,
264
+ options: Object.freeze({ ...options }),
265
+ };
266
+ return {
267
+ id: "oidc",
268
+ db: {
269
+ useHostDb: true,
270
+ },
271
+ ctx: pluginCtx,
272
+ init,
273
+ };
274
+ }
@@ -0,0 +1,73 @@
1
+ import OidcConnection from "./schemas/OidcConnection";
2
+ import { OidcPluginOptions } from "./OidcPluginOptions";
3
+ /**
4
+ * OIDC Plugin context API exposed via ctx.plugins.oidc
5
+ *
6
+ * Provides methods to manage OIDC connections for users.
7
+ */
8
+ export interface OidcPluginContext {
9
+ oidc: {
10
+ /**
11
+ * Get OIDC connection for a user and provider
12
+ *
13
+ * Returns the stored OIDC connection with decrypted tokens (if storeTokens enabled).
14
+ *
15
+ * @param userId - Application user ID
16
+ * @param provider - Provider name (e.g., "acme")
17
+ * @returns OIDC connection or null if not found
18
+ *
19
+ * Example:
20
+ * ```typescript
21
+ * const connection = await ctx.plugins.oidc.getConnection(user._id, 'acme');
22
+ * if (connection) {
23
+ * console.log('User connected to:', connection.issuer);
24
+ * console.log('Subject:', connection.subject);
25
+ * if (connection.accessToken) {
26
+ * // Use access token to call IdP APIs
27
+ * }
28
+ * }
29
+ * ```
30
+ */
31
+ getConnection: (userId: string, provider: string) => Promise<OidcConnection | null>;
32
+ /**
33
+ * Get all OIDC connections for a user
34
+ *
35
+ * Returns all IdP connections for the user with decrypted tokens.
36
+ *
37
+ * @param userId - Application user ID
38
+ * @returns Array of OIDC connections
39
+ *
40
+ * Example:
41
+ * ```typescript
42
+ * const connections = await ctx.plugins.oidc.getConnections(user._id);
43
+ * console.log('User has', connections.length, 'IdP connections');
44
+ * connections.forEach(conn => {
45
+ * console.log('- Provider:', conn.provider, 'Email:', conn.email);
46
+ * });
47
+ * ```
48
+ */
49
+ getConnections: (userId: string) => Promise<OidcConnection[]>;
50
+ /**
51
+ * Delete/unlink OIDC connection for a user
52
+ *
53
+ * Removes the connection between the user and the IdP.
54
+ * The user will need to re-authenticate with the IdP.
55
+ *
56
+ * @param userId - Application user ID
57
+ * @param provider - Provider name (e.g., "acme")
58
+ *
59
+ * Example:
60
+ * ```typescript
61
+ * // User wants to disconnect their Acme account
62
+ * await ctx.plugins.oidc.deleteConnection(user._id, 'acme');
63
+ * ```
64
+ */
65
+ deleteConnection: (userId: string, provider: string) => Promise<void>;
66
+ /**
67
+ * Plugin configuration options (read-only)
68
+ * Useful for checking plugin settings at runtime
69
+ */
70
+ options: Readonly<OidcPluginOptions>;
71
+ };
72
+ }
73
+ //# sourceMappingURL=OidcPluginContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OidcPluginContext.d.ts","sourceRoot":"","sources":["../src/OidcPluginContext.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE;QACF;;;;;;;;;;;;;;;;;;;;WAoBG;QACH,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;QAEpF;;;;;;;;;;;;;;;;WAgBG;QACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;QAE9D;;;;;;;;;;;;;;WAcG;QACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAEtE;;;WAGG;QACH,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;KACxC,CAAC;CACL"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });