binoauth 0.0.11 → 0.0.13

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 (111) hide show
  1. package/README.md +359 -165
  2. package/dist/core/src/admin/client.d.ts +203 -0
  3. package/dist/core/src/admin/client.d.ts.map +1 -0
  4. package/dist/core/src/admin/client.js +391 -0
  5. package/dist/core/src/admin/client.js.map +1 -0
  6. package/dist/core/src/admin/index.d.ts +6 -0
  7. package/dist/core/src/admin/index.d.ts.map +1 -0
  8. package/dist/core/src/admin/index.js +5 -0
  9. package/dist/core/src/admin/index.js.map +1 -0
  10. package/dist/core/src/admin/types.d.ts +412 -0
  11. package/dist/core/src/admin/types.d.ts.map +1 -0
  12. package/dist/core/src/admin/types.js +5 -0
  13. package/dist/core/src/admin/types.js.map +1 -0
  14. package/dist/core/src/auth/client.d.ts +330 -0
  15. package/dist/core/src/auth/client.d.ts.map +1 -0
  16. package/dist/core/src/auth/client.js +408 -0
  17. package/dist/core/src/auth/client.js.map +1 -0
  18. package/dist/core/src/auth/error.d.ts +113 -0
  19. package/dist/core/src/auth/error.d.ts.map +1 -0
  20. package/dist/core/src/auth/error.js +257 -0
  21. package/dist/core/src/auth/error.js.map +1 -0
  22. package/dist/core/src/auth/flows/base-flow.d.ts +98 -0
  23. package/dist/core/src/auth/flows/base-flow.d.ts.map +1 -0
  24. package/dist/core/src/auth/flows/base-flow.js +182 -0
  25. package/dist/core/src/auth/flows/base-flow.js.map +1 -0
  26. package/dist/core/src/auth/flows/magic-link.d.ts +175 -0
  27. package/dist/core/src/auth/flows/magic-link.d.ts.map +1 -0
  28. package/dist/core/src/auth/flows/magic-link.js +228 -0
  29. package/dist/core/src/auth/flows/magic-link.js.map +1 -0
  30. package/dist/core/src/auth/flows/mfa.d.ts +81 -0
  31. package/dist/core/src/auth/flows/mfa.d.ts.map +1 -0
  32. package/dist/core/src/auth/flows/mfa.js +103 -0
  33. package/dist/core/src/auth/flows/mfa.js.map +1 -0
  34. package/dist/core/src/auth/flows/otp.d.ts +172 -0
  35. package/dist/core/src/auth/flows/otp.d.ts.map +1 -0
  36. package/dist/core/src/auth/flows/otp.js +222 -0
  37. package/dist/core/src/auth/flows/otp.js.map +1 -0
  38. package/dist/core/src/auth/flows/password.d.ts +242 -0
  39. package/dist/core/src/auth/flows/password.d.ts.map +1 -0
  40. package/dist/core/src/auth/flows/password.js +344 -0
  41. package/dist/core/src/auth/flows/password.js.map +1 -0
  42. package/dist/core/src/auth/flows/social.d.ts +209 -0
  43. package/dist/core/src/auth/flows/social.d.ts.map +1 -0
  44. package/dist/core/src/auth/flows/social.js +284 -0
  45. package/dist/core/src/auth/flows/social.js.map +1 -0
  46. package/dist/core/src/auth/index.d.ts +19 -0
  47. package/dist/core/src/auth/index.d.ts.map +1 -0
  48. package/dist/core/src/auth/index.js +32 -0
  49. package/dist/core/src/auth/index.js.map +1 -0
  50. package/dist/core/src/auth/types.d.ts +151 -0
  51. package/dist/core/src/auth/types.d.ts.map +1 -0
  52. package/dist/core/src/auth/types.js +7 -0
  53. package/dist/core/src/auth/types.js.map +1 -0
  54. package/dist/core/src/index.d.ts +53 -49
  55. package/dist/core/src/index.d.ts.map +1 -1
  56. package/dist/core/src/index.js +61 -343
  57. package/dist/core/src/index.js.map +1 -1
  58. package/dist/core/src/oauth/client.d.ts +322 -0
  59. package/dist/core/src/oauth/client.d.ts.map +1 -0
  60. package/dist/core/src/oauth/client.js +491 -0
  61. package/dist/core/src/oauth/client.js.map +1 -0
  62. package/dist/core/src/oauth/error.d.ts +18 -0
  63. package/dist/core/src/oauth/error.d.ts.map +1 -0
  64. package/dist/core/src/oauth/error.js +24 -0
  65. package/dist/core/src/oauth/error.js.map +1 -0
  66. package/dist/core/src/oauth/flows/authorization-code.d.ts +122 -0
  67. package/dist/core/src/oauth/flows/authorization-code.d.ts.map +1 -0
  68. package/dist/core/src/oauth/flows/authorization-code.js +278 -0
  69. package/dist/core/src/oauth/flows/authorization-code.js.map +1 -0
  70. package/dist/core/src/oauth/flows/base-flow.d.ts +17 -0
  71. package/dist/core/src/oauth/flows/base-flow.d.ts.map +1 -0
  72. package/dist/core/src/oauth/flows/base-flow.js +107 -0
  73. package/dist/core/src/oauth/flows/base-flow.js.map +1 -0
  74. package/dist/core/src/oauth/flows/client-credentials.d.ts +72 -0
  75. package/dist/core/src/oauth/flows/client-credentials.d.ts.map +1 -0
  76. package/dist/core/src/oauth/flows/client-credentials.js +100 -0
  77. package/dist/core/src/oauth/flows/client-credentials.js.map +1 -0
  78. package/dist/core/src/oauth/flows/device-code.d.ts +108 -0
  79. package/dist/core/src/oauth/flows/device-code.d.ts.map +1 -0
  80. package/dist/core/src/oauth/flows/device-code.js +193 -0
  81. package/dist/core/src/oauth/flows/device-code.js.map +1 -0
  82. package/dist/core/src/oauth/flows/refresh-token.d.ts +59 -0
  83. package/dist/core/src/oauth/flows/refresh-token.d.ts.map +1 -0
  84. package/dist/core/src/oauth/flows/refresh-token.js +105 -0
  85. package/dist/core/src/oauth/flows/refresh-token.js.map +1 -0
  86. package/dist/core/src/oauth/index.d.ts +12 -0
  87. package/dist/core/src/oauth/index.d.ts.map +1 -0
  88. package/dist/core/src/oauth/index.js +11 -0
  89. package/dist/core/src/oauth/index.js.map +1 -0
  90. package/dist/core/src/oauth/storage/encryption.d.ts +12 -0
  91. package/dist/core/src/oauth/storage/encryption.d.ts.map +1 -0
  92. package/dist/core/src/oauth/storage/encryption.js +76 -0
  93. package/dist/core/src/oauth/storage/encryption.js.map +1 -0
  94. package/dist/core/src/oauth/storage/index.d.ts +201 -0
  95. package/dist/core/src/oauth/storage/index.d.ts.map +1 -0
  96. package/dist/core/src/oauth/storage/index.js +322 -0
  97. package/dist/core/src/oauth/storage/index.js.map +1 -0
  98. package/dist/core/src/oauth/storage/strategies.d.ts +34 -0
  99. package/dist/core/src/oauth/storage/strategies.d.ts.map +1 -0
  100. package/dist/core/src/oauth/storage/strategies.js +100 -0
  101. package/dist/core/src/oauth/storage/strategies.js.map +1 -0
  102. package/dist/core/src/oauth/types.d.ts +261 -0
  103. package/dist/core/src/oauth/types.d.ts.map +1 -0
  104. package/dist/core/src/oauth/types.js +39 -0
  105. package/dist/core/src/oauth/types.js.map +1 -0
  106. package/dist/core/src/oauth/utils.d.ts +56 -0
  107. package/dist/core/src/oauth/utils.d.ts.map +1 -0
  108. package/dist/core/src/oauth/utils.js +140 -0
  109. package/dist/core/src/oauth/utils.js.map +1 -0
  110. package/dist/tsconfig.tsbuildinfo +1 -1
  111. package/package.json +1 -1
@@ -0,0 +1,278 @@
1
+ import { TokenStorage } from "../storage";
2
+ import { generatePKCEPair, generateState, validateState } from "../utils";
3
+ import { AuthError, ErrorCode } from "../error";
4
+ import { BaseFlow } from "./base-flow";
5
+ /**
6
+ * OAuth 2.0 Authorization Code Flow with PKCE support
7
+ *
8
+ * This flow is designed for browser-based applications (SPAs) and mobile apps
9
+ * where the client cannot securely store a client secret. It uses PKCE
10
+ * (Proof Key for Code Exchange) for enhanced security.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const flow = new AuthorizationCodeFlow(config, storage, oauthApi);
15
+ *
16
+ * // Step 1: Get authorization URL
17
+ * const loginUrl = await flow.getLoginUrl();
18
+ * window.location.href = loginUrl; // Redirect user to BinoAuth
19
+ *
20
+ * // Step 2: Handle callback (after user returns from BinoAuth)
21
+ * const urlParams = new URLSearchParams(window.location.search);
22
+ * const code = urlParams.get('code');
23
+ * const state = urlParams.get('state');
24
+ *
25
+ * if (code && state) {
26
+ * await flow.handleCallback(code, state);
27
+ * // User is now authenticated, tokens are stored
28
+ * }
29
+ * ```
30
+ */
31
+ export class AuthorizationCodeFlow extends BaseFlow {
32
+ loginUrlGenerationInProgress = false;
33
+ constructor(config, storage, oauthApi) {
34
+ super(config, storage, oauthApi);
35
+ if (!config.authorizeEndpoint) {
36
+ throw new AuthError("Missing authorizeEndpoint in config", ErrorCode.InvalidConfig);
37
+ }
38
+ if (!config.tokenEndpoint) {
39
+ throw new AuthError("Missing tokenEndpoint in config", ErrorCode.InvalidConfig);
40
+ }
41
+ }
42
+ /**
43
+ * Generates the authorization URL for initiating the OAuth flow
44
+ *
45
+ * This method creates a secure authorization URL with PKCE parameters
46
+ * and stores the necessary state and verifier tokens for later validation.
47
+ *
48
+ * @returns Promise resolving to the authorization URL
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const loginUrl = await flow.getLoginUrl();
53
+ * // Returns: "https://auth.binoauth.com/api/v1/oauth/authorize?response_type=code&client_id=..."
54
+ *
55
+ * // Redirect user to the authorization server
56
+ * window.location.href = loginUrl;
57
+ * ```
58
+ *
59
+ * @throws {AuthError} When authorization endpoint is missing from config
60
+ */
61
+ async getLoginUrl() {
62
+ if (this.loginUrlGenerationInProgress) {
63
+ console.warn("OAuth login URL generation already in progress - potential race condition");
64
+ }
65
+ this.loginUrlGenerationInProgress = true;
66
+ try {
67
+ const { verifier, challenge } = await generatePKCEPair();
68
+ const state = generateState();
69
+ console.debug("OAuth login URL generation", {
70
+ generatedState: state,
71
+ stateLength: state.length,
72
+ generatedVerifier: verifier.substring(0, 10) + "...",
73
+ timestamp: new Date().toISOString()
74
+ });
75
+ await this.storage.setTokens({
76
+ state: {
77
+ value: state,
78
+ expiresAt: Date.now() + 1200000, // 20 minutes
79
+ },
80
+ verifier: {
81
+ value: verifier,
82
+ expiresAt: Date.now() + 1200000, // 20 minutes
83
+ },
84
+ });
85
+ const storedStateToken = await this.storage.getStateToken();
86
+ console.debug("OAuth state storage verification", {
87
+ generatedState: state,
88
+ storedState: storedStateToken?.value,
89
+ storageWorked: storedStateToken?.value === state,
90
+ storageExpiry: storedStateToken?.expiresAt
91
+ });
92
+ const params = new URLSearchParams({
93
+ response_type: "code",
94
+ client_id: this.config.clientId,
95
+ scope: this.config.scope,
96
+ state,
97
+ code_challenge: challenge,
98
+ code_challenge_method: "S256",
99
+ redirect_uri: this.config.redirectUri,
100
+ });
101
+ const finalUrl = `${this.config.authorizeEndpoint}?${params.toString()}`;
102
+ console.debug("OAuth login URL complete", {
103
+ finalUrl,
104
+ stateInUrl: params.get('state'),
105
+ stateMatches: params.get('state') === state,
106
+ urlLength: finalUrl.length
107
+ });
108
+ return finalUrl;
109
+ }
110
+ finally {
111
+ this.loginUrlGenerationInProgress = false;
112
+ }
113
+ }
114
+ /**
115
+ * Handles the OAuth callback and exchanges the authorization code for tokens
116
+ *
117
+ * This method validates the state parameter for CSRF protection, then exchanges
118
+ * the authorization code for access and refresh tokens using PKCE verification.
119
+ *
120
+ * @param code - The authorization code returned from the authorization server
121
+ * @param state - The state parameter returned from the authorization server
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * // Extract parameters from callback URL
126
+ * const urlParams = new URLSearchParams(window.location.search);
127
+ * const code = urlParams.get('code')!;
128
+ * const state = urlParams.get('state')!;
129
+ *
130
+ * // Exchange code for tokens
131
+ * await flow.handleCallback(code, state);
132
+ *
133
+ * // Tokens are now stored and user is authenticated
134
+ * const accessToken = await storage.getAccessToken();
135
+ * ```
136
+ *
137
+ * @throws {AuthError} When state validation fails (CSRF protection)
138
+ * @throws {AuthError} When state or verifier tokens are missing/expired
139
+ * @throws {AuthError} When token exchange fails
140
+ */
141
+ async handleCallback(code, state) {
142
+ this.checkRateLimit("callback", 10, 5 * 60 * 1000);
143
+ this.cleanupRateLimiter();
144
+ console.debug("OAuth callback initiated", {
145
+ codeLength: code?.length || 0,
146
+ stateLength: state?.length || 0,
147
+ timestamp: new Date().toISOString()
148
+ });
149
+ const storedStateToken = await this.storage.getStateToken();
150
+ const verifierToken = await this.storage.getVerifierToken();
151
+ console.debug("OAuth callback storage state", {
152
+ hasStoredState: !!storedStateToken,
153
+ hasVerifier: !!verifierToken,
154
+ storedStateExpired: storedStateToken ? this.storage.isTokenExpired(storedStateToken) : null,
155
+ receivedStateLength: state?.length || 0,
156
+ storedStateLength: storedStateToken?.value?.length || 0
157
+ });
158
+ if (!storedStateToken || !verifierToken) {
159
+ console.warn("OAuth callback failed: missing stored state or verifier", {
160
+ hasStoredState: !!storedStateToken,
161
+ hasVerifier: !!verifierToken
162
+ });
163
+ this.storage.clearTokens();
164
+ this.storage.clearStateAndVerifier();
165
+ throw new AuthError("Authentication session not found - please restart login process", ErrorCode.MissingVerifier);
166
+ }
167
+ console.debug("State validation comparison:", {
168
+ receivedState: state,
169
+ storedState: storedStateToken.value,
170
+ lengthsMatch: state.length === storedStateToken.value.length,
171
+ directEquals: state === storedStateToken.value
172
+ });
173
+ if (!validateState(state, storedStateToken.value)) {
174
+ console.error("State validation failed - detailed comparison:", {
175
+ receivedState: state,
176
+ storedState: storedStateToken.value,
177
+ receivedLength: state.length,
178
+ storedLength: storedStateToken.value.length,
179
+ directEquals: state === storedStateToken.value,
180
+ charDiffs: Array.from({ length: Math.min(state.length, storedStateToken.value.length, 10) }, (_, i) => state.charAt(i) !== storedStateToken.value.charAt(i) ?
181
+ `pos${i}: '${state.charAt(i)}' vs '${storedStateToken.value.charAt(i)}'` : null).filter(Boolean)
182
+ });
183
+ this.storage.clearTokens();
184
+ this.storage.clearStateAndVerifier();
185
+ throw new AuthError("State parameter mismatch - potential CSRF attack", ErrorCode.InvalidState);
186
+ }
187
+ if (this.storage.isTokenExpired(storedStateToken)) {
188
+ this.storage.clearTokens();
189
+ this.storage.clearStateAndVerifier();
190
+ throw new AuthError("State parameter expired - possible replay attack", ErrorCode.InvalidState);
191
+ }
192
+ if (this.oauthApi) {
193
+ try {
194
+ const response = await this.oauthApi.getTokensApiV1OauthTokenPost({
195
+ tokenRequest: {
196
+ grantType: "authorization_code",
197
+ code,
198
+ clientId: this.config.clientId,
199
+ codeVerifier: verifierToken.value,
200
+ }
201
+ });
202
+ const tokenSet = this.convertTenantTokenResponse(response);
203
+ await this.storage.setTokens(tokenSet);
204
+ this.storage.clearStateAndVerifier();
205
+ return;
206
+ }
207
+ catch (error) {
208
+ throw new AuthError("Token exchange failed", ErrorCode.TokenExchangeFailed, error.message || "Tenant SDK request failed");
209
+ }
210
+ }
211
+ // Fallback to manual implementation
212
+ const tokenSet = await this.makeTokenRequest({
213
+ grant_type: "authorization_code",
214
+ code,
215
+ redirect_uri: this.config.redirectUri,
216
+ client_id: this.config.clientId,
217
+ code_verifier: verifierToken.value,
218
+ });
219
+ await this.storage.setTokens(tokenSet);
220
+ this.storage.clearStateAndVerifier();
221
+ }
222
+ /**
223
+ * Generates the logout URL for ending the OAuth session
224
+ *
225
+ * @returns Promise resolving to the logout URL
226
+ *
227
+ * @example
228
+ * ```typescript
229
+ * const logoutUrl = await flow.getLogoutUrl();
230
+ * // Returns: "https://auth.binoauth.com/api/v1/oauth/logout?client_id=..."
231
+ *
232
+ * window.location.href = logoutUrl; // Redirect to logout
233
+ * ```
234
+ *
235
+ * @throws {AuthError} When logout endpoint is missing from config
236
+ */
237
+ async getLogoutUrl() {
238
+ if (!this.config.logoutEndpoint) {
239
+ throw new AuthError("Missing logoutEndpoint in config", ErrorCode.InvalidConfig);
240
+ }
241
+ const params = new URLSearchParams({
242
+ client_id: this.config.clientId,
243
+ redirect_uri: this.config.redirectUri,
244
+ });
245
+ return `${this.config.logoutEndpoint}?${params.toString()}`;
246
+ }
247
+ /**
248
+ * Generates the logout page URL with optional return URL
249
+ *
250
+ * This URL points to the BinoAuth logout page where the user can
251
+ * terminate their session and optionally be redirected back.
252
+ *
253
+ * @param returnTo - Optional URL to redirect to after logout
254
+ * @returns Promise resolving to the logout page URL
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * // Simple logout
259
+ * const logoutPageUrl = await flow.getLogoutPageUrl();
260
+ * // Returns: "https://auth.binoauth.com/auth/logout?client_id=..."
261
+ *
262
+ * // Logout with return URL
263
+ * const logoutPageUrl = await flow.getLogoutPageUrl('https://myapp.com/goodbye');
264
+ * // Returns: "https://auth.binoauth.com/auth/logout?client_id=...&return_to=..."
265
+ *
266
+ * window.location.href = logoutPageUrl;
267
+ * ```
268
+ */
269
+ async getLogoutPageUrl(returnTo) {
270
+ const url = new URL(this.config.logoutPage);
271
+ url.searchParams.set("client_id", this.config.clientId);
272
+ if (returnTo) {
273
+ url.searchParams.set("return_to", returnTo);
274
+ }
275
+ return url.toString();
276
+ }
277
+ }
278
+ //# sourceMappingURL=authorization-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-code.js","sourceRoot":"","sources":["../../../../../src/oauth/flows/authorization-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { AuthConfig, TokenSet } from "../types";
2
+ import { TokenStorage } from "../storage";
3
+ import type { OAuth2Api } from "@binoauth/tenant-sdk";
4
+ export declare abstract class BaseFlow {
5
+ protected config: AuthConfig;
6
+ protected storage: TokenStorage;
7
+ protected oauthApi?: OAuth2Api;
8
+ private rateLimiter;
9
+ protected constructor(config: AuthConfig, storage: TokenStorage, oauthApi?: OAuth2Api);
10
+ protected checkRateLimit(operation: string, maxAttempts?: number, windowMs?: number): void;
11
+ protected cleanupRateLimiter(): void;
12
+ protected makeTokenRequest(payload: Record<string, string>): Promise<TokenSet>;
13
+ private convertToTokenSet;
14
+ protected convertTenantTokenResponse(response: any): TokenSet;
15
+ protected getIssuerFromEndpoint(): string;
16
+ }
17
+ //# sourceMappingURL=base-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-flow.d.ts","sourceRoot":"","sources":["../../../../../src/oauth/flows/base-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8BAAsB,QAAQ;IAC5B,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;IAC7B,SAAS,CAAC,OAAO,EAAE,YAAY,CAAC;IAChC,SAAS,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;IAC/B,OAAO,CAAC,WAAW,CAAgE;IAEnF,SAAS,aAAa,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,SAAS;IAMrF,SAAS,CAAC,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,GAAE,MAAU,EAAE,QAAQ,GAAE,MAAuB,GAAG,IAAI;IAyB7G,SAAS,CAAC,kBAAkB,IAAI,IAAI;cASpB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA8BpF,OAAO,CAAC,iBAAiB;IA4CzB,SAAS,CAAC,0BAA0B,CAAC,QAAQ,EAAE,GAAG,GAAG,QAAQ;IAiB7D,SAAS,CAAC,qBAAqB,IAAI,MAAM;CAG1C"}
@@ -0,0 +1,107 @@
1
+ import { TokenStorage } from "../storage";
2
+ import { AuthError, ErrorCode } from "../error";
3
+ export class BaseFlow {
4
+ config;
5
+ storage;
6
+ oauthApi;
7
+ rateLimiter = new Map();
8
+ constructor(config, storage, oauthApi) {
9
+ this.config = config;
10
+ this.storage = storage;
11
+ this.oauthApi = oauthApi;
12
+ }
13
+ checkRateLimit(operation, maxAttempts = 5, windowMs = 15 * 60 * 1000) {
14
+ const now = Date.now();
15
+ const key = `${this.config.clientId}:${operation}`;
16
+ let limiter = this.rateLimiter.get(key);
17
+ if (!limiter || now >= limiter.resetTime) {
18
+ limiter = {
19
+ count: 0,
20
+ resetTime: now + windowMs
21
+ };
22
+ this.rateLimiter.set(key, limiter);
23
+ }
24
+ if (limiter.count >= maxAttempts) {
25
+ const timeUntilReset = Math.ceil((limiter.resetTime - now) / 1000);
26
+ throw new AuthError(`Rate limit exceeded for ${operation}. Try again in ${timeUntilReset} seconds.`, ErrorCode.RateLimitExceeded);
27
+ }
28
+ limiter.count++;
29
+ }
30
+ cleanupRateLimiter() {
31
+ const now = Date.now();
32
+ for (const [key, limiter] of this.rateLimiter.entries()) {
33
+ if (now >= limiter.resetTime) {
34
+ this.rateLimiter.delete(key);
35
+ }
36
+ }
37
+ }
38
+ async makeTokenRequest(payload) {
39
+ const params = new URLSearchParams(payload);
40
+ const response = await fetch(this.config.tokenEndpoint, {
41
+ method: "POST",
42
+ headers: {
43
+ "Content-Type": "application/x-www-form-urlencoded",
44
+ },
45
+ body: params.toString(),
46
+ });
47
+ if (!response.ok) {
48
+ let errorDetail = "Token request failed";
49
+ try {
50
+ const error = await response.json();
51
+ errorDetail = error.detail || error.error_description || error.error || errorDetail;
52
+ }
53
+ catch (e) {
54
+ errorDetail = await response.text();
55
+ }
56
+ throw new AuthError("Token request failed", ErrorCode.TokenExchangeFailed, errorDetail);
57
+ }
58
+ const tokens = await response.json();
59
+ return this.convertToTokenSet(tokens);
60
+ }
61
+ convertToTokenSet(tokens) {
62
+ if (!tokens.access_token || typeof tokens.access_token !== 'string' || tokens.access_token.trim() === '') {
63
+ throw new AuthError("Invalid token response: missing or invalid access_token", ErrorCode.TokenExchangeFailed);
64
+ }
65
+ if (tokens.expires_in === undefined || tokens.expires_in === null || typeof tokens.expires_in !== 'number' || tokens.expires_in <= 0) {
66
+ throw new AuthError("Invalid token response: missing or invalid expires_in", ErrorCode.TokenExchangeFailed);
67
+ }
68
+ if (tokens.refresh_token !== undefined && (typeof tokens.refresh_token !== 'string' || tokens.refresh_token.trim() === '')) {
69
+ throw new AuthError("Invalid token response: invalid refresh_token", ErrorCode.TokenExchangeFailed);
70
+ }
71
+ const tokenSet = {
72
+ accessToken: {
73
+ value: tokens.access_token,
74
+ expiresAt: Date.now() + tokens.expires_in * 1000,
75
+ },
76
+ };
77
+ if (tokens.refresh_token) {
78
+ tokenSet.refreshToken = {
79
+ value: tokens.refresh_token,
80
+ };
81
+ }
82
+ if (tokens.id_token) {
83
+ tokenSet.idToken = {
84
+ value: tokens.id_token,
85
+ };
86
+ }
87
+ return tokenSet;
88
+ }
89
+ convertTenantTokenResponse(response) {
90
+ const tokenSet = {
91
+ accessToken: {
92
+ value: response.accessToken,
93
+ expiresAt: Date.now() + response.expiresIn * 1000,
94
+ },
95
+ };
96
+ if (response.refreshToken) {
97
+ tokenSet.refreshToken = {
98
+ value: response.refreshToken,
99
+ };
100
+ }
101
+ return tokenSet;
102
+ }
103
+ getIssuerFromEndpoint() {
104
+ return this.config.authorizeEndpoint.replace('/api/v1/oauth/authorize', '');
105
+ }
106
+ }
107
+ //# sourceMappingURL=base-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-flow.js","sourceRoot":"","sources":["../../../../../src/oauth/flows/base-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ import type { AuthConfig } from "../types";
2
+ import { TokenStorage } from "../storage";
3
+ import { BaseFlow } from "./base-flow";
4
+ import type { OAuth2Api } from "@binoauth/tenant-sdk";
5
+ /**
6
+ * OAuth 2.0 Client Credentials Grant
7
+ *
8
+ * This flow is used for server-to-server authentication where the client
9
+ * can securely store a client secret. No user interaction is required.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const flow = new ClientCredentialsFlow(
14
+ * { ...config, clientSecret: 'your_client_secret' },
15
+ * storage,
16
+ * oauthApi
17
+ * );
18
+ *
19
+ * // Get access token for server-to-server communication
20
+ * await flow.getTokens();
21
+ *
22
+ * // Token is now stored and ready for API calls
23
+ * const accessToken = await storage.getAccessToken();
24
+ *
25
+ * // Use token for API requests
26
+ * const response = await fetch('/api/protected', {
27
+ * headers: {
28
+ * 'Authorization': `Bearer ${accessToken.value}`
29
+ * }
30
+ * });
31
+ * ```
32
+ */
33
+ export declare class ClientCredentialsFlow extends BaseFlow {
34
+ private clientSecret;
35
+ constructor(config: AuthConfig & {
36
+ clientSecret: string;
37
+ }, storage: TokenStorage, oauthApi?: OAuth2Api);
38
+ /**
39
+ * Requests access tokens using client credentials
40
+ *
41
+ * This method authenticates the client application itself (not a user)
42
+ * and obtains an access token for server-to-server communication.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const flow = new ClientCredentialsFlow(
47
+ * {
48
+ * ...config,
49
+ * clientSecret: 'your_client_secret'
50
+ * },
51
+ * storage,
52
+ * oauthApi
53
+ * );
54
+ *
55
+ * // Request tokens for server-to-server auth
56
+ * await flow.getTokens();
57
+ *
58
+ * // Use the stored token for API calls
59
+ * const accessToken = await storage.getAccessToken();
60
+ * const response = await fetch('/api/protected-resource', {
61
+ * headers: {
62
+ * 'Authorization': `Bearer ${accessToken.value}`
63
+ * }
64
+ * });
65
+ * ```
66
+ *
67
+ * @throws {AuthError} When client credentials are invalid
68
+ * @throws {AuthError} When the token request fails
69
+ */
70
+ getTokens(): Promise<void>;
71
+ }
72
+ //# sourceMappingURL=client-credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-credentials.d.ts","sourceRoot":"","sources":["../../../../../src/oauth/flows/client-credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,qBAAsB,SAAQ,QAAQ;IACjD,OAAO,CAAC,YAAY,CAAS;gBAEjB,MAAM,EAAE,UAAU,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,EAAE,SAAS;IAKtG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAoCjC"}
@@ -0,0 +1,100 @@
1
+ import { TokenStorage } from "../storage";
2
+ import { AuthError, ErrorCode } from "../error";
3
+ import { BaseFlow } from "./base-flow";
4
+ /**
5
+ * OAuth 2.0 Client Credentials Grant
6
+ *
7
+ * This flow is used for server-to-server authentication where the client
8
+ * can securely store a client secret. No user interaction is required.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const flow = new ClientCredentialsFlow(
13
+ * { ...config, clientSecret: 'your_client_secret' },
14
+ * storage,
15
+ * oauthApi
16
+ * );
17
+ *
18
+ * // Get access token for server-to-server communication
19
+ * await flow.getTokens();
20
+ *
21
+ * // Token is now stored and ready for API calls
22
+ * const accessToken = await storage.getAccessToken();
23
+ *
24
+ * // Use token for API requests
25
+ * const response = await fetch('/api/protected', {
26
+ * headers: {
27
+ * 'Authorization': `Bearer ${accessToken.value}`
28
+ * }
29
+ * });
30
+ * ```
31
+ */
32
+ export class ClientCredentialsFlow extends BaseFlow {
33
+ clientSecret;
34
+ constructor(config, storage, oauthApi) {
35
+ super(config, storage, oauthApi);
36
+ this.clientSecret = config.clientSecret;
37
+ }
38
+ /**
39
+ * Requests access tokens using client credentials
40
+ *
41
+ * This method authenticates the client application itself (not a user)
42
+ * and obtains an access token for server-to-server communication.
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const flow = new ClientCredentialsFlow(
47
+ * {
48
+ * ...config,
49
+ * clientSecret: 'your_client_secret'
50
+ * },
51
+ * storage,
52
+ * oauthApi
53
+ * );
54
+ *
55
+ * // Request tokens for server-to-server auth
56
+ * await flow.getTokens();
57
+ *
58
+ * // Use the stored token for API calls
59
+ * const accessToken = await storage.getAccessToken();
60
+ * const response = await fetch('/api/protected-resource', {
61
+ * headers: {
62
+ * 'Authorization': `Bearer ${accessToken.value}`
63
+ * }
64
+ * });
65
+ * ```
66
+ *
67
+ * @throws {AuthError} When client credentials are invalid
68
+ * @throws {AuthError} When the token request fails
69
+ */
70
+ async getTokens() {
71
+ this.checkRateLimit("client_credentials", 5, 10 * 60 * 1000);
72
+ if (this.oauthApi) {
73
+ try {
74
+ const response = await this.oauthApi.getTokensApiV1OauthTokenPost({
75
+ tokenRequest: {
76
+ grantType: "client_credentials",
77
+ clientId: this.config.clientId,
78
+ clientSecret: this.clientSecret,
79
+ scope: this.config.scope,
80
+ }
81
+ });
82
+ const tokenSet = this.convertTenantTokenResponse(response);
83
+ await this.storage.setTokens(tokenSet);
84
+ return;
85
+ }
86
+ catch (error) {
87
+ throw new AuthError("Client credentials token request failed", ErrorCode.TokenExchangeFailed, error.message || "Tenant SDK request failed");
88
+ }
89
+ }
90
+ // Fallback to manual implementation
91
+ const tokenSet = await this.makeTokenRequest({
92
+ grant_type: "client_credentials",
93
+ client_id: this.config.clientId,
94
+ client_secret: this.clientSecret,
95
+ scope: this.config.scope,
96
+ });
97
+ await this.storage.setTokens(tokenSet);
98
+ }
99
+ }
100
+ //# sourceMappingURL=client-credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-credentials.js","sourceRoot":"","sources":["../../../../../src/oauth/flows/client-credentials.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAO,qBAAsB,SAAQ,QAAQ;IACzC,YAAY,CAAS;IAE7B,YAAY,MAA6C,EAAE,OAAqB,EAAE,QAAoB;QACpG,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IAC1C,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAE7D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC;oBAChE,YAAY,EAAE;wBACZ,SAAS,EAAE,oBAAoB;wBAC/B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;wBAC9B,YAAY,EAAE,IAAI,CAAC,YAAY;wBAC/B,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;qBACzB;iBACF,CAAC,CAAC;gBAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;gBAC3D,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBACvC,OAAO;YACT,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,MAAM,IAAI,SAAS,CACjB,yCAAyC,EACzC,SAAS,CAAC,mBAAmB,EAC7B,KAAK,CAAC,OAAO,IAAI,2BAA2B,CAC7C,CAAC;YACJ,CAAC;QACH,CAAC;QAED,oCAAoC;QACpC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC;YAC3C,UAAU,EAAE,oBAAoB;YAChC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,aAAa,EAAE,IAAI,CAAC,YAAY;YAChC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;SACzB,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACzC,CAAC;CACF"}