@flink-app/oauth-plugin 0.12.1-alpha.33

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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +783 -0
  3. package/SECURITY.md +433 -0
  4. package/dist/OAuthInternalContext.d.ts +45 -0
  5. package/dist/OAuthInternalContext.js +2 -0
  6. package/dist/OAuthPlugin.d.ts +70 -0
  7. package/dist/OAuthPlugin.js +220 -0
  8. package/dist/OAuthPluginContext.d.ts +49 -0
  9. package/dist/OAuthPluginContext.js +2 -0
  10. package/dist/OAuthPluginOptions.d.ts +111 -0
  11. package/dist/OAuthPluginOptions.js +2 -0
  12. package/dist/index.d.ts +48 -0
  13. package/dist/index.js +66 -0
  14. package/dist/providers/GitHubProvider.d.ts +32 -0
  15. package/dist/providers/GitHubProvider.js +82 -0
  16. package/dist/providers/GoogleProvider.d.ts +32 -0
  17. package/dist/providers/GoogleProvider.js +83 -0
  18. package/dist/providers/OAuthProvider.d.ts +69 -0
  19. package/dist/providers/OAuthProvider.js +2 -0
  20. package/dist/providers/OAuthProviderBase.d.ts +32 -0
  21. package/dist/providers/OAuthProviderBase.js +86 -0
  22. package/dist/providers/ProviderRegistry.d.ts +14 -0
  23. package/dist/providers/ProviderRegistry.js +24 -0
  24. package/dist/repos/OAuthConnectionRepo.d.ts +30 -0
  25. package/dist/repos/OAuthConnectionRepo.js +38 -0
  26. package/dist/repos/OAuthSessionRepo.d.ts +22 -0
  27. package/dist/repos/OAuthSessionRepo.js +28 -0
  28. package/dist/schemas/OAuthConnection.d.ts +12 -0
  29. package/dist/schemas/OAuthConnection.js +2 -0
  30. package/dist/schemas/OAuthSession.d.ts +9 -0
  31. package/dist/schemas/OAuthSession.js +2 -0
  32. package/dist/utils/encryption-utils.d.ts +34 -0
  33. package/dist/utils/encryption-utils.js +134 -0
  34. package/dist/utils/error-utils.d.ts +68 -0
  35. package/dist/utils/error-utils.js +120 -0
  36. package/dist/utils/state-utils.d.ts +36 -0
  37. package/dist/utils/state-utils.js +72 -0
  38. package/examples/api-client-auth.ts +550 -0
  39. package/examples/basic-auth.ts +288 -0
  40. package/examples/multi-provider.ts +409 -0
  41. package/examples/token-storage.ts +490 -0
  42. package/package.json +38 -0
  43. package/spec/OAuthHandlers.spec.ts +146 -0
  44. package/spec/OAuthPluginSpec.ts +31 -0
  45. package/spec/ProvidersSpec.ts +178 -0
  46. package/spec/README.md +365 -0
  47. package/spec/helpers/mockJwtAuthPlugin.ts +104 -0
  48. package/spec/helpers/mockOAuthProviders.ts +189 -0
  49. package/spec/helpers/reporter.ts +41 -0
  50. package/spec/helpers/testDatabase.ts +107 -0
  51. package/spec/helpers/testHelpers.ts +192 -0
  52. package/spec/integration-critical.spec.ts +857 -0
  53. package/spec/integration.spec.ts +301 -0
  54. package/spec/repositories.spec.ts +181 -0
  55. package/spec/support/jasmine.json +7 -0
  56. package/spec/utils/security.spec.ts +243 -0
  57. package/src/OAuthInternalContext.ts +46 -0
  58. package/src/OAuthPlugin.ts +251 -0
  59. package/src/OAuthPluginContext.ts +53 -0
  60. package/src/OAuthPluginOptions.ts +122 -0
  61. package/src/handlers/CallbackOAuth.ts +238 -0
  62. package/src/handlers/InitiateOAuth.ts +99 -0
  63. package/src/index.ts +62 -0
  64. package/src/providers/GitHubProvider.ts +90 -0
  65. package/src/providers/GoogleProvider.ts +91 -0
  66. package/src/providers/OAuthProvider.ts +77 -0
  67. package/src/providers/OAuthProviderBase.ts +98 -0
  68. package/src/providers/ProviderRegistry.ts +27 -0
  69. package/src/repos/OAuthConnectionRepo.ts +41 -0
  70. package/src/repos/OAuthSessionRepo.ts +30 -0
  71. package/src/repos/TTL_INDEX_NOTE.md +28 -0
  72. package/src/schemas/CallbackRequest.ts +64 -0
  73. package/src/schemas/InitiateRequest.ts +10 -0
  74. package/src/schemas/OAuthConnection.ts +12 -0
  75. package/src/schemas/OAuthSession.ts +9 -0
  76. package/src/utils/encryption-utils.ts +148 -0
  77. package/src/utils/error-utils.ts +139 -0
  78. package/src/utils/state-utils.ts +70 -0
  79. package/src/utils/token-response-utils.ts +49 -0
  80. package/src/utils/validation-utils.ts +120 -0
  81. package/tsconfig.dist.json +4 -0
  82. package/tsconfig.json +24 -0
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.oauthPlugin = void 0;
7
+ const flink_1 = require("@flink-app/flink");
8
+ const OAuthSessionRepo_1 = __importDefault(require("./repos/OAuthSessionRepo"));
9
+ const OAuthConnectionRepo_1 = __importDefault(require("./repos/OAuthConnectionRepo"));
10
+ const encryption_utils_1 = require("./utils/encryption-utils");
11
+ /**
12
+ * OAuth Plugin Factory Function
13
+ *
14
+ * Creates a Flink plugin for OAuth 2.0 authentication with GitHub and Google providers.
15
+ * Integrates with JWT Auth Plugin for token generation.
16
+ *
17
+ * @param options - OAuth plugin configuration options
18
+ * @returns FlinkPlugin instance
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { jwtAuthPlugin } from '@flink-app/jwt-auth-plugin';
23
+ * import { oauthPlugin } from '@flink-app/oauth-plugin';
24
+ *
25
+ * const app = new FlinkApp({
26
+ * plugins: [
27
+ * // JWT Auth Plugin must be registered first
28
+ * jwtAuthPlugin({
29
+ * secret: process.env.JWT_SECRET!,
30
+ * getUser: async (tokenData) => {
31
+ * return ctx.repos.userRepo.getById(tokenData.userId);
32
+ * },
33
+ * rolePermissions: {
34
+ * user: ['read:own'],
35
+ * admin: ['read:all', 'write:all']
36
+ * }
37
+ * }),
38
+ *
39
+ * // OAuth Plugin uses JWT Auth Plugin in callbacks
40
+ * oauthPlugin({
41
+ * providers: {
42
+ * github: {
43
+ * clientId: process.env.GITHUB_CLIENT_ID!,
44
+ * clientSecret: process.env.GITHUB_CLIENT_SECRET!,
45
+ * callbackUrl: 'https://myapp.com/oauth/github/callback'
46
+ * }
47
+ * },
48
+ * onAuthSuccess: async ({ profile, provider }, ctx) => {
49
+ * // Find or create user
50
+ * let user = await ctx.repos.userRepo.getOne({ email: profile.email });
51
+ *
52
+ * if (!user) {
53
+ * user = await ctx.repos.userRepo.create({
54
+ * email: profile.email,
55
+ * name: profile.name,
56
+ * oauthProvider: provider,
57
+ * oauthProviderId: profile.id
58
+ * });
59
+ * }
60
+ *
61
+ * // Generate JWT token using JWT Auth Plugin
62
+ * const token = await ctx.plugins.jwtAuth.createToken(
63
+ * { userId: user._id, email: user.email },
64
+ * ['user']
65
+ * );
66
+ *
67
+ * return {
68
+ * user,
69
+ * token,
70
+ * redirectUrl: 'https://myapp.com/dashboard'
71
+ * };
72
+ * }
73
+ * })
74
+ * ]
75
+ * });
76
+ * ```
77
+ */
78
+ function oauthPlugin(options) {
79
+ // Validation
80
+ if (!options.providers || Object.keys(options.providers).length === 0) {
81
+ throw new Error("OAuth Plugin: At least one provider must be configured");
82
+ }
83
+ // Validate provider configurations
84
+ const configuredProviders = Object.keys(options.providers);
85
+ for (const providerName of configuredProviders) {
86
+ const providerConfig = options.providers[providerName];
87
+ if (!providerConfig)
88
+ continue;
89
+ if (!providerConfig.clientId) {
90
+ throw new Error(`OAuth Plugin: ${providerName} clientId is required`);
91
+ }
92
+ if (!providerConfig.clientSecret) {
93
+ throw new Error(`OAuth Plugin: ${providerName} clientSecret is required`);
94
+ }
95
+ if (!providerConfig.callbackUrl) {
96
+ throw new Error(`OAuth Plugin: ${providerName} callbackUrl is required`);
97
+ }
98
+ }
99
+ if (!options.onAuthSuccess) {
100
+ throw new Error("OAuth Plugin: onAuthSuccess callback is required");
101
+ }
102
+ // Determine encryption key
103
+ let encryptionKey = options.encryptionKey;
104
+ if (!encryptionKey) {
105
+ // Derive from first configured provider's client secret
106
+ const firstProvider = configuredProviders[0];
107
+ const firstProviderConfig = options.providers[firstProvider];
108
+ if (firstProviderConfig) {
109
+ encryptionKey = firstProviderConfig.clientSecret;
110
+ flink_1.log.warn("OAuth Plugin: No encryption key provided, deriving from client secret. " + "For better security, provide a dedicated encryptionKey in options.");
111
+ }
112
+ }
113
+ if (!encryptionKey || encryptionKey.length < 32) {
114
+ throw new Error("OAuth Plugin: Encryption key must be at least 32 characters");
115
+ }
116
+ // Validate encryption key
117
+ (0, encryption_utils_1.validateEncryptionSecret)(encryptionKey);
118
+ let flinkApp;
119
+ let sessionRepo;
120
+ let connectionRepo;
121
+ /**
122
+ * Plugin initialization
123
+ */
124
+ async function init(app, db) {
125
+ flink_1.log.info("Initializing OAuth Plugin...");
126
+ flinkApp = app;
127
+ try {
128
+ if (!db) {
129
+ throw new Error("OAuth Plugin: Database connection is required");
130
+ }
131
+ // Initialize repositories
132
+ const sessionsCollectionName = options.sessionsCollectionName || "oauth_sessions";
133
+ const connectionsCollectionName = options.connectionsCollectionName || "oauth_connections";
134
+ sessionRepo = new OAuthSessionRepo_1.default(sessionsCollectionName, db);
135
+ connectionRepo = new OAuthConnectionRepo_1.default(connectionsCollectionName, db);
136
+ flinkApp.addRepo("oauthSessionRepo", sessionRepo);
137
+ flinkApp.addRepo("oauthConnectionRepo", connectionRepo);
138
+ // Create TTL index for session expiration
139
+ const sessionTTL = options.sessionTTL || 600; // Default 10 minutes
140
+ await db.collection(sessionsCollectionName).createIndex({ createdAt: 1 }, { expireAfterSeconds: sessionTTL });
141
+ flink_1.log.info(`OAuth Plugin: Created TTL index on ${sessionsCollectionName} with ${sessionTTL}s expiration`);
142
+ // Register handlers for each configured provider
143
+ // Note: Handlers will be registered dynamically
144
+ // This requires handlers to be imported, but we'll handle that in the handler files
145
+ // For now, we'll skip handler registration and implement it when handlers are ready
146
+ flink_1.log.info(`OAuth Plugin initialized with providers: ${configuredProviders.join(", ")}`);
147
+ }
148
+ catch (error) {
149
+ flink_1.log.error("Failed to initialize OAuth Plugin:", error);
150
+ throw error;
151
+ }
152
+ }
153
+ /**
154
+ * Get OAuth connection for a user
155
+ */
156
+ async function getConnection(userId, provider) {
157
+ if (!connectionRepo) {
158
+ throw new Error("OAuth Plugin: Plugin not initialized");
159
+ }
160
+ const connection = await connectionRepo.findByUserAndProvider(userId, provider);
161
+ if (!connection) {
162
+ return null;
163
+ }
164
+ // Decrypt tokens before returning
165
+ if (connection.accessToken && encryptionKey) {
166
+ connection.accessToken = (0, encryption_utils_1.decryptToken)(connection.accessToken, encryptionKey);
167
+ }
168
+ if (connection.refreshToken && encryptionKey) {
169
+ connection.refreshToken = (0, encryption_utils_1.decryptToken)(connection.refreshToken, encryptionKey);
170
+ }
171
+ return connection;
172
+ }
173
+ /**
174
+ * Get all OAuth connections for a user
175
+ */
176
+ async function getConnections(userId) {
177
+ if (!connectionRepo) {
178
+ throw new Error("OAuth Plugin: Plugin not initialized");
179
+ }
180
+ const connections = await connectionRepo.findByUserId(userId);
181
+ // Decrypt tokens in each connection
182
+ return connections.map((connection) => {
183
+ if (connection.accessToken && encryptionKey) {
184
+ connection.accessToken = (0, encryption_utils_1.decryptToken)(connection.accessToken, encryptionKey);
185
+ }
186
+ if (connection.refreshToken && encryptionKey) {
187
+ connection.refreshToken = (0, encryption_utils_1.decryptToken)(connection.refreshToken, encryptionKey);
188
+ }
189
+ return connection;
190
+ });
191
+ }
192
+ /**
193
+ * Delete OAuth connection for a user
194
+ */
195
+ async function deleteConnection(userId, provider) {
196
+ if (!connectionRepo) {
197
+ throw new Error("OAuth Plugin: Plugin not initialized");
198
+ }
199
+ await connectionRepo.deleteByUserAndProvider(userId, provider);
200
+ flink_1.log.info(`OAuth Plugin: Deleted ${provider} connection for user ${userId}`);
201
+ }
202
+ /**
203
+ * Plugin context exposed via ctx.plugins.oauth
204
+ */
205
+ const pluginCtx = {
206
+ getConnection,
207
+ getConnections,
208
+ deleteConnection,
209
+ options: Object.freeze({ ...options }),
210
+ };
211
+ return {
212
+ id: "oauth",
213
+ db: {
214
+ useHostDb: true,
215
+ },
216
+ ctx: pluginCtx,
217
+ init,
218
+ };
219
+ }
220
+ exports.oauthPlugin = oauthPlugin;
@@ -0,0 +1,49 @@
1
+ import OAuthConnection from "./schemas/OAuthConnection";
2
+ import { OAuthPluginOptions } from "./OAuthPluginOptions";
3
+ /**
4
+ * OAuth Plugin context API exposed via ctx.plugins.oauth
5
+ *
6
+ * Provides methods for managing OAuth connections (stored tokens) for users.
7
+ * Only applicable when storeTokens option is enabled.
8
+ */
9
+ export interface OAuthPluginContext {
10
+ oauth: {
11
+ /**
12
+ * Get stored OAuth connection for a specific user and provider
13
+ *
14
+ * Tokens are automatically decrypted before being returned.
15
+ * Returns null if no connection exists.
16
+ *
17
+ * @param userId - The user's unique identifier
18
+ * @param provider - The OAuth provider (github or google)
19
+ * @returns The OAuth connection with decrypted tokens, or null
20
+ */
21
+ getConnection: (userId: string, provider: "github" | "google") => Promise<OAuthConnection | null>;
22
+ /**
23
+ * Get all stored OAuth connections for a specific user
24
+ *
25
+ * Tokens are automatically decrypted before being returned.
26
+ * Returns empty array if no connections exist.
27
+ *
28
+ * @param userId - The user's unique identifier
29
+ * @returns Array of OAuth connections with decrypted tokens
30
+ */
31
+ getConnections: (userId: string) => Promise<OAuthConnection[]>;
32
+ /**
33
+ * Delete OAuth connection for a specific user and provider
34
+ *
35
+ * Used when unlinking an OAuth provider from a user account.
36
+ * Also deletes the encrypted tokens from storage.
37
+ *
38
+ * @param userId - The user's unique identifier
39
+ * @param provider - The OAuth provider (github or google)
40
+ * @returns void
41
+ */
42
+ deleteConnection: (userId: string, provider: "github" | "google") => Promise<void>;
43
+ /**
44
+ * Plugin configuration (read-only)
45
+ * Provides access to plugin options for custom logic
46
+ */
47
+ options: Readonly<OAuthPluginOptions>;
48
+ };
49
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,111 @@
1
+ import { OAuthProfile, OAuthTokens } from "./providers/OAuthProvider";
2
+ /**
3
+ * OAuth error information
4
+ */
5
+ export interface OAuthError {
6
+ code: string;
7
+ message: string;
8
+ details?: any;
9
+ }
10
+ /**
11
+ * Response from onAuthSuccess callback
12
+ * Must include JWT token generated by the application
13
+ */
14
+ export interface AuthSuccessCallbackResponse {
15
+ user: any;
16
+ token: string;
17
+ redirectUrl?: string;
18
+ }
19
+ /**
20
+ * Response from onAuthError callback
21
+ */
22
+ export interface AuthErrorCallbackResponse {
23
+ redirectUrl?: string;
24
+ }
25
+ /**
26
+ * Configuration options for OAuth Plugin with JWT integration
27
+ *
28
+ * The plugin depends on @flink-app/jwt-auth-plugin being installed and configured.
29
+ * The onAuthSuccess callback receives the Flink context as a second parameter,
30
+ * allowing the application to generate JWT tokens using ctx.plugins.jwtAuth.createToken().
31
+ */
32
+ export interface OAuthPluginOptions {
33
+ /**
34
+ * OAuth provider configurations
35
+ * At least one provider must be configured
36
+ */
37
+ providers: {
38
+ github?: {
39
+ clientId: string;
40
+ clientSecret: string;
41
+ callbackUrl: string;
42
+ scope?: string[];
43
+ };
44
+ google?: {
45
+ clientId: string;
46
+ clientSecret: string;
47
+ callbackUrl: string;
48
+ scope?: string[];
49
+ };
50
+ };
51
+ /**
52
+ * Whether to store OAuth tokens for future API access
53
+ * If false, tokens are discarded after authentication
54
+ * Default: false
55
+ */
56
+ storeTokens?: boolean;
57
+ /**
58
+ * Callback invoked after successful OAuth authentication
59
+ *
60
+ * Application responsibilities:
61
+ * 1. Find or create user based on OAuth profile
62
+ * 2. Link OAuth provider to user account
63
+ * 3. Generate JWT token using ctx.plugins.jwtAuth.createToken(payload, roles)
64
+ * 4. Return user object, JWT token, and optional redirect URL
65
+ *
66
+ * @param params - OAuth profile, provider name, and tokens (if storeTokens enabled)
67
+ * @param ctx - Flink context with access to repos and plugins (including jwtAuth)
68
+ * @returns User object, JWT token, and optional redirect URL
69
+ */
70
+ onAuthSuccess: (params: {
71
+ profile: OAuthProfile;
72
+ provider: "github" | "google";
73
+ tokens?: OAuthTokens;
74
+ }, ctx: any) => Promise<AuthSuccessCallbackResponse>;
75
+ /**
76
+ * Callback invoked on OAuth errors
77
+ *
78
+ * Application responsibilities:
79
+ * - Log error for debugging
80
+ * - Optionally provide redirect URL for error page
81
+ *
82
+ * @param params - Error information and provider name
83
+ * @returns Optional redirect URL for error page
84
+ */
85
+ onAuthError?: (params: {
86
+ error: OAuthError;
87
+ provider: "github" | "google";
88
+ }) => Promise<AuthErrorCallbackResponse>;
89
+ /**
90
+ * Custom collection name for OAuth sessions
91
+ * Default: 'oauth_sessions'
92
+ */
93
+ sessionsCollectionName?: string;
94
+ /**
95
+ * Custom collection name for OAuth connections (if storeTokens enabled)
96
+ * Default: 'oauth_connections'
97
+ */
98
+ connectionsCollectionName?: string;
99
+ /**
100
+ * Session TTL in seconds
101
+ * Sessions are automatically cleaned up after this duration
102
+ * Default: 600 (10 minutes)
103
+ */
104
+ sessionTTL?: number;
105
+ /**
106
+ * Encryption key for encrypting stored OAuth tokens
107
+ * If not provided, will be derived from first configured provider's client secret
108
+ * Recommended: Use a dedicated encryption key from environment variables
109
+ */
110
+ encryptionKey?: string;
111
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @flink-app/oauth-plugin
3
+ *
4
+ * OAuth 2.0 plugin for Flink supporting GitHub and Google providers
5
+ * with JWT token integration and flexible user management.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { jwtAuthPlugin } from '@flink-app/jwt-auth-plugin';
10
+ * import { oauthPlugin } from '@flink-app/oauth-plugin';
11
+ *
12
+ * const app = new FlinkApp({
13
+ * plugins: [
14
+ * jwtAuthPlugin({ ... }),
15
+ * oauthPlugin({
16
+ * providers: {
17
+ * github: {
18
+ * clientId: process.env.GITHUB_CLIENT_ID!,
19
+ * clientSecret: process.env.GITHUB_CLIENT_SECRET!,
20
+ * callbackUrl: 'https://myapp.com/oauth/github/callback'
21
+ * }
22
+ * },
23
+ * onAuthSuccess: async ({ profile }, ctx) => {
24
+ * const user = await ctx.repos.userRepo.getOne({ email: profile.email });
25
+ * const token = await ctx.plugins.jwtAuth.createToken({ userId: user._id }, ['user']);
26
+ * return { user, token };
27
+ * }
28
+ * })
29
+ * ]
30
+ * });
31
+ * ```
32
+ */
33
+ export { oauthPlugin } from "./OAuthPlugin";
34
+ export type { OAuthPluginOptions, OAuthError, AuthSuccessCallbackResponse, AuthErrorCallbackResponse } from "./OAuthPluginOptions";
35
+ export type { OAuthPluginContext } from "./OAuthPluginContext";
36
+ export type { OAuthInternalContext } from "./OAuthInternalContext";
37
+ export type { OAuthProvider, OAuthTokens, OAuthProfile, AuthorizationUrlParams, TokenExchangeParams, ProviderConfig } from "./providers/OAuthProvider";
38
+ export { GitHubProvider } from "./providers/GitHubProvider";
39
+ export { GoogleProvider } from "./providers/GoogleProvider";
40
+ export { OAuthProviderBase } from "./providers/OAuthProviderBase";
41
+ export { getProvider, type ProviderName } from "./providers/ProviderRegistry";
42
+ export type { default as OAuthSession } from "./schemas/OAuthSession";
43
+ export type { default as OAuthConnection } from "./schemas/OAuthConnection";
44
+ export { default as OAuthSessionRepo } from "./repos/OAuthSessionRepo";
45
+ export { default as OAuthConnectionRepo } from "./repos/OAuthConnectionRepo";
46
+ export { encryptToken, decryptToken, validateEncryptionSecret } from "./utils/encryption-utils";
47
+ export { generateState, validateState } from "./utils/state-utils";
48
+ export { createOAuthError, handleProviderError } from "./utils/error-utils";
package/dist/index.js ADDED
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * @flink-app/oauth-plugin
4
+ *
5
+ * OAuth 2.0 plugin for Flink supporting GitHub and Google providers
6
+ * with JWT token integration and flexible user management.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { jwtAuthPlugin } from '@flink-app/jwt-auth-plugin';
11
+ * import { oauthPlugin } from '@flink-app/oauth-plugin';
12
+ *
13
+ * const app = new FlinkApp({
14
+ * plugins: [
15
+ * jwtAuthPlugin({ ... }),
16
+ * oauthPlugin({
17
+ * providers: {
18
+ * github: {
19
+ * clientId: process.env.GITHUB_CLIENT_ID!,
20
+ * clientSecret: process.env.GITHUB_CLIENT_SECRET!,
21
+ * callbackUrl: 'https://myapp.com/oauth/github/callback'
22
+ * }
23
+ * },
24
+ * onAuthSuccess: async ({ profile }, ctx) => {
25
+ * const user = await ctx.repos.userRepo.getOne({ email: profile.email });
26
+ * const token = await ctx.plugins.jwtAuth.createToken({ userId: user._id }, ['user']);
27
+ * return { user, token };
28
+ * }
29
+ * })
30
+ * ]
31
+ * });
32
+ * ```
33
+ */
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.handleProviderError = exports.createOAuthError = exports.validateState = exports.generateState = exports.validateEncryptionSecret = exports.decryptToken = exports.encryptToken = exports.OAuthConnectionRepo = exports.OAuthSessionRepo = exports.getProvider = exports.OAuthProviderBase = exports.GoogleProvider = exports.GitHubProvider = exports.oauthPlugin = void 0;
39
+ // Plugin factory function
40
+ var OAuthPlugin_1 = require("./OAuthPlugin");
41
+ Object.defineProperty(exports, "oauthPlugin", { enumerable: true, get: function () { return OAuthPlugin_1.oauthPlugin; } });
42
+ // Provider implementations
43
+ var GitHubProvider_1 = require("./providers/GitHubProvider");
44
+ Object.defineProperty(exports, "GitHubProvider", { enumerable: true, get: function () { return GitHubProvider_1.GitHubProvider; } });
45
+ var GoogleProvider_1 = require("./providers/GoogleProvider");
46
+ Object.defineProperty(exports, "GoogleProvider", { enumerable: true, get: function () { return GoogleProvider_1.GoogleProvider; } });
47
+ var OAuthProviderBase_1 = require("./providers/OAuthProviderBase");
48
+ Object.defineProperty(exports, "OAuthProviderBase", { enumerable: true, get: function () { return OAuthProviderBase_1.OAuthProviderBase; } });
49
+ var ProviderRegistry_1 = require("./providers/ProviderRegistry");
50
+ Object.defineProperty(exports, "getProvider", { enumerable: true, get: function () { return ProviderRegistry_1.getProvider; } });
51
+ // Repositories
52
+ var OAuthSessionRepo_1 = require("./repos/OAuthSessionRepo");
53
+ Object.defineProperty(exports, "OAuthSessionRepo", { enumerable: true, get: function () { return __importDefault(OAuthSessionRepo_1).default; } });
54
+ var OAuthConnectionRepo_1 = require("./repos/OAuthConnectionRepo");
55
+ Object.defineProperty(exports, "OAuthConnectionRepo", { enumerable: true, get: function () { return __importDefault(OAuthConnectionRepo_1).default; } });
56
+ // Utilities (for advanced use cases)
57
+ var encryption_utils_1 = require("./utils/encryption-utils");
58
+ Object.defineProperty(exports, "encryptToken", { enumerable: true, get: function () { return encryption_utils_1.encryptToken; } });
59
+ Object.defineProperty(exports, "decryptToken", { enumerable: true, get: function () { return encryption_utils_1.decryptToken; } });
60
+ Object.defineProperty(exports, "validateEncryptionSecret", { enumerable: true, get: function () { return encryption_utils_1.validateEncryptionSecret; } });
61
+ var state_utils_1 = require("./utils/state-utils");
62
+ Object.defineProperty(exports, "generateState", { enumerable: true, get: function () { return state_utils_1.generateState; } });
63
+ Object.defineProperty(exports, "validateState", { enumerable: true, get: function () { return state_utils_1.validateState; } });
64
+ var error_utils_1 = require("./utils/error-utils");
65
+ Object.defineProperty(exports, "createOAuthError", { enumerable: true, get: function () { return error_utils_1.createOAuthError; } });
66
+ Object.defineProperty(exports, "handleProviderError", { enumerable: true, get: function () { return error_utils_1.handleProviderError; } });
@@ -0,0 +1,32 @@
1
+ import { OAuthProvider, OAuthTokens, OAuthProfile, AuthorizationUrlParams, TokenExchangeParams, ProviderConfig } from "./OAuthProvider";
2
+ import { OAuthProviderBase } from "./OAuthProviderBase";
3
+ /**
4
+ * GitHub OAuth 2.0 provider implementation
5
+ *
6
+ * Implements OAuth flow for GitHub:
7
+ * - Authorization URL: https://github.com/login/oauth/authorize
8
+ * - Token exchange: POST https://github.com/login/oauth/access_token
9
+ * - User profile: GET https://api.github.com/user
10
+ *
11
+ * Default scopes: ['user:email']
12
+ */
13
+ export declare class GitHubProvider extends OAuthProviderBase implements OAuthProvider {
14
+ readonly name = "github";
15
+ private static readonly AUTHORIZATION_URL;
16
+ private static readonly TOKEN_URL;
17
+ private static readonly USER_PROFILE_URL;
18
+ private static readonly DEFAULT_SCOPES;
19
+ constructor(config: ProviderConfig);
20
+ /**
21
+ * Generate GitHub authorization URL
22
+ */
23
+ getAuthorizationUrl(params: AuthorizationUrlParams): string;
24
+ /**
25
+ * Exchange authorization code for access token
26
+ */
27
+ exchangeCodeForToken(params: TokenExchangeParams): Promise<OAuthTokens>;
28
+ /**
29
+ * Fetch user profile from GitHub
30
+ */
31
+ getUserProfile(accessToken: string): Promise<OAuthProfile>;
32
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitHubProvider = void 0;
4
+ const OAuthProviderBase_1 = require("./OAuthProviderBase");
5
+ /**
6
+ * GitHub OAuth 2.0 provider implementation
7
+ *
8
+ * Implements OAuth flow for GitHub:
9
+ * - Authorization URL: https://github.com/login/oauth/authorize
10
+ * - Token exchange: POST https://github.com/login/oauth/access_token
11
+ * - User profile: GET https://api.github.com/user
12
+ *
13
+ * Default scopes: ['user:email']
14
+ */
15
+ class GitHubProvider extends OAuthProviderBase_1.OAuthProviderBase {
16
+ constructor(config) {
17
+ super(config);
18
+ this.name = "github";
19
+ }
20
+ /**
21
+ * Generate GitHub authorization URL
22
+ */
23
+ getAuthorizationUrl(params) {
24
+ const scopes = params.scope.length > 0 ? params.scope : GitHubProvider.DEFAULT_SCOPES;
25
+ const queryParams = {
26
+ client_id: this.config.clientId,
27
+ redirect_uri: params.redirectUri,
28
+ state: params.state,
29
+ scope: scopes.join(" "),
30
+ };
31
+ return `${GitHubProvider.AUTHORIZATION_URL}?${this.buildQueryString(queryParams)}`;
32
+ }
33
+ /**
34
+ * Exchange authorization code for access token
35
+ */
36
+ async exchangeCodeForToken(params) {
37
+ const body = this.buildQueryString({
38
+ client_id: this.config.clientId,
39
+ client_secret: this.config.clientSecret,
40
+ code: params.code,
41
+ redirect_uri: params.redirectUri,
42
+ });
43
+ const response = await this.makeHttpRequest(GitHubProvider.TOKEN_URL, {
44
+ method: "POST",
45
+ headers: {
46
+ "Content-Type": "application/x-www-form-urlencoded",
47
+ Accept: "application/json",
48
+ },
49
+ body,
50
+ });
51
+ return {
52
+ accessToken: response.access_token,
53
+ refreshToken: response.refresh_token,
54
+ scope: response.scope,
55
+ expiresIn: response.expires_in,
56
+ };
57
+ }
58
+ /**
59
+ * Fetch user profile from GitHub
60
+ */
61
+ async getUserProfile(accessToken) {
62
+ const response = await this.makeHttpRequest(GitHubProvider.USER_PROFILE_URL, {
63
+ method: "GET",
64
+ headers: {
65
+ Authorization: `Bearer ${accessToken}`,
66
+ Accept: "application/json",
67
+ },
68
+ });
69
+ return {
70
+ id: String(response.id),
71
+ email: response.email,
72
+ name: response.name,
73
+ avatarUrl: response.avatar_url,
74
+ raw: response,
75
+ };
76
+ }
77
+ }
78
+ exports.GitHubProvider = GitHubProvider;
79
+ GitHubProvider.AUTHORIZATION_URL = "https://github.com/login/oauth/authorize";
80
+ GitHubProvider.TOKEN_URL = "https://github.com/login/oauth/access_token";
81
+ GitHubProvider.USER_PROFILE_URL = "https://api.github.com/user";
82
+ GitHubProvider.DEFAULT_SCOPES = ["user:email"];
@@ -0,0 +1,32 @@
1
+ import { OAuthProvider, OAuthTokens, OAuthProfile, AuthorizationUrlParams, TokenExchangeParams, ProviderConfig } from "./OAuthProvider";
2
+ import { OAuthProviderBase } from "./OAuthProviderBase";
3
+ /**
4
+ * Google OAuth 2.0 provider implementation
5
+ *
6
+ * Implements OAuth flow for Google:
7
+ * - Authorization URL: https://accounts.google.com/o/oauth2/v2/auth
8
+ * - Token exchange: POST https://oauth2.googleapis.com/token
9
+ * - User profile: GET https://www.googleapis.com/oauth2/v2/userinfo
10
+ *
11
+ * Default scopes: ['openid', 'email', 'profile']
12
+ */
13
+ export declare class GoogleProvider extends OAuthProviderBase implements OAuthProvider {
14
+ readonly name = "google";
15
+ private static readonly AUTHORIZATION_URL;
16
+ private static readonly TOKEN_URL;
17
+ private static readonly USER_PROFILE_URL;
18
+ private static readonly DEFAULT_SCOPES;
19
+ constructor(config: ProviderConfig);
20
+ /**
21
+ * Generate Google authorization URL
22
+ */
23
+ getAuthorizationUrl(params: AuthorizationUrlParams): string;
24
+ /**
25
+ * Exchange authorization code for access token
26
+ */
27
+ exchangeCodeForToken(params: TokenExchangeParams): Promise<OAuthTokens>;
28
+ /**
29
+ * Fetch user profile from Google
30
+ */
31
+ getUserProfile(accessToken: string): Promise<OAuthProfile>;
32
+ }