@dainprotocol/oauth2-token-manager 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +29 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +23 -27
package/README.md
CHANGED
|
@@ -242,9 +242,20 @@ interface OAuth2Config {
|
|
|
242
242
|
profileUrl?: string;
|
|
243
243
|
usePKCE?: boolean;
|
|
244
244
|
extraAuthParams?: Record<string, string>;
|
|
245
|
+
|
|
246
|
+
// Custom token extraction paths for non-standard OAuth2 responses
|
|
247
|
+
tokenPaths?: {
|
|
248
|
+
accessToken?: string | string[]; // Path(s) to access token (e.g., 'authed_user.access_token')
|
|
249
|
+
refreshToken?: string | string[]; // Path(s) to refresh token
|
|
250
|
+
expiresIn?: string | string[]; // Path(s) to expires_in field
|
|
251
|
+
tokenType?: string | string[]; // Path(s) to token_type field
|
|
252
|
+
scope?: string | string[]; // Path(s) to scope field
|
|
253
|
+
};
|
|
245
254
|
}
|
|
246
255
|
```
|
|
247
256
|
|
|
257
|
+
**Custom Token Paths**: For providers with non-standard response formats (like Slack), you can specify custom paths to extract token fields. See [Custom Token Paths Guide](./CUSTOM_TOKEN_PATHS.md) for detailed examples.
|
|
258
|
+
|
|
248
259
|
#### StoredToken
|
|
249
260
|
|
|
250
261
|
```typescript
|
|
@@ -432,6 +443,65 @@ console.log(
|
|
|
432
443
|
);
|
|
433
444
|
```
|
|
434
445
|
|
|
446
|
+
### Slack OAuth (User Token)
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
const oauth = new OAuth2Client({
|
|
450
|
+
providers: {
|
|
451
|
+
slack: {
|
|
452
|
+
clientId: process.env.SLACK_CLIENT_ID,
|
|
453
|
+
clientSecret: process.env.SLACK_CLIENT_SECRET,
|
|
454
|
+
authorizationUrl: 'https://slack.com/oauth/v2/authorize',
|
|
455
|
+
tokenUrl: 'https://slack.com/api/oauth.v2.access',
|
|
456
|
+
redirectUri: 'http://localhost:3000/auth/slack/callback',
|
|
457
|
+
scopes: ['identity.basic', 'identity.email', 'identity.team'],
|
|
458
|
+
profileUrl: 'https://slack.com/api/users.identity',
|
|
459
|
+
// No tokenPaths needed - defaults prioritize user token
|
|
460
|
+
},
|
|
461
|
+
},
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// Start OAuth flow
|
|
465
|
+
const { url, state } = await oauth.authorize({
|
|
466
|
+
provider: 'slack',
|
|
467
|
+
userId: 'user123',
|
|
468
|
+
email: 'user@example.com',
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// After callback
|
|
472
|
+
const { token, profile } = await oauth.handleCallback(code, state);
|
|
473
|
+
// token.token.accessToken will be the user token (xoxp-...)
|
|
474
|
+
// token.token.raw will contain the full Slack response including team info
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Custom Provider with Non-Standard Response
|
|
478
|
+
|
|
479
|
+
```typescript
|
|
480
|
+
const oauth = new OAuth2Client({
|
|
481
|
+
providers: {
|
|
482
|
+
customApi: {
|
|
483
|
+
clientId: process.env.CUSTOM_CLIENT_ID,
|
|
484
|
+
clientSecret: process.env.CUSTOM_CLIENT_SECRET,
|
|
485
|
+
authorizationUrl: 'https://api.custom.com/oauth/authorize',
|
|
486
|
+
tokenUrl: 'https://api.custom.com/oauth/token',
|
|
487
|
+
redirectUri: 'http://localhost:3000/auth/custom/callback',
|
|
488
|
+
scopes: ['read', 'write'],
|
|
489
|
+
// Custom token paths for non-standard response structure
|
|
490
|
+
tokenPaths: {
|
|
491
|
+
accessToken: 'data.credentials.token',
|
|
492
|
+
refreshToken: 'data.credentials.refresh',
|
|
493
|
+
expiresIn: 'data.ttl',
|
|
494
|
+
},
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
// Works the same way as standard providers
|
|
500
|
+
const accessToken = await oauth.getAccessToken('customApi', 'user@example.com');
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
See [Custom Token Paths Guide](./CUSTOM_TOKEN_PATHS.md) for more examples.
|
|
504
|
+
|
|
435
505
|
### Custom Profile Fetcher Example
|
|
436
506
|
|
|
437
507
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var crypto=require('crypto'),ironSession=require('iron-session');var g=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}generateAuthorizationUrl(e,t,r){let o={client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scopes.join(" "),state:t};(e.usePKCE||e.pkce)&&r&&(o.code_challenge=r,o.code_challenge_method="S256");let n={...e.additionalParams,...e.extraAuthParams};return Object.assign(o,n),`${e.authorizationUrl}?${this.buildUrlParams(o)}`}};var k=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}async exchangeCodeForToken(e,t,r){let o={grant_type:"authorization_code",code:e,redirect_uri:t.redirectUri,client_id:t.clientId};(t.usePKCE||t.pkce)&&r?o.code_verifier=r:t.clientSecret&&(o.client_secret=t.clientSecret);let n=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(o)});if(!n.ok){let w=await n.text();throw new Error(`Token exchange failed: ${n.statusText} - ${w}`)}let i=await n.json(),a=t.responseRootKey?i[t.responseRootKey]:i,c=Date.now(),p=a.expires_in||3600;return {accessToken:a.access_token,refreshToken:a.refresh_token,expiresAt:new Date(c+p*1e3),expiresIn:p,tokenType:a.token_type||"Bearer",scope:a.scope,createdAt:c,raw:i}}async refreshToken(e,t){let r={grant_type:"refresh_token",refresh_token:e,client_id:t.clientId};!(t.usePKCE||t.pkce)&&t.clientSecret&&(r.client_secret=t.clientSecret);let o=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(r)});if(!o.ok){let p=await o.text();throw new Error(`Token refresh failed: ${o.statusText} - ${p}`)}let n=await o.json(),i=t.responseRootKey?n[t.responseRootKey]:n,a=Date.now(),c=i.expires_in||3600;return {accessToken:i.access_token,refreshToken:i.refresh_token||e,expiresAt:new Date(a+c*1e3),expiresIn:c,tokenType:i.token_type||"Bearer",scope:i.scope,createdAt:a,raw:n}}};var l=class{constructor(e,t,r,o){this.config=e;this.authUrlStrategy=t||this.createAuthorizationUrlStrategy(),this.tokenStrategy=r||this.createTokenExchangeStrategy(),this.profileFetcher=o;}authUrlStrategy;tokenStrategy;profileFetcher;async fetchProfile(e){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.fetchUserInfo(e)}getProfileEndpoint(){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.getEndpoint()}setProfileFetcher(e){this.profileFetcher=e;}hasProfileFetcher(){return !!this.profileFetcher}generateAuthorizationUrl(e,t){return this.authUrlStrategy.generateAuthorizationUrl(this.config,e,t)}async exchangeCodeForToken(e,t){return this.tokenStrategy.exchangeCodeForToken(e,this.config,t)}async refreshToken(e){return this.tokenStrategy.refreshToken(e,this.config)}};var T=class extends l{constructor(e,t,r,o){super(e,t,r,o);}createAuthorizationUrlStrategy(){return new g}createTokenExchangeStrategy(){return new k}};var d=class{constructor(e){this.profileEndpoint=e;}async fetchUserInfo(e){let t=await fetch(this.profileEndpoint,{headers:{Authorization:`Bearer ${e}`,Accept:"application/json",...this.getAdditionalHeaders()}});if(!t.ok)throw new Error(`Failed to fetch profile from ${this.profileEndpoint}: ${t.statusText}`);let r=await t.json();return this.mapToUserProfile(r)}getAdditionalHeaders(){return {}}getEndpoint(){return this.profileEndpoint}};var P=class extends d{constructor(){super("https://www.googleapis.com/oauth2/v2/userinfo");}mapToUserProfile(e){return {email:e.email,name:e.name,id:e.id,avatar:e.picture,username:e.email,raw:e}}};var y=class extends d{constructor(){super("https://api.github.com/user");}mapToUserProfile(e){var t;return {email:e.email,name:e.name||e.login,id:(t=e.id)==null?void 0:t.toString(),avatar:e.avatar_url,username:e.login,raw:e}}getAdditionalHeaders(){return {"User-Agent":"OAuth2-Token-Manager"}}};var v=class extends d{constructor(){super("https://graph.microsoft.com/v1.0/me");}mapToUserProfile(e){return {email:e.mail||e.userPrincipalName,name:e.displayName,id:e.id,avatar:void 0,username:e.userPrincipalName,raw:e}}};var h=class extends d{constructor(t,r,o){super(t);this.mapping=r;this.additionalHeaders=o;}mapToUserProfile(t){return this.mapping?{email:this.getNestedProperty(t,this.mapping.email),name:this.mapping.name?this.getNestedProperty(t,this.mapping.name):void 0,id:this.mapping.id?this.getNestedProperty(t,this.mapping.id):void 0,avatar:this.mapping.avatar?this.getNestedProperty(t,this.mapping.avatar):void 0,username:this.mapping.username?this.getNestedProperty(t,this.mapping.username):void 0,raw:t}:{email:t.email||t.mail||t.emailAddress,name:t.name||t.displayName||t.full_name,id:t.id||t.sub||t.user_id,avatar:t.avatar||t.picture||t.avatar_url,username:t.username||t.login||t.preferred_username,raw:t}}getAdditionalHeaders(){return this.additionalHeaders||{}}getNestedProperty(t,r){return r.split(".").reduce((o,n)=>o==null?void 0:o[n],t)}};var A=class{static createProfileFetcher(e,t,r){if(r!=null&&r.profileUrl)return new h(r.profileUrl,r.profileMapping,r.profileHeaders);switch(e){case "google":return new P;case "github":return new y;case "microsoft":case "outlook":return new v;case "facebook":return new h("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let o=t.profileUrl||t.userInfoUrl;if(!o)throw new Error(`Profile URL must be provided for ${e} provider`);return new h(o)}}static registerCustomProfileFetcher(e,t){this.customFetchers.set(e,t);}static customFetchers=new Map;static getCustomProfileFetcher(e){return this.customFetchers.get(e)}};var x=class s{static presetConfigs={google:{authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",profileUrl:"https://www.googleapis.com/oauth2/v2/userinfo",usePKCE:true,extraAuthParams:{access_type:"offline",prompt:"consent"}},github:{authorizationUrl:"https://github.com/login/oauth/authorize",tokenUrl:"https://github.com/login/oauth/access_token",profileUrl:"https://api.github.com/user"},microsoft:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true},outlook:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true,extraAuthParams:{prompt:"select_account"}},facebook:{authorizationUrl:"https://www.facebook.com/v12.0/dialog/oauth",tokenUrl:"https://graph.facebook.com/v12.0/oauth/access_token",profileUrl:"https://graph.facebook.com/me?fields=id,name,email,picture"}};createProvider(e,t){let r=e!=="generic"?s.presetConfigs[e]||{}:{},o={...r,...t,authorizationUrl:t.authorizationUrl||r.authorizationUrl||"",tokenUrl:t.tokenUrl||r.tokenUrl||"",profileUrl:t.profileUrl||r.profileUrl,extraAuthParams:{...r.extraAuthParams||{},...t.extraAuthParams||{}}},n=A.createProfileFetcher(e,o);return new T(o,void 0,void 0,n)}static registerPreset(e,t){s.presetConfigs[e]=t;}static getPresetConfig(e){return s.presetConfigs[e]}};var f=class{tokens=new Map;states=new Map;profileFetchers=new Map;generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async saveToken(e){let t=await this.getToken(e.provider,e.email,e.tenant);if(t){let o={...t,...e,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,o),o}let r={...e,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(r.id,r),r}async queryTokens(e){let t=Array.from(this.tokens.values());if(e.id&&(t=t.filter(r=>r.id===e.id)),e.provider&&(t=t.filter(r=>r.provider===e.provider)),e.userId&&(t=t.filter(r=>r.userId===e.userId)),e.email&&(t=t.filter(r=>r.email===e.email)),e.tenant!==void 0&&(t=t.filter(r=>r.tenant===e.tenant)),!e.includeExpired){let r=new Date().getTime();t=t.filter(o=>new Date(o.token.expiresAt).getTime()>=r);}return e.offset!==void 0&&(t=t.slice(e.offset)),e.limit!==void 0&&(t=t.slice(0,e.limit)),t}async getToken(e,t,r){return (await this.queryTokens({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getTokenById(e){return (await this.queryTokens({id:e,includeExpired:true}))[0]||null}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async getTokensByProvider(e){return this.queryTokens({provider:e})}async getAccounts(e,t){return this.queryTokens({userId:e,provider:t})}async getTokensForEmail(e,t,r){return (await this.queryTokens({userId:e,provider:t,email:r}))[0]||null}async getTokens(e,t){return this.queryTokens({userId:e,provider:t})}async updateToken(e,t){let r=this.tokens.get(e);if(!r)return null;let o={...r,...t.token&&{token:t.token},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,o),o}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let o=await this.getToken(e,t,r);return o?this.tokens.delete(o.id):false}async deleteExpiredTokens(){let e=new Date().getTime(),t=Array.from(this.tokens.entries()).filter(([,r])=>new Date(r.token.expiresAt).getTime()<e).map(([r])=>r);return t.forEach(r=>this.tokens.delete(r)),t.length}async saveAuthorizationState(e){let t={...e,createdAt:new Date(Date.now())};return this.states.set(e.state,t),t}async getAuthorizationState(e){return this.states.get(e)||null}async deleteAuthorizationState(e){return this.states.delete(e)}async cleanupExpiredStates(){let e=new Date().getTime(),t=10*60*1e3,r=Array.from(this.states.entries()).filter(([,o])=>e-o.createdAt.getTime()>t).map(([o])=>o);return r.forEach(o=>this.states.delete(o)),r.length}registerProfileFetcher(e,t){this.profileFetchers.set(e,t);}getProfileFetcher(e){return this.profileFetchers.get(e)}getProfileFetchers(){return new Map(this.profileFetchers)}};var R=()=>crypto.randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),z=s=>crypto.createHash("sha256").update(s).digest("base64url"),I=()=>crypto.randomBytes(16).toString("base64url");var S=class{storage;providerFactory;providers=new Map;providerConfigs=new Map;now;autoRefreshOptions;constructor(e={}){var t,r,o;this.storage=e.storage||new f,this.providerFactory=new x,this.now=Date.now,this.autoRefreshOptions={enabled:((t=e.autoRefresh)==null?void 0:t.enabled)??true,refreshBuffer:((r=e.autoRefresh)==null?void 0:r.refreshBuffer)??10,onRefreshError:(o=e.autoRefresh)==null?void 0:o.onRefreshError},e.providers&&Object.entries(e.providers).forEach(([n,i])=>{this.registerProvider(n,i);});}registerProvider(e,t){this.providerConfigs.set(e,t);let r=this.detectProviderType(e,t),o=this.providerFactory.createProvider(r,t),n=this.storage.getProfileFetcher(e);n&&o.setProfileFetcher(n),this.providers.set(e,o);}async authorize(e){var a;let t=this.providers.get(e.provider);if(!t)throw new Error(`Provider ${e.provider} not found`);let r=I(),o,n;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let c=R(),p=z(c);o=t.generateAuthorizationUrl(r,p),n={state:r,codeVerifier:c,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};}else o=t.generateAuthorizationUrl(r),n={state:r,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};return await this.storage.saveAuthorizationState(n),{url:o,state:r}}async handleCallback(e,t){var U,O,E,b,F;let r=await this.storage.getAuthorizationState(t);if(!r)throw new Error("Invalid or expired state");let o=(U=r.metadata)==null?void 0:U.provider;if(!o)throw new Error("Provider not found in authorization state");let n=this.providers.get(o);if(!n)throw new Error(`Provider ${o} not found`);let i=await n.exchangeCodeForToken(e,r.codeVerifier),a=(O=r.metadata)==null?void 0:O.userId,c=(E=r.metadata)==null?void 0:E.email,p=(b=r.metadata)==null?void 0:b.tenant,w=(F=r.metadata)==null?void 0:F.tenantName;if(!a||!c)throw new Error("User ID and email are required in authorization state");let u;if(n.hasProfileFetcher())try{u=await n.fetchProfile(i.accessToken);}catch(_){console.warn("Failed to fetch user profile:",_);}let B=await this.storage.saveToken({provider:o,userId:a,email:(u==null?void 0:u.email)||c,tenant:p,tenantName:w,token:i,metadata:{...r.metadata,profileFetched:!!u}});await this.storage.deleteAuthorizationState(t);let m=this.providerConfigs.get(o);return m!=null&&m.onSuccess&&await m.onSuccess(a,i),{token:B,profile:u}}async getAccessToken(e,t,r={}){return (await this.getValidToken(e,t,r)).accessToken}async getValidToken(e,t,r={}){let o=await this.storage.getToken(e,t,r.tenant);if(!o){let c=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${c}`)}if(!(r.autoRefresh!==false&&this.isTokenExpired(o.token,r)))return o.token;if(!o.token.refreshToken)throw new Error("Token expired and no refresh token available");let i=this.providers.get(e);if(!i)throw new Error(`Provider ${e} not found`);let a=await i.refreshToken(o.token.refreshToken);return await this.storage.updateToken(o.id,{token:a}),a}async queryTokens(e){let t=this.autoRefreshOptions.enabled&&!e.includeExpired?{...e,includeExpired:true}:e,r=await this.storage.queryTokens(t);return this.autoRefreshOptions.enabled&&!e.includeExpired?(await this.refreshTokensIfNeeded(r)).filter(n=>new Date(n.token.expiresAt).getTime()>this.now()):r}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async deleteToken(e,t,r){return this.storage.deleteTokenByProviderEmail(e,t,r)}async cleanupExpiredTokens(){return this.storage.deleteExpiredTokens()}async cleanupExpiredStates(){return this.storage.cleanupExpiredStates()}isTokenExpired(e,t={}){let{expirationBuffer:r=300}=t;if(e.createdAt&&e.expiresIn!==void 0){let i=e.createdAt+e.expiresIn*1e3;return this.now()+r*1e3>=i}let o=new Date(e.expiresAt).getTime();return this.now()+r*1e3>=o}detectProviderType(e,t){var o;let r=t.authorizationUrl.toLowerCase();return r.includes("accounts.google.com")?"google":r.includes("github.com")?"github":r.includes("facebook.com")?"facebook":r.includes("microsoft.com")||r.includes("microsoftonline.com")?e.toLowerCase().includes("outlook")||(o=t.scopes)!=null&&o.some(n=>n.includes("outlook"))?"outlook":"microsoft":"generic"}async refreshTokensIfNeeded(e){let t=e.map(async r=>{if(this.shouldRefreshToken(r))try{let o=this.providers.get(r.provider);if(!o)return console.warn(`Provider ${r.provider} not found for token refresh`),r;if(!r.token.refreshToken)return console.warn(`No refresh token available for ${r.provider}:${r.email}`),r;let n=await o.refreshToken(r.token.refreshToken);return await this.storage.updateToken(r.id,{token:n})||r}catch(o){return this.autoRefreshOptions.onRefreshError&&this.autoRefreshOptions.onRefreshError(o,r),console.error(`Failed to refresh token for ${r.provider}:${r.email}:`,o),r}return r});return Promise.all(t)}shouldRefreshToken(e){if(!e.token.refreshToken)return false;let t=new Date(e.token.expiresAt).getTime(),r=this.now();if(r>=t)return true;let o=this.autoRefreshOptions.refreshBuffer*60*1e3,n=t-o;return r>=n}updateAutoRefreshOptions(e){this.autoRefreshOptions={...this.autoRefreshOptions,...e};}async getTokensAcrossTenants(e,t){return this.queryTokens({provider:e,userId:t})}async getTenants(e,t){let o=(await this.queryTokens({provider:e,email:t})).map(n=>n.tenant).filter(n=>n!==void 0);return [...new Set(o)]}async getTokenByTenantName(e,t,r){return (await this.queryTokens({provider:e,email:t})).find(n=>n.tenantName===r)||null}async hasTokenForTenant(e,t,r){return await this.storage.getToken(e,t,r)!==null}async getMultiTenantTokens(e,t){return (await this.queryTokens({provider:e,email:t})).map(o=>({token:o,tenant:o.tenant,tenantName:o.tenantName}))}};var ye=(s,e)=>ironSession.sealData(s,{password:e}),ve=(s,e)=>ironSession.unsealData(s,{password:e});
|
|
2
|
-
exports.BaseProfileFetcher=
|
|
1
|
+
'use strict';var crypto=require('crypto'),ironSession=require('iron-session');var v=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}generateAuthorizationUrl(e,t,r){let o={client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scopes.join(" "),state:t};(e.usePKCE||e.pkce)&&r&&(o.code_challenge=r,o.code_challenge_method="S256");let n={...e.additionalParams,...e.extraAuthParams};return Object.assign(o,n),`${e.authorizationUrl}?${this.buildUrlParams(o)}`}};var x=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}async exchangeCodeForToken(e,t,r){let o={grant_type:"authorization_code",code:e,redirect_uri:t.redirectUri,client_id:t.clientId};(t.usePKCE||t.pkce)&&r?o.code_verifier=r:t.clientSecret&&(o.client_secret=t.clientSecret);let n=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(o)});if(!n.ok){let c=await n.text();throw new Error(`Token exchange failed: ${n.statusText} - ${c}`)}let i=await n.json(),a=t.responseRootKey?i[t.responseRootKey]:i;return this.normalizeTokenResponse(a,i,void 0,t)}async refreshToken(e,t){let r={grant_type:"refresh_token",refresh_token:e,client_id:t.clientId};!(t.usePKCE||t.pkce)&&t.clientSecret&&(r.client_secret=t.clientSecret);let o=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(r)});if(!o.ok){let a=await o.text();throw new Error(`Token refresh failed: ${o.statusText} - ${a}`)}let n=await o.json(),i=t.responseRootKey?n[t.responseRootKey]:n;return this.normalizeTokenResponse(i,n,e,t)}normalizeTokenResponse(e,t,r,o){var p,l,f,m,g;let n=Date.now(),i=this.extractValue(e,(p=o==null?void 0:o.tokenPaths)==null?void 0:p.accessToken,["authed_user.access_token","authed_user.accessToken","access_token","accessToken","token.access_token","token.accessToken"]);if(!i)throw new Error("Token response did not include an access_token");let a=this.extractValue(e,(l=o==null?void 0:o.tokenPaths)==null?void 0:l.refreshToken,["authed_user.refresh_token","authed_user.refreshToken","refresh_token","refreshToken","token.refresh_token","token.refreshToken"])??r,c=this.extractValue(e,(f=o==null?void 0:o.tokenPaths)==null?void 0:f.expiresIn,["authed_user.expires_in","authed_user.expiresIn","expires_in","expiresIn","token.expires_in","token.expiresIn"]),y=(typeof c=="string"?parseInt(c,10):c)||3600,d=this.extractValue(e,(m=o==null?void 0:o.tokenPaths)==null?void 0:m.scope,["authed_user.scope","scope","token.scope"]),b=this.extractValue(e,(g=o==null?void 0:o.tokenPaths)==null?void 0:g.tokenType,["authed_user.token_type","authed_user.tokenType","token_type","tokenType","token.token_type","token.tokenType"])??"Bearer";return {accessToken:i,refreshToken:a,expiresAt:new Date(n+y*1e3),expiresIn:y,tokenType:b,scope:d,createdAt:n,raw:t}}extractValue(e,t,r){if(t){let o=Array.isArray(t)?t:[t];for(let n of o){let i=this.getNestedValue(e,n);if(i!==void 0)return i}}if(r)for(let o of r){let n=this.getNestedValue(e,o);if(n!==void 0)return n}}getNestedValue(e,t){let r=t.split("."),o=e;for(let n of r)if(o&&typeof o=="object"&&n in o)o=o[n];else return;return o}};var k=class{constructor(e,t,r,o){this.config=e;this.authUrlStrategy=t||this.createAuthorizationUrlStrategy(),this.tokenStrategy=r||this.createTokenExchangeStrategy(),this.profileFetcher=o;}authUrlStrategy;tokenStrategy;profileFetcher;async fetchProfile(e){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.fetchUserInfo(e)}getProfileEndpoint(){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.getEndpoint()}setProfileFetcher(e){this.profileFetcher=e;}hasProfileFetcher(){return !!this.profileFetcher}generateAuthorizationUrl(e,t){return this.authUrlStrategy.generateAuthorizationUrl(this.config,e,t)}async exchangeCodeForToken(e,t){return this.tokenStrategy.exchangeCodeForToken(e,this.config,t)}async refreshToken(e){return this.tokenStrategy.refreshToken(e,this.config)}};var A=class extends k{constructor(e,t,r,o){super(e,t,r,o);}createAuthorizationUrlStrategy(){return new v}createTokenExchangeStrategy(){return new x}};var u=class{constructor(e){this.profileEndpoint=e;}async fetchUserInfo(e){let t=await fetch(this.profileEndpoint,{headers:{Authorization:`Bearer ${e}`,Accept:"application/json",...this.getAdditionalHeaders()}});if(!t.ok)throw new Error(`Failed to fetch profile from ${this.profileEndpoint}: ${t.statusText}`);let r=await t.json();return this.mapToUserProfile(r)}getAdditionalHeaders(){return {}}getEndpoint(){return this.profileEndpoint}};var S=class extends u{constructor(){super("https://www.googleapis.com/oauth2/v2/userinfo");}mapToUserProfile(e){return {email:e.email,name:e.name,id:e.id,avatar:e.picture,username:e.email,raw:e}}};var w=class extends u{constructor(){super("https://api.github.com/user");}mapToUserProfile(e){var t;return {email:e.email,name:e.name||e.login,id:(t=e.id)==null?void 0:t.toString(),avatar:e.avatar_url,username:e.login,raw:e}}getAdditionalHeaders(){return {"User-Agent":"OAuth2-Token-Manager"}}};var U=class extends u{constructor(){super("https://graph.microsoft.com/v1.0/me");}mapToUserProfile(e){return {email:e.mail||e.userPrincipalName,name:e.displayName,id:e.id,avatar:void 0,username:e.userPrincipalName,raw:e}}};var h=class extends u{constructor(t,r,o){super(t);this.mapping=r;this.additionalHeaders=o;}mapToUserProfile(t){return this.mapping?{email:this.getNestedProperty(t,this.mapping.email),name:this.mapping.name?this.getNestedProperty(t,this.mapping.name):void 0,id:this.mapping.id?this.getNestedProperty(t,this.mapping.id):void 0,avatar:this.mapping.avatar?this.getNestedProperty(t,this.mapping.avatar):void 0,username:this.mapping.username?this.getNestedProperty(t,this.mapping.username):void 0,tenant:this.mapping.tenant?this.getNestedProperty(t,this.mapping.tenant):void 0,tenantName:this.mapping.tenantName?this.getNestedProperty(t,this.mapping.tenantName):void 0,raw:t}:{email:t.email||t.mail||t.emailAddress,name:t.name||t.displayName||t.full_name,id:t.id||t.sub||t.user_id,avatar:t.avatar||t.picture||t.avatar_url,username:t.username||t.login||t.preferred_username,tenant:t.tenant||t.workspace_id||t.organization_id||t.team_id,tenantName:t.tenantName||t.workspace_name||t.organization_name||t.team_name,raw:t}}getAdditionalHeaders(){return this.additionalHeaders||{}}getNestedProperty(t,r){return r.split(".").reduce((o,n)=>o==null?void 0:o[n],t)}};var E=class{static createProfileFetcher(e,t,r){if(r!=null&&r.profileUrl)return new h(r.profileUrl,r.profileMapping,r.profileHeaders);switch(e){case "google":return new S;case "github":return new w;case "microsoft":case "outlook":return new U;case "facebook":return new h("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let o=t.profileUrl||t.userInfoUrl;if(!o)throw new Error(`Profile URL must be provided for ${e} provider`);return new h(o)}}static registerCustomProfileFetcher(e,t){this.customFetchers.set(e,t);}static customFetchers=new Map;static getCustomProfileFetcher(e){return this.customFetchers.get(e)}};var O=class s{static presetConfigs={google:{authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",profileUrl:"https://www.googleapis.com/oauth2/v2/userinfo",usePKCE:true,extraAuthParams:{access_type:"offline",prompt:"consent"}},github:{authorizationUrl:"https://github.com/login/oauth/authorize",tokenUrl:"https://github.com/login/oauth/access_token",profileUrl:"https://api.github.com/user"},microsoft:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true},outlook:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true,extraAuthParams:{prompt:"select_account"}},facebook:{authorizationUrl:"https://www.facebook.com/v12.0/dialog/oauth",tokenUrl:"https://graph.facebook.com/v12.0/oauth/access_token",profileUrl:"https://graph.facebook.com/me?fields=id,name,email,picture"}};createProvider(e,t){let r=e!=="generic"?s.presetConfigs[e]||{}:{},o={...r,...t,authorizationUrl:t.authorizationUrl||r.authorizationUrl||"",tokenUrl:t.tokenUrl||r.tokenUrl||"",profileUrl:t.profileUrl||r.profileUrl,extraAuthParams:{...r.extraAuthParams||{},...t.extraAuthParams||{}}},n=E.createProfileFetcher(e,o);return new A(o,void 0,void 0,n)}static registerPreset(e,t){s.presetConfigs[e]=t;}static getPresetConfig(e){return s.presetConfigs[e]}};var T=class{tokens=new Map;states=new Map;profileFetchers=new Map;generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async saveToken(e){let t=await this.getToken(e.provider,e.email,e.tenant);if(t){let o={...t,...e,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,o),o}let r={...e,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(r.id,r),r}async queryTokens(e){let t=Array.from(this.tokens.values());if(e.id&&(t=t.filter(r=>r.id===e.id)),e.provider&&(t=t.filter(r=>r.provider===e.provider)),e.userId&&(t=t.filter(r=>r.userId===e.userId)),e.email&&(t=t.filter(r=>r.email===e.email)),e.tenant!==void 0&&(t=t.filter(r=>r.tenant===e.tenant)),!e.includeExpired){let r=new Date().getTime();t=t.filter(o=>new Date(o.token.expiresAt).getTime()>=r);}return e.offset!==void 0&&(t=t.slice(e.offset)),e.limit!==void 0&&(t=t.slice(0,e.limit)),t}async getToken(e,t,r){return (await this.queryTokens({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getTokenById(e){return (await this.queryTokens({id:e,includeExpired:true}))[0]||null}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async getTokensByProvider(e){return this.queryTokens({provider:e})}async getAccounts(e,t){return this.queryTokens({userId:e,provider:t})}async getTokensForEmail(e,t,r){return (await this.queryTokens({userId:e,provider:t,email:r}))[0]||null}async getTokens(e,t){return this.queryTokens({userId:e,provider:t})}async updateToken(e,t){let r=this.tokens.get(e);if(!r)return null;let o={...r,...t.token&&{token:t.token},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,o),o}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let o=await this.getToken(e,t,r);return o?this.tokens.delete(o.id):false}async deleteExpiredTokens(){let e=new Date().getTime(),t=Array.from(this.tokens.entries()).filter(([,r])=>new Date(r.token.expiresAt).getTime()<e).map(([r])=>r);return t.forEach(r=>this.tokens.delete(r)),t.length}async saveAuthorizationState(e){let t={...e,createdAt:new Date(Date.now())};return this.states.set(e.state,t),t}async getAuthorizationState(e){return this.states.get(e)||null}async deleteAuthorizationState(e){return this.states.delete(e)}async cleanupExpiredStates(){let e=new Date().getTime(),t=10*60*1e3,r=Array.from(this.states.entries()).filter(([,o])=>e-o.createdAt.getTime()>t).map(([o])=>o);return r.forEach(o=>this.states.delete(o)),r.length}registerProfileFetcher(e,t){this.profileFetchers.set(e,t);}getProfileFetcher(e){return this.profileFetchers.get(e)}getProfileFetchers(){return new Map(this.profileFetchers)}};var z=()=>crypto.randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),_=s=>crypto.createHash("sha256").update(s).digest("base64url"),I=()=>crypto.randomBytes(16).toString("base64url");var F=class{storage;providerFactory;providers=new Map;providerConfigs=new Map;now;autoRefreshOptions;constructor(e={}){var t,r,o;this.storage=e.storage||new T,this.providerFactory=new O,this.now=Date.now,this.autoRefreshOptions={enabled:((t=e.autoRefresh)==null?void 0:t.enabled)??true,refreshBuffer:((r=e.autoRefresh)==null?void 0:r.refreshBuffer)??10,onRefreshError:(o=e.autoRefresh)==null?void 0:o.onRefreshError},e.providers&&Object.entries(e.providers).forEach(([n,i])=>{this.registerProvider(n,i);});}registerProvider(e,t){this.providerConfigs.set(e,t);let r=this.detectProviderType(e,t),o=this.providerFactory.createProvider(r,t),n=this.storage.getProfileFetcher(e);n&&o.setProfileFetcher(n),this.providers.set(e,o);}async authorize(e){var a;let t=this.providers.get(e.provider);if(!t)throw new Error(`Provider ${e.provider} not found`);let r=I(),o,n;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let c=z(),P=_(c);o=t.generateAuthorizationUrl(r,P),n={state:r,codeVerifier:c,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};}else o=t.generateAuthorizationUrl(r),n={state:r,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};return await this.storage.saveAuthorizationState(n),{url:o,state:r}}async handleCallback(e,t){var l,f,m,g,C;let r=await this.storage.getAuthorizationState(t);if(!r)throw new Error("Invalid or expired state");let o=(l=r.metadata)==null?void 0:l.provider;if(!o)throw new Error("Provider not found in authorization state");let n=this.providers.get(o);if(!n)throw new Error(`Provider ${o} not found`);let i=await n.exchangeCodeForToken(e,r.codeVerifier),a=(f=r.metadata)==null?void 0:f.userId,c=(m=r.metadata)==null?void 0:m.email,P=(g=r.metadata)==null?void 0:g.tenant,y=(C=r.metadata)==null?void 0:C.tenantName;if(!a||!c)throw new Error("User ID and email are required in authorization state");let d;if(n.hasProfileFetcher())try{d=await n.fetchProfile(i.accessToken);}catch(N){console.warn("Failed to fetch user profile:",N);}let b=await this.storage.saveToken({provider:o,userId:a,email:(d==null?void 0:d.email)||c,tenant:(d==null?void 0:d.tenant)||P,tenantName:(d==null?void 0:d.tenantName)||y,token:i,metadata:{...r.metadata,profileFetched:!!d}});await this.storage.deleteAuthorizationState(t);let p=this.providerConfigs.get(o);return p!=null&&p.onSuccess&&await p.onSuccess(a,i),{token:b,profile:d}}async getAccessToken(e,t,r={}){return (await this.getValidToken(e,t,r)).accessToken}async getValidToken(e,t,r={}){let o=await this.storage.getToken(e,t,r.tenant);if(!o){let c=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${c}`)}if(!(r.autoRefresh!==false&&this.isTokenExpired(o.token,r)))return o.token;if(!o.token.refreshToken)throw new Error("Token expired and no refresh token available");let i=this.providers.get(e);if(!i)throw new Error(`Provider ${e} not found`);let a=await i.refreshToken(o.token.refreshToken);return await this.storage.updateToken(o.id,{token:a}),a}async queryTokens(e){let t=this.autoRefreshOptions.enabled&&!e.includeExpired?{...e,includeExpired:true}:e,r=await this.storage.queryTokens(t);return this.autoRefreshOptions.enabled&&!e.includeExpired?(await this.refreshTokensIfNeeded(r)).filter(n=>new Date(n.token.expiresAt).getTime()>this.now()):r}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async deleteToken(e,t,r){return this.storage.deleteTokenByProviderEmail(e,t,r)}async cleanupExpiredTokens(){return this.storage.deleteExpiredTokens()}async cleanupExpiredStates(){return this.storage.cleanupExpiredStates()}isTokenExpired(e,t={}){let{expirationBuffer:r=300}=t;if(e.createdAt&&e.expiresIn!==void 0){let i=e.createdAt+e.expiresIn*1e3;return this.now()+r*1e3>=i}let o=new Date(e.expiresAt).getTime();return this.now()+r*1e3>=o}detectProviderType(e,t){var o;let r=t.authorizationUrl.toLowerCase();return r.includes("accounts.google.com")?"google":r.includes("github.com")?"github":r.includes("facebook.com")?"facebook":r.includes("microsoft.com")||r.includes("microsoftonline.com")?e.toLowerCase().includes("outlook")||(o=t.scopes)!=null&&o.some(n=>n.includes("outlook"))?"outlook":"microsoft":"generic"}async refreshTokensIfNeeded(e){let t=e.map(async r=>{if(this.shouldRefreshToken(r))try{let o=this.providers.get(r.provider);if(!o)return console.warn(`Provider ${r.provider} not found for token refresh`),r;if(!r.token.refreshToken)return console.warn(`No refresh token available for ${r.provider}:${r.email}`),r;let n=await o.refreshToken(r.token.refreshToken);return await this.storage.updateToken(r.id,{token:n})||r}catch(o){return this.autoRefreshOptions.onRefreshError&&this.autoRefreshOptions.onRefreshError(o,r),console.error(`Failed to refresh token for ${r.provider}:${r.email}:`,o),r}return r});return Promise.all(t)}shouldRefreshToken(e){if(!e.token.refreshToken)return false;let t=new Date(e.token.expiresAt).getTime(),r=this.now();if(r>=t)return true;let o=this.autoRefreshOptions.refreshBuffer*60*1e3,n=t-o;return r>=n}updateAutoRefreshOptions(e){this.autoRefreshOptions={...this.autoRefreshOptions,...e};}async getTokensAcrossTenants(e,t){return this.queryTokens({provider:e,userId:t})}async getTenants(e,t){let o=(await this.queryTokens({provider:e,email:t})).map(n=>n.tenant).filter(n=>n!==void 0);return [...new Set(o)]}async getTokenByTenantName(e,t,r){return (await this.queryTokens({provider:e,email:t})).find(n=>n.tenantName===r)||null}async hasTokenForTenant(e,t,r){return await this.storage.getToken(e,t,r)!==null}async getMultiTenantTokens(e,t){return (await this.queryTokens({provider:e,email:t})).map(o=>({token:o,tenant:o.tenant,tenantName:o.tenantName}))}};var ye=(s,e)=>ironSession.sealData(s,{password:e}),ve=(s,e)=>ironSession.unsealData(s,{password:e});
|
|
2
|
+
exports.BaseProfileFetcher=u;exports.GenericOAuth2Provider=A;exports.GenericProfileFetcher=h;exports.GitHubProfileFetcher=w;exports.GoogleProfileFetcher=S;exports.InMemoryStorageAdapter=T;exports.MicrosoftProfileFetcher=U;exports.OAuth2Client=F;exports.OAuth2Provider=k;exports.ProfileFetcherFactory=E;exports.StandardAuthorizationUrlStrategy=v;exports.StandardTokenExchangeStrategy=x;exports.createCodeChallenge=_;exports.createCodeVerifier=z;exports.generateState=I;exports.seal=ye;exports.unseal=ve;//# sourceMappingURL=index.cjs.map
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/strategies/standard-authorization-url.strategy.ts","../src/strategies/standard-token-exchange.strategy.ts","../src/providers/base.provider.ts","../src/providers/generic.provider.ts","../src/profile/base-profile-fetcher.ts","../src/profile/google-profile-fetcher.ts","../src/profile/github-profile-fetcher.ts","../src/profile/microsoft-profile-fetcher.ts","../src/profile/generic-profile-fetcher.ts","../src/profile/profile-fetcher-factory.ts","../src/providers/provider.factory.ts","../src/storage/memory.adapter.ts","../src/utils/crypto.ts","../src/facade/oauth2.facade.ts","../src/utils/seal.ts"],"names":["StandardAuthorizationUrlStrategy","params","value","key","config","state","codeChallenge","extraParams","StandardTokenExchangeStrategy","code","codeVerifier","response","errorText","data","tokenData","now","expiresIn","refreshToken","OAuth2Provider","authUrlStrategy","tokenStrategy","profileFetcher","accessToken","GenericOAuth2Provider","BaseProfileFetcher","profileEndpoint","rawData","GoogleProfileFetcher","GitHubProfileFetcher","_a","MicrosoftProfileFetcher","GenericProfileFetcher","mapping","additionalHeaders","obj","path","current","ProfileFetcherFactory","providerType","options","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","presetConfig","mergedConfig","name","InMemoryStorageAdapter","input","existingToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","token","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","_b","_c","customFetcher","authUrl","authState","_d","_e","providerInstance","tenantName","profile","error","savedToken","storedToken","tenantInfo","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData"],"mappings":"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","file":"index.cjs","sourcesContent":["import { OAuth2Config } from '../types';\nimport { AuthorizationUrlStrategy } from './authorization-url.strategy';\n\nexport class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n generateAuthorizationUrl(config: OAuth2Config, state: string, codeChallenge?: string): string {\n const params: Record<string, string | undefined> = {\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n response_type: 'code',\n scope: config.scopes.join(' '),\n state,\n };\n\n // Add PKCE parameters\n if ((config.usePKCE || config.pkce) && codeChallenge) {\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Merge additional parameters (for both additionalParams and extraAuthParams)\n const extraParams = {\n ...config.additionalParams,\n ...config.extraAuthParams,\n };\n\n Object.assign(params, extraParams);\n\n return `${config.authorizationUrl}?${this.buildUrlParams(params)}`;\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\nimport { TokenExchangeStrategy } from './token-exchange.strategy';\n\nexport class StandardTokenExchangeStrategy implements TokenExchangeStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n async exchangeCodeForToken(\n code: string,\n config: OAuth2Config,\n codeVerifier?: string,\n ): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n };\n\n // Handle PKCE\n if ((config.usePKCE || config.pkce) && codeVerifier) {\n params.code_verifier = codeVerifier;\n } else if (config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n\n // Handle nested response (e.g., Outlook might nest tokens)\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n const now = Date.now();\n const expiresIn = tokenData.expires_in || 3600;\n\n return {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token,\n expiresAt: new Date(now + expiresIn * 1000),\n expiresIn: expiresIn,\n tokenType: tokenData.token_type || 'Bearer',\n scope: tokenData.scope,\n createdAt: now,\n raw: data,\n };\n }\n\n async refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.clientId,\n };\n\n // Only add client_secret if not using PKCE\n if (!(config.usePKCE || config.pkce) && config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n const now = Date.now();\n const expiresIn = tokenData.expires_in || 3600;\n\n return {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token || refreshToken,\n expiresAt: new Date(now + expiresIn * 1000),\n expiresIn: expiresIn,\n tokenType: tokenData.token_type || 'Bearer',\n scope: tokenData.scope,\n createdAt: now,\n raw: data,\n };\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\n\nimport { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { UserProfile } from './interfaces/profile-fetcher.interface';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport abstract class OAuth2Provider {\n protected authUrlStrategy: AuthorizationUrlStrategy;\n protected tokenStrategy: TokenExchangeStrategy;\n protected profileFetcher?: BaseProfileFetcher;\n\n constructor(\n protected config: OAuth2Config,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n this.authUrlStrategy = authUrlStrategy || this.createAuthorizationUrlStrategy();\n this.tokenStrategy = tokenStrategy || this.createTokenExchangeStrategy();\n this.profileFetcher = profileFetcher;\n }\n\n // Factory methods\n protected abstract createAuthorizationUrlStrategy(): AuthorizationUrlStrategy;\n protected abstract createTokenExchangeStrategy(): TokenExchangeStrategy;\n\n // Profile fetching methods\n async fetchProfile(accessToken: string): Promise<UserProfile> {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.fetchUserInfo(accessToken);\n }\n\n getProfileEndpoint(): string {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.getEndpoint();\n }\n\n setProfileFetcher(profileFetcher: BaseProfileFetcher): void {\n this.profileFetcher = profileFetcher;\n }\n\n hasProfileFetcher(): boolean {\n return !!this.profileFetcher;\n }\n\n generateAuthorizationUrl(state: string, codeChallenge?: string): string {\n return this.authUrlStrategy.generateAuthorizationUrl(this.config, state, codeChallenge);\n }\n\n async exchangeCodeForToken(code: string, codeVerifier?: string): Promise<OAuth2Token> {\n return this.tokenStrategy.exchangeCodeForToken(code, this.config, codeVerifier);\n }\n\n async refreshToken(refreshToken: string): Promise<OAuth2Token> {\n return this.tokenStrategy.refreshToken(refreshToken, this.config);\n }\n}\n","import { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { StandardAuthorizationUrlStrategy } from '../strategies/standard-authorization-url.strategy';\nimport { StandardTokenExchangeStrategy } from '../strategies/standard-token-exchange.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { OAuth2Provider } from './base.provider';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class GenericOAuth2Provider extends OAuth2Provider {\n constructor(\n config: any,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n super(config, authUrlStrategy, tokenStrategy, profileFetcher);\n }\n\n protected createAuthorizationUrlStrategy(): AuthorizationUrlStrategy {\n return new StandardAuthorizationUrlStrategy();\n }\n\n protected createTokenExchangeStrategy(): TokenExchangeStrategy {\n return new StandardTokenExchangeStrategy();\n }\n}\n","import { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport abstract class BaseProfileFetcher {\n constructor(protected profileEndpoint: string) {}\n\n /**\n * Fetch user profile information from the OAuth provider\n * @param accessToken The OAuth access token\n * @returns Promise resolving to standardized user profile\n */\n async fetchUserInfo(accessToken: string): Promise<UserProfile> {\n const response = await fetch(this.profileEndpoint, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n ...this.getAdditionalHeaders(),\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch profile from ${this.profileEndpoint}: ${response.statusText}`,\n );\n }\n\n const rawData = await response.json();\n return this.mapToUserProfile(rawData);\n }\n\n /**\n * Map the raw API response to our standardized UserProfile structure\n * Override this method to customize mapping for different providers\n */\n protected abstract mapToUserProfile(rawData: any): UserProfile;\n\n /**\n * Get additional headers if needed for the profile request\n * Override this method to add provider-specific headers\n */\n protected getAdditionalHeaders(): Record<string, string> {\n return {};\n }\n\n /**\n * Get the profile endpoint URL\n */\n getEndpoint(): string {\n return this.profileEndpoint;\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GoogleProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://www.googleapis.com/oauth2/v2/userinfo');\n }\n\n mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name,\n id: rawData.id,\n avatar: rawData.picture,\n username: rawData.email,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GitHubProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://api.github.com/user');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name || rawData.login,\n id: rawData.id?.toString(),\n avatar: rawData.avatar_url,\n username: rawData.login,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return {\n 'User-Agent': 'OAuth2-Token-Manager', // GitHub requires User-Agent\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class MicrosoftProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://graph.microsoft.com/v1.0/me');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.mail || rawData.userPrincipalName,\n name: rawData.displayName,\n id: rawData.id,\n avatar: undefined, // Microsoft Graph doesn't include avatar in basic profile\n username: rawData.userPrincipalName,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface ProfileMapping {\n email: string;\n name?: string;\n id?: string;\n avatar?: string;\n username?: string;\n}\n\nexport class GenericProfileFetcher extends BaseProfileFetcher {\n constructor(\n profileEndpoint: string,\n private mapping?: ProfileMapping,\n private additionalHeaders?: Record<string, string>,\n ) {\n super(profileEndpoint);\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n if (this.mapping) {\n return {\n email: this.getNestedProperty(rawData, this.mapping.email),\n name: this.mapping.name ? this.getNestedProperty(rawData, this.mapping.name) : undefined,\n id: this.mapping.id ? this.getNestedProperty(rawData, this.mapping.id) : undefined,\n avatar: this.mapping.avatar\n ? this.getNestedProperty(rawData, this.mapping.avatar)\n : undefined,\n username: this.mapping.username\n ? this.getNestedProperty(rawData, this.mapping.username)\n : undefined,\n raw: rawData,\n };\n }\n\n // Default generic mapping\n return {\n email: rawData.email || rawData.mail || rawData.emailAddress,\n name: rawData.name || rawData.displayName || rawData.full_name,\n id: rawData.id || rawData.sub || rawData.user_id,\n avatar: rawData.avatar || rawData.picture || rawData.avatar_url,\n username: rawData.username || rawData.login || rawData.preferred_username,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return this.additionalHeaders || {};\n }\n\n private getNestedProperty(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { GoogleProfileFetcher } from './google-profile-fetcher';\nimport { GitHubProfileFetcher } from './github-profile-fetcher';\nimport { MicrosoftProfileFetcher } from './microsoft-profile-fetcher';\nimport { GenericProfileFetcher, ProfileMapping } from './generic-profile-fetcher';\nimport { ProviderType } from '../providers/provider.factory';\nimport { OAuth2Config } from '../types';\n\nexport interface ProfileFetcherOptions {\n profileUrl?: string;\n profileMapping?: ProfileMapping;\n profileHeaders?: Record<string, string>;\n}\n\nexport class ProfileFetcherFactory {\n static createProfileFetcher(\n providerType: ProviderType,\n config: OAuth2Config,\n options?: ProfileFetcherOptions,\n ): BaseProfileFetcher {\n // If custom options are provided, use GenericProfileFetcher\n if (options?.profileUrl) {\n return new GenericProfileFetcher(\n options.profileUrl,\n options.profileMapping,\n options.profileHeaders,\n );\n }\n\n // Use provider-specific fetchers for known providers\n switch (providerType) {\n case 'google':\n return new GoogleProfileFetcher();\n case 'github':\n return new GitHubProfileFetcher();\n case 'microsoft':\n case 'outlook':\n return new MicrosoftProfileFetcher();\n case 'facebook':\n return new GenericProfileFetcher(\n 'https://graph.facebook.com/me?fields=id,name,email,picture',\n );\n case 'generic':\n default:\n // For generic providers, use the profileUrl from config\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n throw new Error(`Profile URL must be provided for ${providerType} provider`);\n }\n return new GenericProfileFetcher(profileUrl);\n }\n }\n\n static registerCustomProfileFetcher(\n providerName: string,\n profileFetcher: BaseProfileFetcher,\n ): void {\n // Store custom profile fetchers for later use\n this.customFetchers.set(providerName, profileFetcher);\n }\n\n private static customFetchers = new Map<string, BaseProfileFetcher>();\n\n static getCustomProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.customFetchers.get(providerName);\n }\n}\n","import { OAuth2Config } from '../types';\nimport { OAuth2Provider } from './base.provider';\nimport { GenericOAuth2Provider } from './generic.provider';\nimport { ProfileFetcherFactory } from '../profile/profile-fetcher-factory';\n\nexport type ProviderType = 'google' | 'github' | 'microsoft' | 'outlook' | 'facebook' | 'generic';\n\nexport interface ProviderFactory {\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider;\n}\n\nexport class OAuth2ProviderFactory implements ProviderFactory {\n private static presetConfigs: Record<string, Partial<OAuth2Config>> = {\n google: {\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n profileUrl: 'https://www.googleapis.com/oauth2/v2/userinfo',\n usePKCE: true,\n extraAuthParams: {\n access_type: 'offline',\n prompt: 'consent',\n },\n },\n github: {\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n profileUrl: 'https://api.github.com/user',\n },\n microsoft: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n },\n outlook: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n extraAuthParams: {\n prompt: 'select_account',\n },\n },\n facebook: {\n authorizationUrl: 'https://www.facebook.com/v12.0/dialog/oauth',\n tokenUrl: 'https://graph.facebook.com/v12.0/oauth/access_token',\n profileUrl: 'https://graph.facebook.com/me?fields=id,name,email,picture',\n },\n };\n\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider {\n const presetConfig = type !== 'generic' ? OAuth2ProviderFactory.presetConfigs[type] || {} : {};\n\n // Only override preset values if the user explicitly provides them (not empty strings)\n const mergedConfig: OAuth2Config = {\n ...presetConfig,\n ...config,\n // Don't override preset URLs with empty strings\n authorizationUrl: config.authorizationUrl || presetConfig.authorizationUrl || '',\n tokenUrl: config.tokenUrl || presetConfig.tokenUrl || '',\n profileUrl: config.profileUrl || presetConfig.profileUrl,\n extraAuthParams: {\n ...(presetConfig.extraAuthParams || {}),\n ...(config.extraAuthParams || {}),\n },\n };\n\n const profileFetcher = ProfileFetcherFactory.createProfileFetcher(type, mergedConfig);\n\n return new GenericOAuth2Provider(mergedConfig, undefined, undefined, profileFetcher);\n }\n\n static registerPreset(name: string, config: Partial<OAuth2Config>): void {\n OAuth2ProviderFactory.presetConfigs[name] = config;\n }\n\n static getPresetConfig(name: string): Partial<OAuth2Config> | undefined {\n return OAuth2ProviderFactory.presetConfigs[name];\n }\n}\n","import { AuthorizationState } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class InMemoryStorageAdapter implements StorageAdapter {\n private tokens: Map<string, StoredToken> = new Map();\n private states: Map<string, AuthorizationState> = new Map();\n private profileFetchers: Map<string, BaseProfileFetcher> = new Map();\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n const existingToken = await this.getToken(input.provider, input.email, input.tenant);\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...input,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n return updatedToken;\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...input,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n return newToken;\n }\n\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n let tokens = Array.from(this.tokens.values());\n\n // Apply filters\n if (query.id) {\n tokens = tokens.filter((t) => t.id === query.id);\n }\n if (query.provider) {\n tokens = tokens.filter((t) => t.provider === query.provider);\n }\n if (query.userId) {\n tokens = tokens.filter((t) => t.userId === query.userId);\n }\n if (query.email) {\n tokens = tokens.filter((t) => t.email === query.email);\n }\n if (query.tenant !== undefined) {\n tokens = tokens.filter((t) => t.tenant === query.tenant);\n }\n\n // Filter out expired tokens unless explicitly requested\n if (!query.includeExpired) {\n const now = new Date().getTime();\n tokens = tokens.filter((t) => {\n const expiresAt = new Date(t.token.expiresAt).getTime();\n return expiresAt >= now;\n });\n }\n\n // Apply pagination\n if (query.offset !== undefined) {\n tokens = tokens.slice(query.offset);\n }\n if (query.limit !== undefined) {\n tokens = tokens.slice(0, query.limit);\n }\n\n return tokens;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ provider, email, tenant, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ id, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n async getTokensByProvider(provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider });\n }\n\n async getAccounts(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async getTokensForEmail(\n userId: string,\n provider: string,\n email: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokens({ userId, provider, email });\n return results[0] || null;\n }\n\n async getTokens(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async updateToken(id: string, update: UpdateTokenInput): Promise<StoredToken | null> {\n const token = this.tokens.get(id);\n if (!token) return null;\n\n const updatedToken: StoredToken = {\n ...token,\n ...(update.token && { token: update.token }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n return updatedToken;\n }\n\n async deleteToken(id: string): Promise<boolean> {\n return this.tokens.delete(id);\n }\n\n async deleteTokenByProviderEmail(provider: string, email: string, tenant?: string): Promise<boolean> {\n const token = await this.getToken(provider, email, tenant);\n if (!token) return false;\n return this.tokens.delete(token.id);\n }\n\n async deleteExpiredTokens(): Promise<number> {\n const now = new Date().getTime();\n const expiredTokens = Array.from(this.tokens.entries())\n .filter(([, token]) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt < now;\n })\n .map(([id]) => id);\n\n expiredTokens.forEach((id) => this.tokens.delete(id));\n return expiredTokens.length;\n }\n\n // Authorization state operations\n async saveAuthorizationState(\n state: Omit<AuthorizationState, 'createdAt'>,\n ): Promise<AuthorizationState> {\n const newState: AuthorizationState = {\n ...state,\n createdAt: new Date(Date.now()),\n };\n this.states.set(state.state, newState);\n return newState;\n }\n\n async getAuthorizationState(state: string): Promise<AuthorizationState | null> {\n return this.states.get(state) || null;\n }\n\n async deleteAuthorizationState(state: string): Promise<boolean> {\n return this.states.delete(state);\n }\n\n async cleanupExpiredStates(): Promise<number> {\n const now = new Date().getTime();\n const maxAge = 10 * 60 * 1000; // 10 minutes\n\n const expiredStates = Array.from(this.states.entries())\n .filter(([, state]) => {\n const stateAge = now - state.createdAt.getTime();\n return stateAge > maxAge;\n })\n .map(([key]) => key);\n\n expiredStates.forEach((key) => this.states.delete(key));\n return expiredStates.length;\n }\n\n // Profile fetcher operations\n registerProfileFetcher(providerName: string, fetcher: BaseProfileFetcher): void {\n this.profileFetchers.set(providerName, fetcher);\n }\n\n getProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.profileFetchers.get(providerName);\n }\n\n getProfileFetchers(): Map<string, BaseProfileFetcher> {\n return new Map(this.profileFetchers);\n }\n}\n","import { createHash, randomBytes } from 'crypto';\n\nexport const createCodeVerifier = () =>\n randomBytes(32)\n .toString('base64')\n .replace(/[^a-zA-Z0-9]/g, '')\n .substring(0, 128);\n\nexport const createCodeChallenge = (verifier: string): string => {\n return createHash('sha256').update(verifier).digest('base64url');\n};\n\nexport const generateState = (): string => {\n return randomBytes(16).toString('base64url');\n};\n","import { OAuth2Config, OAuth2Token, AuthorizationState } from '../types';\nimport { OAuth2ProviderFactory, ProviderType } from '../providers/provider.factory';\nimport { StorageAdapter, StoredToken, TokenQuery } from '../storage/interfaces';\nimport { InMemoryStorageAdapter } from '../storage/memory.adapter';\nimport { ProviderFactory } from '../providers/provider.factory';\nimport { createCodeVerifier, createCodeChallenge, generateState } from '../utils/crypto';\nimport { OAuth2Provider } from '../providers/base.provider';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface OAuth2Options {\n storage?: StorageAdapter;\n providers?: Record<string, OAuth2Config>;\n autoRefresh?: AutoRefreshOptions;\n}\n\nexport interface AutoRefreshOptions {\n enabled?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n onRefreshError?: (error: Error, token: StoredToken) => void;\n}\n\nexport interface AuthorizationOptions {\n provider: string;\n userId: string;\n email: string;\n tenant?: string; // For multi-tenant providers like Slack\n tenantName?: string; // Human-readable tenant name\n scopes?: string[];\n metadata?: Record<string, any>;\n usePKCE?: boolean;\n}\n\nexport interface TokenOptions {\n autoRefresh?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n expirationBuffer?: number; // seconds before expiry to consider expired\n defaultExpiresIn?: number; // default expiration in seconds\n}\n\nexport interface CallbackResult {\n token: StoredToken;\n profile?: UserProfile;\n}\n\nexport class OAuth2Client {\n private storage: StorageAdapter;\n private providerFactory: ProviderFactory;\n private providers: Map<string, OAuth2Provider> = new Map();\n private providerConfigs: Map<string, OAuth2Config> = new Map();\n private now: () => number;\n private autoRefreshOptions: AutoRefreshOptions;\n\n constructor(options: OAuth2Options = {}) {\n this.storage = options.storage || new InMemoryStorageAdapter();\n this.providerFactory = new OAuth2ProviderFactory();\n this.now = Date.now;\n\n // Set default auto-refresh options - enabled by default\n this.autoRefreshOptions = {\n enabled: options.autoRefresh?.enabled ?? true, // Enabled by default\n refreshBuffer: options.autoRefresh?.refreshBuffer ?? 10, // 10 minutes before expiry (safe for Google's 1-hour tokens)\n onRefreshError: options.autoRefresh?.onRefreshError,\n };\n\n // Register predefined providers\n if (options.providers) {\n Object.entries(options.providers).forEach(([name, config]) => {\n this.registerProvider(name, config);\n });\n }\n }\n\n /**\n * Register a provider configuration\n */\n registerProvider(name: string, config: OAuth2Config): void {\n this.providerConfigs.set(name, config);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config);\n\n // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n if (customFetcher) {\n provider.setProfileFetcher(customFetcher);\n }\n\n this.providers.set(name, provider);\n }\n\n /**\n * Start OAuth2 authorization flow\n */\n async authorize(options: AuthorizationOptions): Promise<{ url: string; state: string }> {\n const provider = this.providers.get(options.provider);\n if (!provider) throw new Error(`Provider ${options.provider} not found`);\n\n const state = generateState();\n let authUrl: string;\n let authState: Omit<AuthorizationState, 'createdAt'>;\n\n const requiresPKCE = this.providerConfigs.get(options.provider)?.usePKCE || options.usePKCE;\n\n if (requiresPKCE) {\n const codeVerifier = createCodeVerifier();\n const codeChallenge = createCodeChallenge(codeVerifier);\n authUrl = provider.generateAuthorizationUrl(state, codeChallenge);\n authState = {\n state,\n codeVerifier,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n } else {\n authUrl = provider.generateAuthorizationUrl(state);\n authState = {\n state,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n }\n\n await this.storage.saveAuthorizationState(authState);\n return { url: authUrl, state };\n }\n\n /**\n * Handle OAuth2 callback\n */\n async handleCallback(code: string, state: string): Promise<CallbackResult> {\n const authState = await this.storage.getAuthorizationState(state);\n if (!authState) throw new Error('Invalid or expired state');\n\n const provider = authState.metadata?.provider;\n if (!provider) throw new Error('Provider not found in authorization state');\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n // Exchange code for tokens\n const tokens = await providerInstance.exchangeCodeForToken(code, authState.codeVerifier);\n\n // Extract user data from metadata\n const userId = authState.metadata?.userId;\n const email = authState.metadata?.email;\n const tenant = authState.metadata?.tenant;\n const tenantName = authState.metadata?.tenantName;\n\n if (!userId || !email) {\n throw new Error('User ID and email are required in authorization state');\n }\n\n // Fetch profile if available\n let profile: UserProfile | undefined;\n if (providerInstance.hasProfileFetcher()) {\n try {\n profile = await providerInstance.fetchProfile(tokens.accessToken);\n } catch (error) {\n console.warn('Failed to fetch user profile:', error);\n }\n }\n\n // Save token\n const savedToken = await this.storage.saveToken({\n provider,\n userId,\n email: profile?.email || email,\n tenant,\n tenantName,\n token: tokens,\n metadata: {\n ...authState.metadata,\n profileFetched: !!profile,\n },\n });\n\n // Clean up authorization state\n await this.storage.deleteAuthorizationState(state);\n\n // Call onSuccess callback if defined\n const config = this.providerConfigs.get(provider);\n if (config?.onSuccess) {\n await config.onSuccess(userId, tokens);\n }\n\n return {\n token: savedToken,\n profile,\n };\n }\n\n /**\n * Get a valid access token (auto-refresh if needed)\n */\n async getAccessToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<string> {\n const token = await this.getValidToken(provider, email, options);\n return token.accessToken;\n }\n\n /**\n * Get a valid token (auto-refresh if needed)\n */\n async getValidToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<OAuth2Token> {\n const storedToken = await this.storage.getToken(provider, email, options.tenant);\n if (!storedToken) {\n const tenantInfo = options.tenant ? ` and tenant ${options.tenant}` : '';\n throw new Error(`No token found for provider ${provider}, email ${email}${tenantInfo}`);\n }\n\n const needsRefresh =\n options.autoRefresh !== false && this.isTokenExpired(storedToken.token, options);\n\n if (!needsRefresh) {\n return storedToken.token;\n }\n\n // Refresh the token\n if (!storedToken.token.refreshToken) {\n throw new Error('Token expired and no refresh token available');\n }\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n const newToken = await providerInstance.refreshToken(storedToken.token.refreshToken);\n await this.storage.updateToken(storedToken.id, { token: newToken });\n\n return newToken;\n }\n\n /**\n * Query tokens with automatic refresh\n */\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n // When auto-refresh is enabled, we need to include expired tokens\n // so we can attempt to refresh them\n const queryWithExpired =\n this.autoRefreshOptions.enabled && !query.includeExpired\n ? { ...query, includeExpired: true }\n : query;\n\n const tokens = await this.storage.queryTokens(queryWithExpired);\n\n if (this.autoRefreshOptions.enabled && !query.includeExpired) {\n const refreshedTokens = await this.refreshTokensIfNeeded(tokens);\n // Filter out tokens that are still expired after refresh attempt\n return refreshedTokens.filter((token) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt > this.now();\n });\n }\n\n return tokens;\n }\n\n /**\n * Get all tokens for a user\n */\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n /**\n * Get all tokens for an email\n */\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n /**\n * Delete a token\n */\n async deleteToken(provider: string, email: string, tenant?: string): Promise<boolean> {\n return this.storage.deleteTokenByProviderEmail(provider, email, tenant);\n }\n\n /**\n * Delete all expired tokens\n */\n async cleanupExpiredTokens(): Promise<number> {\n return this.storage.deleteExpiredTokens();\n }\n\n /**\n * Clean up expired authorization states\n */\n async cleanupExpiredStates(): Promise<number> {\n return this.storage.cleanupExpiredStates();\n }\n\n // Helper methods\n private isTokenExpired(token: OAuth2Token, options: TokenOptions = {}): boolean {\n const { expirationBuffer = 300 } = options;\n\n if (token.createdAt && token.expiresIn !== undefined) {\n const expiresAt = token.createdAt + token.expiresIn * 1000;\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n const expiresAt = new Date(token.expiresAt).getTime();\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n private detectProviderType(name: string, config: OAuth2Config): ProviderType {\n // Try to detect based on the authorization URL\n const authUrl = config.authorizationUrl.toLowerCase();\n\n // Check for known providers that have specific implementations\n if (authUrl.includes('accounts.google.com')) return 'google';\n if (authUrl.includes('github.com')) return 'github';\n if (authUrl.includes('facebook.com')) return 'facebook';\n if (authUrl.includes('microsoft.com') || authUrl.includes('microsoftonline.com')) {\n // Check if it's specifically for Outlook\n if (\n name.toLowerCase().includes('outlook') ||\n config.scopes?.some((s) => s.includes('outlook'))\n ) {\n return 'outlook';\n }\n return 'microsoft';\n }\n\n // Default to generic provider for all others\n return 'generic';\n }\n\n /**\n * Refresh tokens if they are near expiration\n */\n private async refreshTokensIfNeeded(tokens: StoredToken[]): Promise<StoredToken[]> {\n const refreshPromises = tokens.map(async (token) => {\n if (this.shouldRefreshToken(token)) {\n try {\n const provider = this.providers.get(token.provider);\n if (!provider) {\n console.warn(`Provider ${token.provider} not found for token refresh`);\n return token;\n }\n\n if (!token.token.refreshToken) {\n console.warn(`No refresh token available for ${token.provider}:${token.email}`);\n return token;\n }\n\n const newToken = await provider.refreshToken(token.token.refreshToken);\n const updated = await this.storage.updateToken(token.id, { token: newToken });\n return updated || token;\n } catch (error) {\n if (this.autoRefreshOptions.onRefreshError) {\n this.autoRefreshOptions.onRefreshError(error as Error, token);\n }\n console.error(`Failed to refresh token for ${token.provider}:${token.email}:`, error);\n return token;\n }\n }\n return token;\n });\n\n return Promise.all(refreshPromises);\n }\n\n /**\n * Check if a token should be refreshed\n */\n private shouldRefreshToken(storedToken: StoredToken): boolean {\n // Skip if no refresh token\n if (!storedToken.token.refreshToken) {\n return false;\n }\n\n // Check if token is expired or near expiration\n const expiresAt = new Date(storedToken.token.expiresAt).getTime();\n const now = this.now();\n\n // If already expired, definitely try to refresh\n if (now >= expiresAt) {\n return true;\n }\n\n // Otherwise, check if within refresh buffer\n const bufferMs = this.autoRefreshOptions.refreshBuffer! * 60 * 1000;\n const shouldRefreshAt = expiresAt - bufferMs;\n\n return now >= shouldRefreshAt;\n }\n\n /**\n * Update auto-refresh options\n */\n updateAutoRefreshOptions(options: Partial<AutoRefreshOptions>): void {\n this.autoRefreshOptions = { ...this.autoRefreshOptions, ...options };\n }\n\n /**\n * Get all tokens for a specific provider and user across all tenants\n */\n async getTokensAcrossTenants(provider: string, userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider, userId });\n }\n\n /**\n * Get all tenants for a specific provider and email\n */\n async getTenants(provider: string, email: string): Promise<string[]> {\n const tokens = await this.queryTokens({ provider, email });\n const tenants = tokens\n .map((t) => t.tenant)\n .filter((tenant): tenant is string => tenant !== undefined);\n return [...new Set(tenants)]; // Return unique tenants\n }\n\n /**\n * Get token by tenant name (useful for Slack workspaces with human-readable names)\n */\n async getTokenByTenantName(\n provider: string,\n email: string,\n tenantName: string,\n ): Promise<StoredToken | null> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.find((t) => t.tenantName === tenantName) || null;\n }\n\n /**\n * Check if a token exists for a specific tenant\n */\n async hasTokenForTenant(\n provider: string,\n email: string,\n tenant: string,\n ): Promise<boolean> {\n const token = await this.storage.getToken(provider, email, tenant);\n return token !== null;\n }\n\n /**\n * Get all tokens with their tenant information\n */\n async getMultiTenantTokens(\n provider: string,\n email: string,\n ): Promise<Array<{ token: StoredToken; tenant?: string; tenantName?: string }>> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.map((token) => ({\n token,\n tenant: token.tenant,\n tenantName: token.tenantName,\n }));\n }\n}\n","import { sealData, unsealData } from 'iron-session';\n\nexport const seal = <T>(d: T, key: string) => sealData(d, { password: key });\nexport const unseal = <T>(s: string, key: string) => unsealData<T>(s, { password: key });\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/strategies/standard-authorization-url.strategy.ts","../src/strategies/standard-token-exchange.strategy.ts","../src/providers/base.provider.ts","../src/providers/generic.provider.ts","../src/profile/base-profile-fetcher.ts","../src/profile/google-profile-fetcher.ts","../src/profile/github-profile-fetcher.ts","../src/profile/microsoft-profile-fetcher.ts","../src/profile/generic-profile-fetcher.ts","../src/profile/profile-fetcher-factory.ts","../src/providers/provider.factory.ts","../src/storage/memory.adapter.ts","../src/utils/crypto.ts","../src/facade/oauth2.facade.ts","../src/utils/seal.ts"],"names":["StandardAuthorizationUrlStrategy","params","value","key","config","state","codeChallenge","extraParams","StandardTokenExchangeStrategy","code","codeVerifier","response","errorText","data","tokenData","refreshToken","rawResponse","refreshTokenFallback","_a","_b","_c","_d","_e","now","accessToken","rawRefreshToken","rawExpiresIn","expiresInSeconds","scope","tokenType","obj","customPaths","defaultPaths","paths","path","keys","current","OAuth2Provider","authUrlStrategy","tokenStrategy","profileFetcher","GenericOAuth2Provider","BaseProfileFetcher","profileEndpoint","rawData","GoogleProfileFetcher","GitHubProfileFetcher","MicrosoftProfileFetcher","GenericProfileFetcher","mapping","additionalHeaders","ProfileFetcherFactory","providerType","options","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","presetConfig","mergedConfig","name","InMemoryStorageAdapter","input","existingToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","token","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","customFetcher","authUrl","authState","providerInstance","tenantName","profile","error","savedToken","storedToken","tenantInfo","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData"],"mappings":"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","file":"index.cjs","sourcesContent":["import { OAuth2Config } from '../types';\nimport { AuthorizationUrlStrategy } from './authorization-url.strategy';\n\nexport class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n generateAuthorizationUrl(config: OAuth2Config, state: string, codeChallenge?: string): string {\n const params: Record<string, string | undefined> = {\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n response_type: 'code',\n scope: config.scopes.join(' '),\n state,\n };\n\n // Add PKCE parameters\n if ((config.usePKCE || config.pkce) && codeChallenge) {\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Merge additional parameters (for both additionalParams and extraAuthParams)\n const extraParams = {\n ...config.additionalParams,\n ...config.extraAuthParams,\n };\n\n Object.assign(params, extraParams);\n\n return `${config.authorizationUrl}?${this.buildUrlParams(params)}`;\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\nimport { TokenExchangeStrategy } from './token-exchange.strategy';\n\nexport class StandardTokenExchangeStrategy implements TokenExchangeStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n async exchangeCodeForToken(\n code: string,\n config: OAuth2Config,\n codeVerifier?: string,\n ): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n };\n\n // Handle PKCE\n if ((config.usePKCE || config.pkce) && codeVerifier) {\n params.code_verifier = codeVerifier;\n } else if (config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n\n // Handle nested response (e.g., Outlook might nest tokens)\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n return this.normalizeTokenResponse(tokenData, data, undefined, config);\n }\n\n async refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.clientId,\n };\n\n // Only add client_secret if not using PKCE\n if (!(config.usePKCE || config.pkce) && config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n return this.normalizeTokenResponse(tokenData, data, refreshToken, config);\n }\n\n protected normalizeTokenResponse(\n tokenData: Record<string, any>,\n rawResponse: Record<string, any>,\n refreshTokenFallback?: string,\n config?: OAuth2Config,\n ): OAuth2Token {\n const now = Date.now();\n\n // Extract values using custom paths if provided, otherwise use defaults\n const accessToken = this.extractValue(\n tokenData,\n config?.tokenPaths?.accessToken,\n // Default paths: For providers like Slack that return both bot and user tokens,\n // prioritize the user token in authed_user over the root-level bot token\n [\n 'authed_user.access_token',\n 'authed_user.accessToken',\n 'access_token',\n 'accessToken',\n 'token.access_token',\n 'token.accessToken',\n ],\n );\n\n if (!accessToken) {\n throw new Error('Token response did not include an access_token');\n }\n\n const rawRefreshToken =\n this.extractValue(tokenData, config?.tokenPaths?.refreshToken, [\n 'authed_user.refresh_token',\n 'authed_user.refreshToken',\n 'refresh_token',\n 'refreshToken',\n 'token.refresh_token',\n 'token.refreshToken',\n ]) ?? refreshTokenFallback;\n\n const rawExpiresIn = this.extractValue(tokenData, config?.tokenPaths?.expiresIn, [\n 'authed_user.expires_in',\n 'authed_user.expiresIn',\n 'expires_in',\n 'expiresIn',\n 'token.expires_in',\n 'token.expiresIn',\n ]);\n\n const parsedExpiresIn =\n typeof rawExpiresIn === 'string' ? parseInt(rawExpiresIn, 10) : rawExpiresIn;\n\n const expiresInSeconds = parsedExpiresIn || 3600;\n\n const scope = this.extractValue(tokenData, config?.tokenPaths?.scope, [\n 'authed_user.scope',\n 'scope',\n 'token.scope',\n ]);\n\n const tokenType =\n this.extractValue(tokenData, config?.tokenPaths?.tokenType, [\n 'authed_user.token_type',\n 'authed_user.tokenType',\n 'token_type',\n 'tokenType',\n 'token.token_type',\n 'token.tokenType',\n ]) ?? 'Bearer';\n\n return {\n accessToken,\n refreshToken: rawRefreshToken,\n expiresAt: new Date(now + expiresInSeconds * 1000),\n expiresIn: expiresInSeconds,\n tokenType,\n scope,\n createdAt: now,\n raw: rawResponse,\n };\n }\n\n /**\n * Extract a value from a nested object using a dot-notation path\n * @param obj The object to extract from\n * @param customPaths Custom path(s) provided by config (takes priority)\n * @param defaultPaths Default fallback paths to try\n * @returns The extracted value or undefined\n */\n private extractValue(\n obj: Record<string, any>,\n customPaths?: string | string[],\n defaultPaths?: string[],\n ): any {\n // Try custom paths first if provided\n if (customPaths) {\n const paths = Array.isArray(customPaths) ? customPaths : [customPaths];\n for (const path of paths) {\n const value = this.getNestedValue(obj, path);\n if (value !== undefined) return value;\n }\n }\n\n // Fall back to default paths\n if (defaultPaths) {\n for (const path of defaultPaths) {\n const value = this.getNestedValue(obj, path);\n if (value !== undefined) return value;\n }\n }\n\n return undefined;\n }\n\n /**\n * Get a nested value from an object using dot notation (e.g., 'authed_user.access_token')\n * @param obj The object to traverse\n * @param path The dot-notation path\n * @returns The value at the path or undefined\n */\n private getNestedValue(obj: Record<string, any>, path: string): any {\n const keys = path.split('.');\n let current: any = obj;\n\n for (const key of keys) {\n if (current && typeof current === 'object' && key in current) {\n current = current[key];\n } else {\n return undefined;\n }\n }\n\n return current;\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\n\nimport { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { UserProfile } from './interfaces/profile-fetcher.interface';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport abstract class OAuth2Provider {\n protected authUrlStrategy: AuthorizationUrlStrategy;\n protected tokenStrategy: TokenExchangeStrategy;\n protected profileFetcher?: BaseProfileFetcher;\n\n constructor(\n protected config: OAuth2Config,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n this.authUrlStrategy = authUrlStrategy || this.createAuthorizationUrlStrategy();\n this.tokenStrategy = tokenStrategy || this.createTokenExchangeStrategy();\n this.profileFetcher = profileFetcher;\n }\n\n // Factory methods\n protected abstract createAuthorizationUrlStrategy(): AuthorizationUrlStrategy;\n protected abstract createTokenExchangeStrategy(): TokenExchangeStrategy;\n\n // Profile fetching methods\n async fetchProfile(accessToken: string): Promise<UserProfile> {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.fetchUserInfo(accessToken);\n }\n\n getProfileEndpoint(): string {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.getEndpoint();\n }\n\n setProfileFetcher(profileFetcher: BaseProfileFetcher): void {\n this.profileFetcher = profileFetcher;\n }\n\n hasProfileFetcher(): boolean {\n return !!this.profileFetcher;\n }\n\n generateAuthorizationUrl(state: string, codeChallenge?: string): string {\n return this.authUrlStrategy.generateAuthorizationUrl(this.config, state, codeChallenge);\n }\n\n async exchangeCodeForToken(code: string, codeVerifier?: string): Promise<OAuth2Token> {\n return this.tokenStrategy.exchangeCodeForToken(code, this.config, codeVerifier);\n }\n\n async refreshToken(refreshToken: string): Promise<OAuth2Token> {\n return this.tokenStrategy.refreshToken(refreshToken, this.config);\n }\n}\n","import { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { StandardAuthorizationUrlStrategy } from '../strategies/standard-authorization-url.strategy';\nimport { StandardTokenExchangeStrategy } from '../strategies/standard-token-exchange.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { OAuth2Provider } from './base.provider';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class GenericOAuth2Provider extends OAuth2Provider {\n constructor(\n config: any,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n super(config, authUrlStrategy, tokenStrategy, profileFetcher);\n }\n\n protected createAuthorizationUrlStrategy(): AuthorizationUrlStrategy {\n return new StandardAuthorizationUrlStrategy();\n }\n\n protected createTokenExchangeStrategy(): TokenExchangeStrategy {\n return new StandardTokenExchangeStrategy();\n }\n}\n","import { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport abstract class BaseProfileFetcher {\n constructor(protected profileEndpoint: string) {}\n\n /**\n * Fetch user profile information from the OAuth provider\n * @param accessToken The OAuth access token\n * @returns Promise resolving to standardized user profile\n */\n async fetchUserInfo(accessToken: string): Promise<UserProfile> {\n const response = await fetch(this.profileEndpoint, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n ...this.getAdditionalHeaders(),\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch profile from ${this.profileEndpoint}: ${response.statusText}`,\n );\n }\n\n const rawData = await response.json();\n return this.mapToUserProfile(rawData);\n }\n\n /**\n * Map the raw API response to our standardized UserProfile structure\n * Override this method to customize mapping for different providers\n * @param rawData The raw API response data\n * @returns UserProfile with optional tenant information\n */\n protected abstract mapToUserProfile(rawData: any): UserProfile;\n\n /**\n * Get additional headers if needed for the profile request\n * Override this method to add provider-specific headers\n */\n protected getAdditionalHeaders(): Record<string, string> {\n return {};\n }\n\n /**\n * Get the profile endpoint URL\n */\n getEndpoint(): string {\n return this.profileEndpoint;\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GoogleProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://www.googleapis.com/oauth2/v2/userinfo');\n }\n\n mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name,\n id: rawData.id,\n avatar: rawData.picture,\n username: rawData.email,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GitHubProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://api.github.com/user');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name || rawData.login,\n id: rawData.id?.toString(),\n avatar: rawData.avatar_url,\n username: rawData.login,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return {\n 'User-Agent': 'OAuth2-Token-Manager', // GitHub requires User-Agent\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class MicrosoftProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://graph.microsoft.com/v1.0/me');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.mail || rawData.userPrincipalName,\n name: rawData.displayName,\n id: rawData.id,\n avatar: undefined, // Microsoft Graph doesn't include avatar in basic profile\n username: rawData.userPrincipalName,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface ProfileMapping {\n email: string;\n name?: string;\n id?: string;\n avatar?: string;\n username?: string;\n tenant?: string; // Path to tenant/workspace ID in the raw data\n tenantName?: string; // Path to tenant/workspace name in the raw data\n}\n\nexport class GenericProfileFetcher extends BaseProfileFetcher {\n constructor(\n profileEndpoint: string,\n private mapping?: ProfileMapping,\n private additionalHeaders?: Record<string, string>,\n ) {\n super(profileEndpoint);\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n if (this.mapping) {\n return {\n email: this.getNestedProperty(rawData, this.mapping.email),\n name: this.mapping.name ? this.getNestedProperty(rawData, this.mapping.name) : undefined,\n id: this.mapping.id ? this.getNestedProperty(rawData, this.mapping.id) : undefined,\n avatar: this.mapping.avatar\n ? this.getNestedProperty(rawData, this.mapping.avatar)\n : undefined,\n username: this.mapping.username\n ? this.getNestedProperty(rawData, this.mapping.username)\n : undefined,\n tenant: this.mapping.tenant\n ? this.getNestedProperty(rawData, this.mapping.tenant)\n : undefined,\n tenantName: this.mapping.tenantName\n ? this.getNestedProperty(rawData, this.mapping.tenantName)\n : undefined,\n raw: rawData,\n };\n }\n\n // Default generic mapping\n return {\n email: rawData.email || rawData.mail || rawData.emailAddress,\n name: rawData.name || rawData.displayName || rawData.full_name,\n id: rawData.id || rawData.sub || rawData.user_id,\n avatar: rawData.avatar || rawData.picture || rawData.avatar_url,\n username: rawData.username || rawData.login || rawData.preferred_username,\n tenant: rawData.tenant || rawData.workspace_id || rawData.organization_id || rawData.team_id,\n tenantName:\n rawData.tenantName ||\n rawData.workspace_name ||\n rawData.organization_name ||\n rawData.team_name,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return this.additionalHeaders || {};\n }\n\n private getNestedProperty(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { GoogleProfileFetcher } from './google-profile-fetcher';\nimport { GitHubProfileFetcher } from './github-profile-fetcher';\nimport { MicrosoftProfileFetcher } from './microsoft-profile-fetcher';\nimport { GenericProfileFetcher, ProfileMapping } from './generic-profile-fetcher';\nimport { ProviderType } from '../providers/provider.factory';\nimport { OAuth2Config } from '../types';\n\nexport interface ProfileFetcherOptions {\n profileUrl?: string;\n profileMapping?: ProfileMapping;\n profileHeaders?: Record<string, string>;\n}\n\nexport class ProfileFetcherFactory {\n static createProfileFetcher(\n providerType: ProviderType,\n config: OAuth2Config,\n options?: ProfileFetcherOptions,\n ): BaseProfileFetcher {\n // If custom options are provided, use GenericProfileFetcher\n if (options?.profileUrl) {\n return new GenericProfileFetcher(\n options.profileUrl,\n options.profileMapping,\n options.profileHeaders,\n );\n }\n\n // Use provider-specific fetchers for known providers\n switch (providerType) {\n case 'google':\n return new GoogleProfileFetcher();\n case 'github':\n return new GitHubProfileFetcher();\n case 'microsoft':\n case 'outlook':\n return new MicrosoftProfileFetcher();\n case 'facebook':\n return new GenericProfileFetcher(\n 'https://graph.facebook.com/me?fields=id,name,email,picture',\n );\n case 'generic':\n default:\n // For generic providers, use the profileUrl from config\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n throw new Error(`Profile URL must be provided for ${providerType} provider`);\n }\n return new GenericProfileFetcher(profileUrl);\n }\n }\n\n static registerCustomProfileFetcher(\n providerName: string,\n profileFetcher: BaseProfileFetcher,\n ): void {\n // Store custom profile fetchers for later use\n this.customFetchers.set(providerName, profileFetcher);\n }\n\n private static customFetchers = new Map<string, BaseProfileFetcher>();\n\n static getCustomProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.customFetchers.get(providerName);\n }\n}\n","import { OAuth2Config } from '../types';\nimport { OAuth2Provider } from './base.provider';\nimport { GenericOAuth2Provider } from './generic.provider';\nimport { ProfileFetcherFactory } from '../profile/profile-fetcher-factory';\n\nexport type ProviderType = 'google' | 'github' | 'microsoft' | 'outlook' | 'facebook' | 'generic';\n\nexport interface ProviderFactory {\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider;\n}\n\nexport class OAuth2ProviderFactory implements ProviderFactory {\n private static presetConfigs: Record<string, Partial<OAuth2Config>> = {\n google: {\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n profileUrl: 'https://www.googleapis.com/oauth2/v2/userinfo',\n usePKCE: true,\n extraAuthParams: {\n access_type: 'offline',\n prompt: 'consent',\n },\n },\n github: {\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n profileUrl: 'https://api.github.com/user',\n },\n microsoft: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n },\n outlook: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n extraAuthParams: {\n prompt: 'select_account',\n },\n },\n facebook: {\n authorizationUrl: 'https://www.facebook.com/v12.0/dialog/oauth',\n tokenUrl: 'https://graph.facebook.com/v12.0/oauth/access_token',\n profileUrl: 'https://graph.facebook.com/me?fields=id,name,email,picture',\n },\n };\n\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider {\n const presetConfig = type !== 'generic' ? OAuth2ProviderFactory.presetConfigs[type] || {} : {};\n\n // Only override preset values if the user explicitly provides them (not empty strings)\n const mergedConfig: OAuth2Config = {\n ...presetConfig,\n ...config,\n // Don't override preset URLs with empty strings\n authorizationUrl: config.authorizationUrl || presetConfig.authorizationUrl || '',\n tokenUrl: config.tokenUrl || presetConfig.tokenUrl || '',\n profileUrl: config.profileUrl || presetConfig.profileUrl,\n extraAuthParams: {\n ...(presetConfig.extraAuthParams || {}),\n ...(config.extraAuthParams || {}),\n },\n };\n\n const profileFetcher = ProfileFetcherFactory.createProfileFetcher(type, mergedConfig);\n\n return new GenericOAuth2Provider(mergedConfig, undefined, undefined, profileFetcher);\n }\n\n static registerPreset(name: string, config: Partial<OAuth2Config>): void {\n OAuth2ProviderFactory.presetConfigs[name] = config;\n }\n\n static getPresetConfig(name: string): Partial<OAuth2Config> | undefined {\n return OAuth2ProviderFactory.presetConfigs[name];\n }\n}\n","import { AuthorizationState } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class InMemoryStorageAdapter implements StorageAdapter {\n private tokens: Map<string, StoredToken> = new Map();\n private states: Map<string, AuthorizationState> = new Map();\n private profileFetchers: Map<string, BaseProfileFetcher> = new Map();\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n const existingToken = await this.getToken(input.provider, input.email, input.tenant);\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...input,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n return updatedToken;\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...input,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n return newToken;\n }\n\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n let tokens = Array.from(this.tokens.values());\n\n // Apply filters\n if (query.id) {\n tokens = tokens.filter((t) => t.id === query.id);\n }\n if (query.provider) {\n tokens = tokens.filter((t) => t.provider === query.provider);\n }\n if (query.userId) {\n tokens = tokens.filter((t) => t.userId === query.userId);\n }\n if (query.email) {\n tokens = tokens.filter((t) => t.email === query.email);\n }\n if (query.tenant !== undefined) {\n tokens = tokens.filter((t) => t.tenant === query.tenant);\n }\n\n // Filter out expired tokens unless explicitly requested\n if (!query.includeExpired) {\n const now = new Date().getTime();\n tokens = tokens.filter((t) => {\n const expiresAt = new Date(t.token.expiresAt).getTime();\n return expiresAt >= now;\n });\n }\n\n // Apply pagination\n if (query.offset !== undefined) {\n tokens = tokens.slice(query.offset);\n }\n if (query.limit !== undefined) {\n tokens = tokens.slice(0, query.limit);\n }\n\n return tokens;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ provider, email, tenant, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ id, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n async getTokensByProvider(provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider });\n }\n\n async getAccounts(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async getTokensForEmail(\n userId: string,\n provider: string,\n email: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokens({ userId, provider, email });\n return results[0] || null;\n }\n\n async getTokens(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async updateToken(id: string, update: UpdateTokenInput): Promise<StoredToken | null> {\n const token = this.tokens.get(id);\n if (!token) return null;\n\n const updatedToken: StoredToken = {\n ...token,\n ...(update.token && { token: update.token }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n return updatedToken;\n }\n\n async deleteToken(id: string): Promise<boolean> {\n return this.tokens.delete(id);\n }\n\n async deleteTokenByProviderEmail(\n provider: string,\n email: string,\n tenant?: string,\n ): Promise<boolean> {\n const token = await this.getToken(provider, email, tenant);\n if (!token) return false;\n return this.tokens.delete(token.id);\n }\n\n async deleteExpiredTokens(): Promise<number> {\n const now = new Date().getTime();\n const expiredTokens = Array.from(this.tokens.entries())\n .filter(([, token]) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt < now;\n })\n .map(([id]) => id);\n\n expiredTokens.forEach((id) => this.tokens.delete(id));\n return expiredTokens.length;\n }\n\n // Authorization state operations\n async saveAuthorizationState(\n state: Omit<AuthorizationState, 'createdAt'>,\n ): Promise<AuthorizationState> {\n const newState: AuthorizationState = {\n ...state,\n createdAt: new Date(Date.now()),\n };\n this.states.set(state.state, newState);\n return newState;\n }\n\n async getAuthorizationState(state: string): Promise<AuthorizationState | null> {\n return this.states.get(state) || null;\n }\n\n async deleteAuthorizationState(state: string): Promise<boolean> {\n return this.states.delete(state);\n }\n\n async cleanupExpiredStates(): Promise<number> {\n const now = new Date().getTime();\n const maxAge = 10 * 60 * 1000; // 10 minutes\n\n const expiredStates = Array.from(this.states.entries())\n .filter(([, state]) => {\n const stateAge = now - state.createdAt.getTime();\n return stateAge > maxAge;\n })\n .map(([key]) => key);\n\n expiredStates.forEach((key) => this.states.delete(key));\n return expiredStates.length;\n }\n\n // Profile fetcher operations\n registerProfileFetcher(providerName: string, fetcher: BaseProfileFetcher): void {\n this.profileFetchers.set(providerName, fetcher);\n }\n\n getProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.profileFetchers.get(providerName);\n }\n\n getProfileFetchers(): Map<string, BaseProfileFetcher> {\n return new Map(this.profileFetchers);\n }\n}\n","import { createHash, randomBytes } from 'crypto';\n\nexport const createCodeVerifier = () =>\n randomBytes(32)\n .toString('base64')\n .replace(/[^a-zA-Z0-9]/g, '')\n .substring(0, 128);\n\nexport const createCodeChallenge = (verifier: string): string => {\n return createHash('sha256').update(verifier).digest('base64url');\n};\n\nexport const generateState = (): string => {\n return randomBytes(16).toString('base64url');\n};\n","import { OAuth2Config, OAuth2Token, AuthorizationState } from '../types';\nimport { OAuth2ProviderFactory, ProviderType } from '../providers/provider.factory';\nimport { StorageAdapter, StoredToken, TokenQuery } from '../storage/interfaces';\nimport { InMemoryStorageAdapter } from '../storage/memory.adapter';\nimport { ProviderFactory } from '../providers/provider.factory';\nimport { createCodeVerifier, createCodeChallenge, generateState } from '../utils/crypto';\nimport { OAuth2Provider } from '../providers/base.provider';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface OAuth2Options {\n storage?: StorageAdapter;\n providers?: Record<string, OAuth2Config>;\n autoRefresh?: AutoRefreshOptions;\n}\n\nexport interface AutoRefreshOptions {\n enabled?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n onRefreshError?: (error: Error, token: StoredToken) => void;\n}\n\nexport interface AuthorizationOptions {\n provider: string;\n userId: string;\n email: string;\n tenant?: string; // For multi-tenant providers like Slack\n tenantName?: string; // Human-readable tenant name\n scopes?: string[];\n metadata?: Record<string, any>;\n usePKCE?: boolean;\n}\n\nexport interface TokenOptions {\n autoRefresh?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n expirationBuffer?: number; // seconds before expiry to consider expired\n defaultExpiresIn?: number; // default expiration in seconds\n}\n\nexport interface CallbackResult {\n token: StoredToken;\n profile?: UserProfile;\n}\n\nexport class OAuth2Client {\n private storage: StorageAdapter;\n private providerFactory: ProviderFactory;\n private providers: Map<string, OAuth2Provider> = new Map();\n private providerConfigs: Map<string, OAuth2Config> = new Map();\n private now: () => number;\n private autoRefreshOptions: AutoRefreshOptions;\n\n constructor(options: OAuth2Options = {}) {\n this.storage = options.storage || new InMemoryStorageAdapter();\n this.providerFactory = new OAuth2ProviderFactory();\n this.now = Date.now;\n\n // Set default auto-refresh options - enabled by default\n this.autoRefreshOptions = {\n enabled: options.autoRefresh?.enabled ?? true, // Enabled by default\n refreshBuffer: options.autoRefresh?.refreshBuffer ?? 10, // 10 minutes before expiry (safe for Google's 1-hour tokens)\n onRefreshError: options.autoRefresh?.onRefreshError,\n };\n\n // Register predefined providers\n if (options.providers) {\n Object.entries(options.providers).forEach(([name, config]) => {\n this.registerProvider(name, config);\n });\n }\n }\n\n /**\n * Register a provider configuration\n */\n registerProvider(name: string, config: OAuth2Config): void {\n this.providerConfigs.set(name, config);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config);\n\n // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n if (customFetcher) {\n provider.setProfileFetcher(customFetcher);\n }\n\n this.providers.set(name, provider);\n }\n\n /**\n * Start OAuth2 authorization flow\n */\n async authorize(options: AuthorizationOptions): Promise<{ url: string; state: string }> {\n const provider = this.providers.get(options.provider);\n if (!provider) throw new Error(`Provider ${options.provider} not found`);\n\n const state = generateState();\n let authUrl: string;\n let authState: Omit<AuthorizationState, 'createdAt'>;\n\n const requiresPKCE = this.providerConfigs.get(options.provider)?.usePKCE || options.usePKCE;\n\n if (requiresPKCE) {\n const codeVerifier = createCodeVerifier();\n const codeChallenge = createCodeChallenge(codeVerifier);\n authUrl = provider.generateAuthorizationUrl(state, codeChallenge);\n authState = {\n state,\n codeVerifier,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n } else {\n authUrl = provider.generateAuthorizationUrl(state);\n authState = {\n state,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n }\n\n await this.storage.saveAuthorizationState(authState);\n return { url: authUrl, state };\n }\n\n /**\n * Handle OAuth2 callback\n */\n async handleCallback(code: string, state: string): Promise<CallbackResult> {\n const authState = await this.storage.getAuthorizationState(state);\n if (!authState) throw new Error('Invalid or expired state');\n\n const provider = authState.metadata?.provider;\n if (!provider) throw new Error('Provider not found in authorization state');\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n // Exchange code for tokens\n const tokens = await providerInstance.exchangeCodeForToken(code, authState.codeVerifier);\n\n // Extract user data from metadata\n const userId = authState.metadata?.userId;\n const email = authState.metadata?.email;\n const tenant = authState.metadata?.tenant;\n const tenantName = authState.metadata?.tenantName;\n\n if (!userId || !email) {\n throw new Error('User ID and email are required in authorization state');\n }\n\n // Fetch profile if available\n let profile: UserProfile | undefined;\n if (providerInstance.hasProfileFetcher()) {\n try {\n profile = await providerInstance.fetchProfile(tokens.accessToken);\n } catch (error) {\n console.warn('Failed to fetch user profile:', error);\n }\n }\n\n // Save token - use profile data if available, otherwise fall back to authorization state\n const savedToken = await this.storage.saveToken({\n provider,\n userId,\n email: profile?.email || email,\n tenant: profile?.tenant || tenant,\n tenantName: profile?.tenantName || tenantName,\n token: tokens,\n metadata: {\n ...authState.metadata,\n profileFetched: !!profile,\n },\n });\n\n // Clean up authorization state\n await this.storage.deleteAuthorizationState(state);\n\n // Call onSuccess callback if defined\n const config = this.providerConfigs.get(provider);\n if (config?.onSuccess) {\n await config.onSuccess(userId, tokens);\n }\n\n return {\n token: savedToken,\n profile,\n };\n }\n\n /**\n * Get a valid access token (auto-refresh if needed)\n */\n async getAccessToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<string> {\n const token = await this.getValidToken(provider, email, options);\n return token.accessToken;\n }\n\n /**\n * Get a valid token (auto-refresh if needed)\n */\n async getValidToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<OAuth2Token> {\n const storedToken = await this.storage.getToken(provider, email, options.tenant);\n if (!storedToken) {\n const tenantInfo = options.tenant ? ` and tenant ${options.tenant}` : '';\n throw new Error(`No token found for provider ${provider}, email ${email}${tenantInfo}`);\n }\n\n const needsRefresh =\n options.autoRefresh !== false && this.isTokenExpired(storedToken.token, options);\n\n if (!needsRefresh) {\n return storedToken.token;\n }\n\n // Refresh the token\n if (!storedToken.token.refreshToken) {\n throw new Error('Token expired and no refresh token available');\n }\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n const newToken = await providerInstance.refreshToken(storedToken.token.refreshToken);\n await this.storage.updateToken(storedToken.id, { token: newToken });\n\n return newToken;\n }\n\n /**\n * Query tokens with automatic refresh\n */\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n // When auto-refresh is enabled, we need to include expired tokens\n // so we can attempt to refresh them\n const queryWithExpired =\n this.autoRefreshOptions.enabled && !query.includeExpired\n ? { ...query, includeExpired: true }\n : query;\n\n const tokens = await this.storage.queryTokens(queryWithExpired);\n\n if (this.autoRefreshOptions.enabled && !query.includeExpired) {\n const refreshedTokens = await this.refreshTokensIfNeeded(tokens);\n // Filter out tokens that are still expired after refresh attempt\n return refreshedTokens.filter((token) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt > this.now();\n });\n }\n\n return tokens;\n }\n\n /**\n * Get all tokens for a user\n */\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n /**\n * Get all tokens for an email\n */\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n /**\n * Delete a token\n */\n async deleteToken(provider: string, email: string, tenant?: string): Promise<boolean> {\n return this.storage.deleteTokenByProviderEmail(provider, email, tenant);\n }\n\n /**\n * Delete all expired tokens\n */\n async cleanupExpiredTokens(): Promise<number> {\n return this.storage.deleteExpiredTokens();\n }\n\n /**\n * Clean up expired authorization states\n */\n async cleanupExpiredStates(): Promise<number> {\n return this.storage.cleanupExpiredStates();\n }\n\n // Helper methods\n private isTokenExpired(token: OAuth2Token, options: TokenOptions = {}): boolean {\n const { expirationBuffer = 300 } = options;\n\n if (token.createdAt && token.expiresIn !== undefined) {\n const expiresAt = token.createdAt + token.expiresIn * 1000;\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n const expiresAt = new Date(token.expiresAt).getTime();\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n private detectProviderType(name: string, config: OAuth2Config): ProviderType {\n // Try to detect based on the authorization URL\n const authUrl = config.authorizationUrl.toLowerCase();\n\n // Check for known providers that have specific implementations\n if (authUrl.includes('accounts.google.com')) return 'google';\n if (authUrl.includes('github.com')) return 'github';\n if (authUrl.includes('facebook.com')) return 'facebook';\n if (authUrl.includes('microsoft.com') || authUrl.includes('microsoftonline.com')) {\n // Check if it's specifically for Outlook\n if (\n name.toLowerCase().includes('outlook') ||\n config.scopes?.some((s) => s.includes('outlook'))\n ) {\n return 'outlook';\n }\n return 'microsoft';\n }\n\n // Default to generic provider for all others\n return 'generic';\n }\n\n /**\n * Refresh tokens if they are near expiration\n */\n private async refreshTokensIfNeeded(tokens: StoredToken[]): Promise<StoredToken[]> {\n const refreshPromises = tokens.map(async (token) => {\n if (this.shouldRefreshToken(token)) {\n try {\n const provider = this.providers.get(token.provider);\n if (!provider) {\n console.warn(`Provider ${token.provider} not found for token refresh`);\n return token;\n }\n\n if (!token.token.refreshToken) {\n console.warn(`No refresh token available for ${token.provider}:${token.email}`);\n return token;\n }\n\n const newToken = await provider.refreshToken(token.token.refreshToken);\n const updated = await this.storage.updateToken(token.id, { token: newToken });\n return updated || token;\n } catch (error) {\n if (this.autoRefreshOptions.onRefreshError) {\n this.autoRefreshOptions.onRefreshError(error as Error, token);\n }\n console.error(`Failed to refresh token for ${token.provider}:${token.email}:`, error);\n return token;\n }\n }\n return token;\n });\n\n return Promise.all(refreshPromises);\n }\n\n /**\n * Check if a token should be refreshed\n */\n private shouldRefreshToken(storedToken: StoredToken): boolean {\n // Skip if no refresh token\n if (!storedToken.token.refreshToken) {\n return false;\n }\n\n // Check if token is expired or near expiration\n const expiresAt = new Date(storedToken.token.expiresAt).getTime();\n const now = this.now();\n\n // If already expired, definitely try to refresh\n if (now >= expiresAt) {\n return true;\n }\n\n // Otherwise, check if within refresh buffer\n const bufferMs = this.autoRefreshOptions.refreshBuffer! * 60 * 1000;\n const shouldRefreshAt = expiresAt - bufferMs;\n\n return now >= shouldRefreshAt;\n }\n\n /**\n * Update auto-refresh options\n */\n updateAutoRefreshOptions(options: Partial<AutoRefreshOptions>): void {\n this.autoRefreshOptions = { ...this.autoRefreshOptions, ...options };\n }\n\n /**\n * Get all tokens for a specific provider and user across all tenants\n */\n async getTokensAcrossTenants(provider: string, userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider, userId });\n }\n\n /**\n * Get all tenants for a specific provider and email\n */\n async getTenants(provider: string, email: string): Promise<string[]> {\n const tokens = await this.queryTokens({ provider, email });\n const tenants = tokens\n .map((t) => t.tenant)\n .filter((tenant): tenant is string => tenant !== undefined);\n return [...new Set(tenants)]; // Return unique tenants\n }\n\n /**\n * Get token by tenant name (useful for Slack workspaces with human-readable names)\n */\n async getTokenByTenantName(\n provider: string,\n email: string,\n tenantName: string,\n ): Promise<StoredToken | null> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.find((t) => t.tenantName === tenantName) || null;\n }\n\n /**\n * Check if a token exists for a specific tenant\n */\n async hasTokenForTenant(provider: string, email: string, tenant: string): Promise<boolean> {\n const token = await this.storage.getToken(provider, email, tenant);\n return token !== null;\n }\n\n /**\n * Get all tokens with their tenant information\n */\n async getMultiTenantTokens(\n provider: string,\n email: string,\n ): Promise<Array<{ token: StoredToken; tenant?: string; tenantName?: string }>> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.map((token) => ({\n token,\n tenant: token.tenant,\n tenantName: token.tenantName,\n }));\n }\n}\n","import { sealData, unsealData } from 'iron-session';\n\nexport const seal = <T>(d: T, key: string) => sealData(d, { password: key });\nexport const unseal = <T>(s: string, key: string) => unsealData<T>(s, { password: key });\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -13,6 +13,13 @@ interface OAuth2Config {
|
|
|
13
13
|
profileUrl?: string;
|
|
14
14
|
userInfoUrl?: string;
|
|
15
15
|
onSuccess?: (userId: string, tokens: OAuth2Token) => Promise<void>;
|
|
16
|
+
tokenPaths?: {
|
|
17
|
+
accessToken?: string | string[];
|
|
18
|
+
refreshToken?: string | string[];
|
|
19
|
+
expiresIn?: string | string[];
|
|
20
|
+
tokenType?: string | string[];
|
|
21
|
+
scope?: string | string[];
|
|
22
|
+
};
|
|
16
23
|
}
|
|
17
24
|
interface OAuth2Token {
|
|
18
25
|
accessToken: string;
|
|
@@ -38,6 +45,8 @@ interface UserProfile {
|
|
|
38
45
|
id?: string;
|
|
39
46
|
avatar?: string;
|
|
40
47
|
username?: string;
|
|
48
|
+
tenant?: string;
|
|
49
|
+
tenantName?: string;
|
|
41
50
|
raw?: Record<string, any>;
|
|
42
51
|
}
|
|
43
52
|
interface ProfileFetcher {
|
|
@@ -66,6 +75,8 @@ declare abstract class BaseProfileFetcher {
|
|
|
66
75
|
/**
|
|
67
76
|
* Map the raw API response to our standardized UserProfile structure
|
|
68
77
|
* Override this method to customize mapping for different providers
|
|
78
|
+
* @param rawData The raw API response data
|
|
79
|
+
* @returns UserProfile with optional tenant information
|
|
69
80
|
*/
|
|
70
81
|
protected abstract mapToUserProfile(rawData: any): UserProfile;
|
|
71
82
|
/**
|
|
@@ -340,6 +351,22 @@ declare class StandardTokenExchangeStrategy implements TokenExchangeStrategy {
|
|
|
340
351
|
protected buildUrlParams(params: Record<string, string | undefined>): string;
|
|
341
352
|
exchangeCodeForToken(code: string, config: OAuth2Config, codeVerifier?: string): Promise<OAuth2Token>;
|
|
342
353
|
refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token>;
|
|
354
|
+
protected normalizeTokenResponse(tokenData: Record<string, any>, rawResponse: Record<string, any>, refreshTokenFallback?: string, config?: OAuth2Config): OAuth2Token;
|
|
355
|
+
/**
|
|
356
|
+
* Extract a value from a nested object using a dot-notation path
|
|
357
|
+
* @param obj The object to extract from
|
|
358
|
+
* @param customPaths Custom path(s) provided by config (takes priority)
|
|
359
|
+
* @param defaultPaths Default fallback paths to try
|
|
360
|
+
* @returns The extracted value or undefined
|
|
361
|
+
*/
|
|
362
|
+
private extractValue;
|
|
363
|
+
/**
|
|
364
|
+
* Get a nested value from an object using dot notation (e.g., 'authed_user.access_token')
|
|
365
|
+
* @param obj The object to traverse
|
|
366
|
+
* @param path The dot-notation path
|
|
367
|
+
* @returns The value at the path or undefined
|
|
368
|
+
*/
|
|
369
|
+
private getNestedValue;
|
|
343
370
|
}
|
|
344
371
|
|
|
345
372
|
declare class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy {
|
|
@@ -375,6 +402,8 @@ interface ProfileMapping {
|
|
|
375
402
|
id?: string;
|
|
376
403
|
avatar?: string;
|
|
377
404
|
username?: string;
|
|
405
|
+
tenant?: string;
|
|
406
|
+
tenantName?: string;
|
|
378
407
|
}
|
|
379
408
|
declare class GenericProfileFetcher extends BaseProfileFetcher {
|
|
380
409
|
private mapping?;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,13 @@ interface OAuth2Config {
|
|
|
13
13
|
profileUrl?: string;
|
|
14
14
|
userInfoUrl?: string;
|
|
15
15
|
onSuccess?: (userId: string, tokens: OAuth2Token) => Promise<void>;
|
|
16
|
+
tokenPaths?: {
|
|
17
|
+
accessToken?: string | string[];
|
|
18
|
+
refreshToken?: string | string[];
|
|
19
|
+
expiresIn?: string | string[];
|
|
20
|
+
tokenType?: string | string[];
|
|
21
|
+
scope?: string | string[];
|
|
22
|
+
};
|
|
16
23
|
}
|
|
17
24
|
interface OAuth2Token {
|
|
18
25
|
accessToken: string;
|
|
@@ -38,6 +45,8 @@ interface UserProfile {
|
|
|
38
45
|
id?: string;
|
|
39
46
|
avatar?: string;
|
|
40
47
|
username?: string;
|
|
48
|
+
tenant?: string;
|
|
49
|
+
tenantName?: string;
|
|
41
50
|
raw?: Record<string, any>;
|
|
42
51
|
}
|
|
43
52
|
interface ProfileFetcher {
|
|
@@ -66,6 +75,8 @@ declare abstract class BaseProfileFetcher {
|
|
|
66
75
|
/**
|
|
67
76
|
* Map the raw API response to our standardized UserProfile structure
|
|
68
77
|
* Override this method to customize mapping for different providers
|
|
78
|
+
* @param rawData The raw API response data
|
|
79
|
+
* @returns UserProfile with optional tenant information
|
|
69
80
|
*/
|
|
70
81
|
protected abstract mapToUserProfile(rawData: any): UserProfile;
|
|
71
82
|
/**
|
|
@@ -340,6 +351,22 @@ declare class StandardTokenExchangeStrategy implements TokenExchangeStrategy {
|
|
|
340
351
|
protected buildUrlParams(params: Record<string, string | undefined>): string;
|
|
341
352
|
exchangeCodeForToken(code: string, config: OAuth2Config, codeVerifier?: string): Promise<OAuth2Token>;
|
|
342
353
|
refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token>;
|
|
354
|
+
protected normalizeTokenResponse(tokenData: Record<string, any>, rawResponse: Record<string, any>, refreshTokenFallback?: string, config?: OAuth2Config): OAuth2Token;
|
|
355
|
+
/**
|
|
356
|
+
* Extract a value from a nested object using a dot-notation path
|
|
357
|
+
* @param obj The object to extract from
|
|
358
|
+
* @param customPaths Custom path(s) provided by config (takes priority)
|
|
359
|
+
* @param defaultPaths Default fallback paths to try
|
|
360
|
+
* @returns The extracted value or undefined
|
|
361
|
+
*/
|
|
362
|
+
private extractValue;
|
|
363
|
+
/**
|
|
364
|
+
* Get a nested value from an object using dot notation (e.g., 'authed_user.access_token')
|
|
365
|
+
* @param obj The object to traverse
|
|
366
|
+
* @param path The dot-notation path
|
|
367
|
+
* @returns The value at the path or undefined
|
|
368
|
+
*/
|
|
369
|
+
private getNestedValue;
|
|
343
370
|
}
|
|
344
371
|
|
|
345
372
|
declare class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy {
|
|
@@ -375,6 +402,8 @@ interface ProfileMapping {
|
|
|
375
402
|
id?: string;
|
|
376
403
|
avatar?: string;
|
|
377
404
|
username?: string;
|
|
405
|
+
tenant?: string;
|
|
406
|
+
tenantName?: string;
|
|
378
407
|
}
|
|
379
408
|
declare class GenericProfileFetcher extends BaseProfileFetcher {
|
|
380
409
|
private mapping?;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {createHash,randomBytes}from'crypto';import {sealData,unsealData}from'iron-session';var g=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}generateAuthorizationUrl(e,t,r){let o={client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scopes.join(" "),state:t};(e.usePKCE||e.pkce)&&r&&(o.code_challenge=r,o.code_challenge_method="S256");let n={...e.additionalParams,...e.extraAuthParams};return Object.assign(o,n),`${e.authorizationUrl}?${this.buildUrlParams(o)}`}};var k=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}async exchangeCodeForToken(e,t,r){let o={grant_type:"authorization_code",code:e,redirect_uri:t.redirectUri,client_id:t.clientId};(t.usePKCE||t.pkce)&&r?o.code_verifier=r:t.clientSecret&&(o.client_secret=t.clientSecret);let n=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(o)});if(!n.ok){let w=await n.text();throw new Error(`Token exchange failed: ${n.statusText} - ${w}`)}let i=await n.json(),a=t.responseRootKey?i[t.responseRootKey]:i,c=Date.now(),p=a.expires_in||3600;return {accessToken:a.access_token,refreshToken:a.refresh_token,expiresAt:new Date(c+p*1e3),expiresIn:p,tokenType:a.token_type||"Bearer",scope:a.scope,createdAt:c,raw:i}}async refreshToken(e,t){let r={grant_type:"refresh_token",refresh_token:e,client_id:t.clientId};!(t.usePKCE||t.pkce)&&t.clientSecret&&(r.client_secret=t.clientSecret);let o=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(r)});if(!o.ok){let p=await o.text();throw new Error(`Token refresh failed: ${o.statusText} - ${p}`)}let n=await o.json(),i=t.responseRootKey?n[t.responseRootKey]:n,a=Date.now(),c=i.expires_in||3600;return {accessToken:i.access_token,refreshToken:i.refresh_token||e,expiresAt:new Date(a+c*1e3),expiresIn:c,tokenType:i.token_type||"Bearer",scope:i.scope,createdAt:a,raw:n}}};var l=class{constructor(e,t,r,o){this.config=e;this.authUrlStrategy=t||this.createAuthorizationUrlStrategy(),this.tokenStrategy=r||this.createTokenExchangeStrategy(),this.profileFetcher=o;}authUrlStrategy;tokenStrategy;profileFetcher;async fetchProfile(e){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.fetchUserInfo(e)}getProfileEndpoint(){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.getEndpoint()}setProfileFetcher(e){this.profileFetcher=e;}hasProfileFetcher(){return !!this.profileFetcher}generateAuthorizationUrl(e,t){return this.authUrlStrategy.generateAuthorizationUrl(this.config,e,t)}async exchangeCodeForToken(e,t){return this.tokenStrategy.exchangeCodeForToken(e,this.config,t)}async refreshToken(e){return this.tokenStrategy.refreshToken(e,this.config)}};var T=class extends l{constructor(e,t,r,o){super(e,t,r,o);}createAuthorizationUrlStrategy(){return new g}createTokenExchangeStrategy(){return new k}};var d=class{constructor(e){this.profileEndpoint=e;}async fetchUserInfo(e){let t=await fetch(this.profileEndpoint,{headers:{Authorization:`Bearer ${e}`,Accept:"application/json",...this.getAdditionalHeaders()}});if(!t.ok)throw new Error(`Failed to fetch profile from ${this.profileEndpoint}: ${t.statusText}`);let r=await t.json();return this.mapToUserProfile(r)}getAdditionalHeaders(){return {}}getEndpoint(){return this.profileEndpoint}};var P=class extends d{constructor(){super("https://www.googleapis.com/oauth2/v2/userinfo");}mapToUserProfile(e){return {email:e.email,name:e.name,id:e.id,avatar:e.picture,username:e.email,raw:e}}};var y=class extends d{constructor(){super("https://api.github.com/user");}mapToUserProfile(e){var t;return {email:e.email,name:e.name||e.login,id:(t=e.id)==null?void 0:t.toString(),avatar:e.avatar_url,username:e.login,raw:e}}getAdditionalHeaders(){return {"User-Agent":"OAuth2-Token-Manager"}}};var v=class extends d{constructor(){super("https://graph.microsoft.com/v1.0/me");}mapToUserProfile(e){return {email:e.mail||e.userPrincipalName,name:e.displayName,id:e.id,avatar:void 0,username:e.userPrincipalName,raw:e}}};var h=class extends d{constructor(t,r,o){super(t);this.mapping=r;this.additionalHeaders=o;}mapToUserProfile(t){return this.mapping?{email:this.getNestedProperty(t,this.mapping.email),name:this.mapping.name?this.getNestedProperty(t,this.mapping.name):void 0,id:this.mapping.id?this.getNestedProperty(t,this.mapping.id):void 0,avatar:this.mapping.avatar?this.getNestedProperty(t,this.mapping.avatar):void 0,username:this.mapping.username?this.getNestedProperty(t,this.mapping.username):void 0,raw:t}:{email:t.email||t.mail||t.emailAddress,name:t.name||t.displayName||t.full_name,id:t.id||t.sub||t.user_id,avatar:t.avatar||t.picture||t.avatar_url,username:t.username||t.login||t.preferred_username,raw:t}}getAdditionalHeaders(){return this.additionalHeaders||{}}getNestedProperty(t,r){return r.split(".").reduce((o,n)=>o==null?void 0:o[n],t)}};var A=class{static createProfileFetcher(e,t,r){if(r!=null&&r.profileUrl)return new h(r.profileUrl,r.profileMapping,r.profileHeaders);switch(e){case "google":return new P;case "github":return new y;case "microsoft":case "outlook":return new v;case "facebook":return new h("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let o=t.profileUrl||t.userInfoUrl;if(!o)throw new Error(`Profile URL must be provided for ${e} provider`);return new h(o)}}static registerCustomProfileFetcher(e,t){this.customFetchers.set(e,t);}static customFetchers=new Map;static getCustomProfileFetcher(e){return this.customFetchers.get(e)}};var x=class s{static presetConfigs={google:{authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",profileUrl:"https://www.googleapis.com/oauth2/v2/userinfo",usePKCE:true,extraAuthParams:{access_type:"offline",prompt:"consent"}},github:{authorizationUrl:"https://github.com/login/oauth/authorize",tokenUrl:"https://github.com/login/oauth/access_token",profileUrl:"https://api.github.com/user"},microsoft:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true},outlook:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true,extraAuthParams:{prompt:"select_account"}},facebook:{authorizationUrl:"https://www.facebook.com/v12.0/dialog/oauth",tokenUrl:"https://graph.facebook.com/v12.0/oauth/access_token",profileUrl:"https://graph.facebook.com/me?fields=id,name,email,picture"}};createProvider(e,t){let r=e!=="generic"?s.presetConfigs[e]||{}:{},o={...r,...t,authorizationUrl:t.authorizationUrl||r.authorizationUrl||"",tokenUrl:t.tokenUrl||r.tokenUrl||"",profileUrl:t.profileUrl||r.profileUrl,extraAuthParams:{...r.extraAuthParams||{},...t.extraAuthParams||{}}},n=A.createProfileFetcher(e,o);return new T(o,void 0,void 0,n)}static registerPreset(e,t){s.presetConfigs[e]=t;}static getPresetConfig(e){return s.presetConfigs[e]}};var f=class{tokens=new Map;states=new Map;profileFetchers=new Map;generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async saveToken(e){let t=await this.getToken(e.provider,e.email,e.tenant);if(t){let o={...t,...e,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,o),o}let r={...e,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(r.id,r),r}async queryTokens(e){let t=Array.from(this.tokens.values());if(e.id&&(t=t.filter(r=>r.id===e.id)),e.provider&&(t=t.filter(r=>r.provider===e.provider)),e.userId&&(t=t.filter(r=>r.userId===e.userId)),e.email&&(t=t.filter(r=>r.email===e.email)),e.tenant!==void 0&&(t=t.filter(r=>r.tenant===e.tenant)),!e.includeExpired){let r=new Date().getTime();t=t.filter(o=>new Date(o.token.expiresAt).getTime()>=r);}return e.offset!==void 0&&(t=t.slice(e.offset)),e.limit!==void 0&&(t=t.slice(0,e.limit)),t}async getToken(e,t,r){return (await this.queryTokens({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getTokenById(e){return (await this.queryTokens({id:e,includeExpired:true}))[0]||null}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async getTokensByProvider(e){return this.queryTokens({provider:e})}async getAccounts(e,t){return this.queryTokens({userId:e,provider:t})}async getTokensForEmail(e,t,r){return (await this.queryTokens({userId:e,provider:t,email:r}))[0]||null}async getTokens(e,t){return this.queryTokens({userId:e,provider:t})}async updateToken(e,t){let r=this.tokens.get(e);if(!r)return null;let o={...r,...t.token&&{token:t.token},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,o),o}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let o=await this.getToken(e,t,r);return o?this.tokens.delete(o.id):false}async deleteExpiredTokens(){let e=new Date().getTime(),t=Array.from(this.tokens.entries()).filter(([,r])=>new Date(r.token.expiresAt).getTime()<e).map(([r])=>r);return t.forEach(r=>this.tokens.delete(r)),t.length}async saveAuthorizationState(e){let t={...e,createdAt:new Date(Date.now())};return this.states.set(e.state,t),t}async getAuthorizationState(e){return this.states.get(e)||null}async deleteAuthorizationState(e){return this.states.delete(e)}async cleanupExpiredStates(){let e=new Date().getTime(),t=10*60*1e3,r=Array.from(this.states.entries()).filter(([,o])=>e-o.createdAt.getTime()>t).map(([o])=>o);return r.forEach(o=>this.states.delete(o)),r.length}registerProfileFetcher(e,t){this.profileFetchers.set(e,t);}getProfileFetcher(e){return this.profileFetchers.get(e)}getProfileFetchers(){return new Map(this.profileFetchers)}};var R=()=>randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),z=s=>createHash("sha256").update(s).digest("base64url"),I=()=>randomBytes(16).toString("base64url");var S=class{storage;providerFactory;providers=new Map;providerConfigs=new Map;now;autoRefreshOptions;constructor(e={}){var t,r,o;this.storage=e.storage||new f,this.providerFactory=new x,this.now=Date.now,this.autoRefreshOptions={enabled:((t=e.autoRefresh)==null?void 0:t.enabled)??true,refreshBuffer:((r=e.autoRefresh)==null?void 0:r.refreshBuffer)??10,onRefreshError:(o=e.autoRefresh)==null?void 0:o.onRefreshError},e.providers&&Object.entries(e.providers).forEach(([n,i])=>{this.registerProvider(n,i);});}registerProvider(e,t){this.providerConfigs.set(e,t);let r=this.detectProviderType(e,t),o=this.providerFactory.createProvider(r,t),n=this.storage.getProfileFetcher(e);n&&o.setProfileFetcher(n),this.providers.set(e,o);}async authorize(e){var a;let t=this.providers.get(e.provider);if(!t)throw new Error(`Provider ${e.provider} not found`);let r=I(),o,n;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let c=R(),p=z(c);o=t.generateAuthorizationUrl(r,p),n={state:r,codeVerifier:c,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};}else o=t.generateAuthorizationUrl(r),n={state:r,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};return await this.storage.saveAuthorizationState(n),{url:o,state:r}}async handleCallback(e,t){var U,O,E,b,F;let r=await this.storage.getAuthorizationState(t);if(!r)throw new Error("Invalid or expired state");let o=(U=r.metadata)==null?void 0:U.provider;if(!o)throw new Error("Provider not found in authorization state");let n=this.providers.get(o);if(!n)throw new Error(`Provider ${o} not found`);let i=await n.exchangeCodeForToken(e,r.codeVerifier),a=(O=r.metadata)==null?void 0:O.userId,c=(E=r.metadata)==null?void 0:E.email,p=(b=r.metadata)==null?void 0:b.tenant,w=(F=r.metadata)==null?void 0:F.tenantName;if(!a||!c)throw new Error("User ID and email are required in authorization state");let u;if(n.hasProfileFetcher())try{u=await n.fetchProfile(i.accessToken);}catch(_){console.warn("Failed to fetch user profile:",_);}let B=await this.storage.saveToken({provider:o,userId:a,email:(u==null?void 0:u.email)||c,tenant:p,tenantName:w,token:i,metadata:{...r.metadata,profileFetched:!!u}});await this.storage.deleteAuthorizationState(t);let m=this.providerConfigs.get(o);return m!=null&&m.onSuccess&&await m.onSuccess(a,i),{token:B,profile:u}}async getAccessToken(e,t,r={}){return (await this.getValidToken(e,t,r)).accessToken}async getValidToken(e,t,r={}){let o=await this.storage.getToken(e,t,r.tenant);if(!o){let c=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${c}`)}if(!(r.autoRefresh!==false&&this.isTokenExpired(o.token,r)))return o.token;if(!o.token.refreshToken)throw new Error("Token expired and no refresh token available");let i=this.providers.get(e);if(!i)throw new Error(`Provider ${e} not found`);let a=await i.refreshToken(o.token.refreshToken);return await this.storage.updateToken(o.id,{token:a}),a}async queryTokens(e){let t=this.autoRefreshOptions.enabled&&!e.includeExpired?{...e,includeExpired:true}:e,r=await this.storage.queryTokens(t);return this.autoRefreshOptions.enabled&&!e.includeExpired?(await this.refreshTokensIfNeeded(r)).filter(n=>new Date(n.token.expiresAt).getTime()>this.now()):r}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async deleteToken(e,t,r){return this.storage.deleteTokenByProviderEmail(e,t,r)}async cleanupExpiredTokens(){return this.storage.deleteExpiredTokens()}async cleanupExpiredStates(){return this.storage.cleanupExpiredStates()}isTokenExpired(e,t={}){let{expirationBuffer:r=300}=t;if(e.createdAt&&e.expiresIn!==void 0){let i=e.createdAt+e.expiresIn*1e3;return this.now()+r*1e3>=i}let o=new Date(e.expiresAt).getTime();return this.now()+r*1e3>=o}detectProviderType(e,t){var o;let r=t.authorizationUrl.toLowerCase();return r.includes("accounts.google.com")?"google":r.includes("github.com")?"github":r.includes("facebook.com")?"facebook":r.includes("microsoft.com")||r.includes("microsoftonline.com")?e.toLowerCase().includes("outlook")||(o=t.scopes)!=null&&o.some(n=>n.includes("outlook"))?"outlook":"microsoft":"generic"}async refreshTokensIfNeeded(e){let t=e.map(async r=>{if(this.shouldRefreshToken(r))try{let o=this.providers.get(r.provider);if(!o)return console.warn(`Provider ${r.provider} not found for token refresh`),r;if(!r.token.refreshToken)return console.warn(`No refresh token available for ${r.provider}:${r.email}`),r;let n=await o.refreshToken(r.token.refreshToken);return await this.storage.updateToken(r.id,{token:n})||r}catch(o){return this.autoRefreshOptions.onRefreshError&&this.autoRefreshOptions.onRefreshError(o,r),console.error(`Failed to refresh token for ${r.provider}:${r.email}:`,o),r}return r});return Promise.all(t)}shouldRefreshToken(e){if(!e.token.refreshToken)return false;let t=new Date(e.token.expiresAt).getTime(),r=this.now();if(r>=t)return true;let o=this.autoRefreshOptions.refreshBuffer*60*1e3,n=t-o;return r>=n}updateAutoRefreshOptions(e){this.autoRefreshOptions={...this.autoRefreshOptions,...e};}async getTokensAcrossTenants(e,t){return this.queryTokens({provider:e,userId:t})}async getTenants(e,t){let o=(await this.queryTokens({provider:e,email:t})).map(n=>n.tenant).filter(n=>n!==void 0);return [...new Set(o)]}async getTokenByTenantName(e,t,r){return (await this.queryTokens({provider:e,email:t})).find(n=>n.tenantName===r)||null}async hasTokenForTenant(e,t,r){return await this.storage.getToken(e,t,r)!==null}async getMultiTenantTokens(e,t){return (await this.queryTokens({provider:e,email:t})).map(o=>({token:o,tenant:o.tenant,tenantName:o.tenantName}))}};var ye=(s,e)=>sealData(s,{password:e}),ve=(s,e)=>unsealData(s,{password:e});
|
|
2
|
-
export{
|
|
1
|
+
import {createHash,randomBytes}from'crypto';import {sealData,unsealData}from'iron-session';var v=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}generateAuthorizationUrl(e,t,r){let o={client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scopes.join(" "),state:t};(e.usePKCE||e.pkce)&&r&&(o.code_challenge=r,o.code_challenge_method="S256");let n={...e.additionalParams,...e.extraAuthParams};return Object.assign(o,n),`${e.authorizationUrl}?${this.buildUrlParams(o)}`}};var x=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,o])=>`${r}=${encodeURIComponent(o)}`).join("&")}async exchangeCodeForToken(e,t,r){let o={grant_type:"authorization_code",code:e,redirect_uri:t.redirectUri,client_id:t.clientId};(t.usePKCE||t.pkce)&&r?o.code_verifier=r:t.clientSecret&&(o.client_secret=t.clientSecret);let n=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(o)});if(!n.ok){let c=await n.text();throw new Error(`Token exchange failed: ${n.statusText} - ${c}`)}let i=await n.json(),a=t.responseRootKey?i[t.responseRootKey]:i;return this.normalizeTokenResponse(a,i,void 0,t)}async refreshToken(e,t){let r={grant_type:"refresh_token",refresh_token:e,client_id:t.clientId};!(t.usePKCE||t.pkce)&&t.clientSecret&&(r.client_secret=t.clientSecret);let o=await fetch(t.tokenUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:this.buildUrlParams(r)});if(!o.ok){let a=await o.text();throw new Error(`Token refresh failed: ${o.statusText} - ${a}`)}let n=await o.json(),i=t.responseRootKey?n[t.responseRootKey]:n;return this.normalizeTokenResponse(i,n,e,t)}normalizeTokenResponse(e,t,r,o){var p,l,f,m,g;let n=Date.now(),i=this.extractValue(e,(p=o==null?void 0:o.tokenPaths)==null?void 0:p.accessToken,["authed_user.access_token","authed_user.accessToken","access_token","accessToken","token.access_token","token.accessToken"]);if(!i)throw new Error("Token response did not include an access_token");let a=this.extractValue(e,(l=o==null?void 0:o.tokenPaths)==null?void 0:l.refreshToken,["authed_user.refresh_token","authed_user.refreshToken","refresh_token","refreshToken","token.refresh_token","token.refreshToken"])??r,c=this.extractValue(e,(f=o==null?void 0:o.tokenPaths)==null?void 0:f.expiresIn,["authed_user.expires_in","authed_user.expiresIn","expires_in","expiresIn","token.expires_in","token.expiresIn"]),y=(typeof c=="string"?parseInt(c,10):c)||3600,d=this.extractValue(e,(m=o==null?void 0:o.tokenPaths)==null?void 0:m.scope,["authed_user.scope","scope","token.scope"]),b=this.extractValue(e,(g=o==null?void 0:o.tokenPaths)==null?void 0:g.tokenType,["authed_user.token_type","authed_user.tokenType","token_type","tokenType","token.token_type","token.tokenType"])??"Bearer";return {accessToken:i,refreshToken:a,expiresAt:new Date(n+y*1e3),expiresIn:y,tokenType:b,scope:d,createdAt:n,raw:t}}extractValue(e,t,r){if(t){let o=Array.isArray(t)?t:[t];for(let n of o){let i=this.getNestedValue(e,n);if(i!==void 0)return i}}if(r)for(let o of r){let n=this.getNestedValue(e,o);if(n!==void 0)return n}}getNestedValue(e,t){let r=t.split("."),o=e;for(let n of r)if(o&&typeof o=="object"&&n in o)o=o[n];else return;return o}};var k=class{constructor(e,t,r,o){this.config=e;this.authUrlStrategy=t||this.createAuthorizationUrlStrategy(),this.tokenStrategy=r||this.createTokenExchangeStrategy(),this.profileFetcher=o;}authUrlStrategy;tokenStrategy;profileFetcher;async fetchProfile(e){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.fetchUserInfo(e)}getProfileEndpoint(){if(!this.profileFetcher)throw new Error("Profile fetcher not configured for this provider");return this.profileFetcher.getEndpoint()}setProfileFetcher(e){this.profileFetcher=e;}hasProfileFetcher(){return !!this.profileFetcher}generateAuthorizationUrl(e,t){return this.authUrlStrategy.generateAuthorizationUrl(this.config,e,t)}async exchangeCodeForToken(e,t){return this.tokenStrategy.exchangeCodeForToken(e,this.config,t)}async refreshToken(e){return this.tokenStrategy.refreshToken(e,this.config)}};var A=class extends k{constructor(e,t,r,o){super(e,t,r,o);}createAuthorizationUrlStrategy(){return new v}createTokenExchangeStrategy(){return new x}};var u=class{constructor(e){this.profileEndpoint=e;}async fetchUserInfo(e){let t=await fetch(this.profileEndpoint,{headers:{Authorization:`Bearer ${e}`,Accept:"application/json",...this.getAdditionalHeaders()}});if(!t.ok)throw new Error(`Failed to fetch profile from ${this.profileEndpoint}: ${t.statusText}`);let r=await t.json();return this.mapToUserProfile(r)}getAdditionalHeaders(){return {}}getEndpoint(){return this.profileEndpoint}};var S=class extends u{constructor(){super("https://www.googleapis.com/oauth2/v2/userinfo");}mapToUserProfile(e){return {email:e.email,name:e.name,id:e.id,avatar:e.picture,username:e.email,raw:e}}};var w=class extends u{constructor(){super("https://api.github.com/user");}mapToUserProfile(e){var t;return {email:e.email,name:e.name||e.login,id:(t=e.id)==null?void 0:t.toString(),avatar:e.avatar_url,username:e.login,raw:e}}getAdditionalHeaders(){return {"User-Agent":"OAuth2-Token-Manager"}}};var U=class extends u{constructor(){super("https://graph.microsoft.com/v1.0/me");}mapToUserProfile(e){return {email:e.mail||e.userPrincipalName,name:e.displayName,id:e.id,avatar:void 0,username:e.userPrincipalName,raw:e}}};var h=class extends u{constructor(t,r,o){super(t);this.mapping=r;this.additionalHeaders=o;}mapToUserProfile(t){return this.mapping?{email:this.getNestedProperty(t,this.mapping.email),name:this.mapping.name?this.getNestedProperty(t,this.mapping.name):void 0,id:this.mapping.id?this.getNestedProperty(t,this.mapping.id):void 0,avatar:this.mapping.avatar?this.getNestedProperty(t,this.mapping.avatar):void 0,username:this.mapping.username?this.getNestedProperty(t,this.mapping.username):void 0,tenant:this.mapping.tenant?this.getNestedProperty(t,this.mapping.tenant):void 0,tenantName:this.mapping.tenantName?this.getNestedProperty(t,this.mapping.tenantName):void 0,raw:t}:{email:t.email||t.mail||t.emailAddress,name:t.name||t.displayName||t.full_name,id:t.id||t.sub||t.user_id,avatar:t.avatar||t.picture||t.avatar_url,username:t.username||t.login||t.preferred_username,tenant:t.tenant||t.workspace_id||t.organization_id||t.team_id,tenantName:t.tenantName||t.workspace_name||t.organization_name||t.team_name,raw:t}}getAdditionalHeaders(){return this.additionalHeaders||{}}getNestedProperty(t,r){return r.split(".").reduce((o,n)=>o==null?void 0:o[n],t)}};var E=class{static createProfileFetcher(e,t,r){if(r!=null&&r.profileUrl)return new h(r.profileUrl,r.profileMapping,r.profileHeaders);switch(e){case "google":return new S;case "github":return new w;case "microsoft":case "outlook":return new U;case "facebook":return new h("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let o=t.profileUrl||t.userInfoUrl;if(!o)throw new Error(`Profile URL must be provided for ${e} provider`);return new h(o)}}static registerCustomProfileFetcher(e,t){this.customFetchers.set(e,t);}static customFetchers=new Map;static getCustomProfileFetcher(e){return this.customFetchers.get(e)}};var O=class s{static presetConfigs={google:{authorizationUrl:"https://accounts.google.com/o/oauth2/v2/auth",tokenUrl:"https://oauth2.googleapis.com/token",profileUrl:"https://www.googleapis.com/oauth2/v2/userinfo",usePKCE:true,extraAuthParams:{access_type:"offline",prompt:"consent"}},github:{authorizationUrl:"https://github.com/login/oauth/authorize",tokenUrl:"https://github.com/login/oauth/access_token",profileUrl:"https://api.github.com/user"},microsoft:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true},outlook:{authorizationUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/authorize",tokenUrl:"https://login.microsoftonline.com/common/oauth2/v2.0/token",profileUrl:"https://graph.microsoft.com/v1.0/me",usePKCE:true,extraAuthParams:{prompt:"select_account"}},facebook:{authorizationUrl:"https://www.facebook.com/v12.0/dialog/oauth",tokenUrl:"https://graph.facebook.com/v12.0/oauth/access_token",profileUrl:"https://graph.facebook.com/me?fields=id,name,email,picture"}};createProvider(e,t){let r=e!=="generic"?s.presetConfigs[e]||{}:{},o={...r,...t,authorizationUrl:t.authorizationUrl||r.authorizationUrl||"",tokenUrl:t.tokenUrl||r.tokenUrl||"",profileUrl:t.profileUrl||r.profileUrl,extraAuthParams:{...r.extraAuthParams||{},...t.extraAuthParams||{}}},n=E.createProfileFetcher(e,o);return new A(o,void 0,void 0,n)}static registerPreset(e,t){s.presetConfigs[e]=t;}static getPresetConfig(e){return s.presetConfigs[e]}};var T=class{tokens=new Map;states=new Map;profileFetchers=new Map;generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async saveToken(e){let t=await this.getToken(e.provider,e.email,e.tenant);if(t){let o={...t,...e,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,o),o}let r={...e,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(r.id,r),r}async queryTokens(e){let t=Array.from(this.tokens.values());if(e.id&&(t=t.filter(r=>r.id===e.id)),e.provider&&(t=t.filter(r=>r.provider===e.provider)),e.userId&&(t=t.filter(r=>r.userId===e.userId)),e.email&&(t=t.filter(r=>r.email===e.email)),e.tenant!==void 0&&(t=t.filter(r=>r.tenant===e.tenant)),!e.includeExpired){let r=new Date().getTime();t=t.filter(o=>new Date(o.token.expiresAt).getTime()>=r);}return e.offset!==void 0&&(t=t.slice(e.offset)),e.limit!==void 0&&(t=t.slice(0,e.limit)),t}async getToken(e,t,r){return (await this.queryTokens({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getTokenById(e){return (await this.queryTokens({id:e,includeExpired:true}))[0]||null}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async getTokensByProvider(e){return this.queryTokens({provider:e})}async getAccounts(e,t){return this.queryTokens({userId:e,provider:t})}async getTokensForEmail(e,t,r){return (await this.queryTokens({userId:e,provider:t,email:r}))[0]||null}async getTokens(e,t){return this.queryTokens({userId:e,provider:t})}async updateToken(e,t){let r=this.tokens.get(e);if(!r)return null;let o={...r,...t.token&&{token:t.token},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,o),o}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let o=await this.getToken(e,t,r);return o?this.tokens.delete(o.id):false}async deleteExpiredTokens(){let e=new Date().getTime(),t=Array.from(this.tokens.entries()).filter(([,r])=>new Date(r.token.expiresAt).getTime()<e).map(([r])=>r);return t.forEach(r=>this.tokens.delete(r)),t.length}async saveAuthorizationState(e){let t={...e,createdAt:new Date(Date.now())};return this.states.set(e.state,t),t}async getAuthorizationState(e){return this.states.get(e)||null}async deleteAuthorizationState(e){return this.states.delete(e)}async cleanupExpiredStates(){let e=new Date().getTime(),t=10*60*1e3,r=Array.from(this.states.entries()).filter(([,o])=>e-o.createdAt.getTime()>t).map(([o])=>o);return r.forEach(o=>this.states.delete(o)),r.length}registerProfileFetcher(e,t){this.profileFetchers.set(e,t);}getProfileFetcher(e){return this.profileFetchers.get(e)}getProfileFetchers(){return new Map(this.profileFetchers)}};var z=()=>randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),_=s=>createHash("sha256").update(s).digest("base64url"),I=()=>randomBytes(16).toString("base64url");var F=class{storage;providerFactory;providers=new Map;providerConfigs=new Map;now;autoRefreshOptions;constructor(e={}){var t,r,o;this.storage=e.storage||new T,this.providerFactory=new O,this.now=Date.now,this.autoRefreshOptions={enabled:((t=e.autoRefresh)==null?void 0:t.enabled)??true,refreshBuffer:((r=e.autoRefresh)==null?void 0:r.refreshBuffer)??10,onRefreshError:(o=e.autoRefresh)==null?void 0:o.onRefreshError},e.providers&&Object.entries(e.providers).forEach(([n,i])=>{this.registerProvider(n,i);});}registerProvider(e,t){this.providerConfigs.set(e,t);let r=this.detectProviderType(e,t),o=this.providerFactory.createProvider(r,t),n=this.storage.getProfileFetcher(e);n&&o.setProfileFetcher(n),this.providers.set(e,o);}async authorize(e){var a;let t=this.providers.get(e.provider);if(!t)throw new Error(`Provider ${e.provider} not found`);let r=I(),o,n;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let c=z(),P=_(c);o=t.generateAuthorizationUrl(r,P),n={state:r,codeVerifier:c,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};}else o=t.generateAuthorizationUrl(r),n={state:r,config:this.providerConfigs.get(e.provider),metadata:{...e.metadata,userId:e.userId,email:e.email,provider:e.provider,tenant:e.tenant,tenantName:e.tenantName}};return await this.storage.saveAuthorizationState(n),{url:o,state:r}}async handleCallback(e,t){var l,f,m,g,C;let r=await this.storage.getAuthorizationState(t);if(!r)throw new Error("Invalid or expired state");let o=(l=r.metadata)==null?void 0:l.provider;if(!o)throw new Error("Provider not found in authorization state");let n=this.providers.get(o);if(!n)throw new Error(`Provider ${o} not found`);let i=await n.exchangeCodeForToken(e,r.codeVerifier),a=(f=r.metadata)==null?void 0:f.userId,c=(m=r.metadata)==null?void 0:m.email,P=(g=r.metadata)==null?void 0:g.tenant,y=(C=r.metadata)==null?void 0:C.tenantName;if(!a||!c)throw new Error("User ID and email are required in authorization state");let d;if(n.hasProfileFetcher())try{d=await n.fetchProfile(i.accessToken);}catch(N){console.warn("Failed to fetch user profile:",N);}let b=await this.storage.saveToken({provider:o,userId:a,email:(d==null?void 0:d.email)||c,tenant:(d==null?void 0:d.tenant)||P,tenantName:(d==null?void 0:d.tenantName)||y,token:i,metadata:{...r.metadata,profileFetched:!!d}});await this.storage.deleteAuthorizationState(t);let p=this.providerConfigs.get(o);return p!=null&&p.onSuccess&&await p.onSuccess(a,i),{token:b,profile:d}}async getAccessToken(e,t,r={}){return (await this.getValidToken(e,t,r)).accessToken}async getValidToken(e,t,r={}){let o=await this.storage.getToken(e,t,r.tenant);if(!o){let c=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${c}`)}if(!(r.autoRefresh!==false&&this.isTokenExpired(o.token,r)))return o.token;if(!o.token.refreshToken)throw new Error("Token expired and no refresh token available");let i=this.providers.get(e);if(!i)throw new Error(`Provider ${e} not found`);let a=await i.refreshToken(o.token.refreshToken);return await this.storage.updateToken(o.id,{token:a}),a}async queryTokens(e){let t=this.autoRefreshOptions.enabled&&!e.includeExpired?{...e,includeExpired:true}:e,r=await this.storage.queryTokens(t);return this.autoRefreshOptions.enabled&&!e.includeExpired?(await this.refreshTokensIfNeeded(r)).filter(n=>new Date(n.token.expiresAt).getTime()>this.now()):r}async getTokensByUserId(e){return this.queryTokens({userId:e})}async getTokensByEmail(e){return this.queryTokens({email:e})}async deleteToken(e,t,r){return this.storage.deleteTokenByProviderEmail(e,t,r)}async cleanupExpiredTokens(){return this.storage.deleteExpiredTokens()}async cleanupExpiredStates(){return this.storage.cleanupExpiredStates()}isTokenExpired(e,t={}){let{expirationBuffer:r=300}=t;if(e.createdAt&&e.expiresIn!==void 0){let i=e.createdAt+e.expiresIn*1e3;return this.now()+r*1e3>=i}let o=new Date(e.expiresAt).getTime();return this.now()+r*1e3>=o}detectProviderType(e,t){var o;let r=t.authorizationUrl.toLowerCase();return r.includes("accounts.google.com")?"google":r.includes("github.com")?"github":r.includes("facebook.com")?"facebook":r.includes("microsoft.com")||r.includes("microsoftonline.com")?e.toLowerCase().includes("outlook")||(o=t.scopes)!=null&&o.some(n=>n.includes("outlook"))?"outlook":"microsoft":"generic"}async refreshTokensIfNeeded(e){let t=e.map(async r=>{if(this.shouldRefreshToken(r))try{let o=this.providers.get(r.provider);if(!o)return console.warn(`Provider ${r.provider} not found for token refresh`),r;if(!r.token.refreshToken)return console.warn(`No refresh token available for ${r.provider}:${r.email}`),r;let n=await o.refreshToken(r.token.refreshToken);return await this.storage.updateToken(r.id,{token:n})||r}catch(o){return this.autoRefreshOptions.onRefreshError&&this.autoRefreshOptions.onRefreshError(o,r),console.error(`Failed to refresh token for ${r.provider}:${r.email}:`,o),r}return r});return Promise.all(t)}shouldRefreshToken(e){if(!e.token.refreshToken)return false;let t=new Date(e.token.expiresAt).getTime(),r=this.now();if(r>=t)return true;let o=this.autoRefreshOptions.refreshBuffer*60*1e3,n=t-o;return r>=n}updateAutoRefreshOptions(e){this.autoRefreshOptions={...this.autoRefreshOptions,...e};}async getTokensAcrossTenants(e,t){return this.queryTokens({provider:e,userId:t})}async getTenants(e,t){let o=(await this.queryTokens({provider:e,email:t})).map(n=>n.tenant).filter(n=>n!==void 0);return [...new Set(o)]}async getTokenByTenantName(e,t,r){return (await this.queryTokens({provider:e,email:t})).find(n=>n.tenantName===r)||null}async hasTokenForTenant(e,t,r){return await this.storage.getToken(e,t,r)!==null}async getMultiTenantTokens(e,t){return (await this.queryTokens({provider:e,email:t})).map(o=>({token:o,tenant:o.tenant,tenantName:o.tenantName}))}};var ye=(s,e)=>sealData(s,{password:e}),ve=(s,e)=>unsealData(s,{password:e});
|
|
2
|
+
export{u as BaseProfileFetcher,A as GenericOAuth2Provider,h as GenericProfileFetcher,w as GitHubProfileFetcher,S as GoogleProfileFetcher,T as InMemoryStorageAdapter,U as MicrosoftProfileFetcher,F as OAuth2Client,k as OAuth2Provider,E as ProfileFetcherFactory,v as StandardAuthorizationUrlStrategy,x as StandardTokenExchangeStrategy,_ as createCodeChallenge,z as createCodeVerifier,I as generateState,ye as seal,ve as unseal};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/strategies/standard-authorization-url.strategy.ts","../src/strategies/standard-token-exchange.strategy.ts","../src/providers/base.provider.ts","../src/providers/generic.provider.ts","../src/profile/base-profile-fetcher.ts","../src/profile/google-profile-fetcher.ts","../src/profile/github-profile-fetcher.ts","../src/profile/microsoft-profile-fetcher.ts","../src/profile/generic-profile-fetcher.ts","../src/profile/profile-fetcher-factory.ts","../src/providers/provider.factory.ts","../src/storage/memory.adapter.ts","../src/utils/crypto.ts","../src/facade/oauth2.facade.ts","../src/utils/seal.ts"],"names":["StandardAuthorizationUrlStrategy","params","value","key","config","state","codeChallenge","extraParams","StandardTokenExchangeStrategy","code","codeVerifier","response","errorText","data","tokenData","now","expiresIn","refreshToken","OAuth2Provider","authUrlStrategy","tokenStrategy","profileFetcher","accessToken","GenericOAuth2Provider","BaseProfileFetcher","profileEndpoint","rawData","GoogleProfileFetcher","GitHubProfileFetcher","_a","MicrosoftProfileFetcher","GenericProfileFetcher","mapping","additionalHeaders","obj","path","current","ProfileFetcherFactory","providerType","options","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","presetConfig","mergedConfig","name","InMemoryStorageAdapter","input","existingToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","token","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","_b","_c","customFetcher","authUrl","authState","_d","_e","providerInstance","tenantName","profile","error","savedToken","storedToken","tenantInfo","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData"],"mappings":"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","file":"index.js","sourcesContent":["import { OAuth2Config } from '../types';\nimport { AuthorizationUrlStrategy } from './authorization-url.strategy';\n\nexport class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n generateAuthorizationUrl(config: OAuth2Config, state: string, codeChallenge?: string): string {\n const params: Record<string, string | undefined> = {\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n response_type: 'code',\n scope: config.scopes.join(' '),\n state,\n };\n\n // Add PKCE parameters\n if ((config.usePKCE || config.pkce) && codeChallenge) {\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Merge additional parameters (for both additionalParams and extraAuthParams)\n const extraParams = {\n ...config.additionalParams,\n ...config.extraAuthParams,\n };\n\n Object.assign(params, extraParams);\n\n return `${config.authorizationUrl}?${this.buildUrlParams(params)}`;\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\nimport { TokenExchangeStrategy } from './token-exchange.strategy';\n\nexport class StandardTokenExchangeStrategy implements TokenExchangeStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n async exchangeCodeForToken(\n code: string,\n config: OAuth2Config,\n codeVerifier?: string,\n ): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n };\n\n // Handle PKCE\n if ((config.usePKCE || config.pkce) && codeVerifier) {\n params.code_verifier = codeVerifier;\n } else if (config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n\n // Handle nested response (e.g., Outlook might nest tokens)\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n const now = Date.now();\n const expiresIn = tokenData.expires_in || 3600;\n\n return {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token,\n expiresAt: new Date(now + expiresIn * 1000),\n expiresIn: expiresIn,\n tokenType: tokenData.token_type || 'Bearer',\n scope: tokenData.scope,\n createdAt: now,\n raw: data,\n };\n }\n\n async refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.clientId,\n };\n\n // Only add client_secret if not using PKCE\n if (!(config.usePKCE || config.pkce) && config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n const now = Date.now();\n const expiresIn = tokenData.expires_in || 3600;\n\n return {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token || refreshToken,\n expiresAt: new Date(now + expiresIn * 1000),\n expiresIn: expiresIn,\n tokenType: tokenData.token_type || 'Bearer',\n scope: tokenData.scope,\n createdAt: now,\n raw: data,\n };\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\n\nimport { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { UserProfile } from './interfaces/profile-fetcher.interface';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport abstract class OAuth2Provider {\n protected authUrlStrategy: AuthorizationUrlStrategy;\n protected tokenStrategy: TokenExchangeStrategy;\n protected profileFetcher?: BaseProfileFetcher;\n\n constructor(\n protected config: OAuth2Config,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n this.authUrlStrategy = authUrlStrategy || this.createAuthorizationUrlStrategy();\n this.tokenStrategy = tokenStrategy || this.createTokenExchangeStrategy();\n this.profileFetcher = profileFetcher;\n }\n\n // Factory methods\n protected abstract createAuthorizationUrlStrategy(): AuthorizationUrlStrategy;\n protected abstract createTokenExchangeStrategy(): TokenExchangeStrategy;\n\n // Profile fetching methods\n async fetchProfile(accessToken: string): Promise<UserProfile> {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.fetchUserInfo(accessToken);\n }\n\n getProfileEndpoint(): string {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.getEndpoint();\n }\n\n setProfileFetcher(profileFetcher: BaseProfileFetcher): void {\n this.profileFetcher = profileFetcher;\n }\n\n hasProfileFetcher(): boolean {\n return !!this.profileFetcher;\n }\n\n generateAuthorizationUrl(state: string, codeChallenge?: string): string {\n return this.authUrlStrategy.generateAuthorizationUrl(this.config, state, codeChallenge);\n }\n\n async exchangeCodeForToken(code: string, codeVerifier?: string): Promise<OAuth2Token> {\n return this.tokenStrategy.exchangeCodeForToken(code, this.config, codeVerifier);\n }\n\n async refreshToken(refreshToken: string): Promise<OAuth2Token> {\n return this.tokenStrategy.refreshToken(refreshToken, this.config);\n }\n}\n","import { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { StandardAuthorizationUrlStrategy } from '../strategies/standard-authorization-url.strategy';\nimport { StandardTokenExchangeStrategy } from '../strategies/standard-token-exchange.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { OAuth2Provider } from './base.provider';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class GenericOAuth2Provider extends OAuth2Provider {\n constructor(\n config: any,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n super(config, authUrlStrategy, tokenStrategy, profileFetcher);\n }\n\n protected createAuthorizationUrlStrategy(): AuthorizationUrlStrategy {\n return new StandardAuthorizationUrlStrategy();\n }\n\n protected createTokenExchangeStrategy(): TokenExchangeStrategy {\n return new StandardTokenExchangeStrategy();\n }\n}\n","import { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport abstract class BaseProfileFetcher {\n constructor(protected profileEndpoint: string) {}\n\n /**\n * Fetch user profile information from the OAuth provider\n * @param accessToken The OAuth access token\n * @returns Promise resolving to standardized user profile\n */\n async fetchUserInfo(accessToken: string): Promise<UserProfile> {\n const response = await fetch(this.profileEndpoint, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n ...this.getAdditionalHeaders(),\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch profile from ${this.profileEndpoint}: ${response.statusText}`,\n );\n }\n\n const rawData = await response.json();\n return this.mapToUserProfile(rawData);\n }\n\n /**\n * Map the raw API response to our standardized UserProfile structure\n * Override this method to customize mapping for different providers\n */\n protected abstract mapToUserProfile(rawData: any): UserProfile;\n\n /**\n * Get additional headers if needed for the profile request\n * Override this method to add provider-specific headers\n */\n protected getAdditionalHeaders(): Record<string, string> {\n return {};\n }\n\n /**\n * Get the profile endpoint URL\n */\n getEndpoint(): string {\n return this.profileEndpoint;\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GoogleProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://www.googleapis.com/oauth2/v2/userinfo');\n }\n\n mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name,\n id: rawData.id,\n avatar: rawData.picture,\n username: rawData.email,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GitHubProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://api.github.com/user');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name || rawData.login,\n id: rawData.id?.toString(),\n avatar: rawData.avatar_url,\n username: rawData.login,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return {\n 'User-Agent': 'OAuth2-Token-Manager', // GitHub requires User-Agent\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class MicrosoftProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://graph.microsoft.com/v1.0/me');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.mail || rawData.userPrincipalName,\n name: rawData.displayName,\n id: rawData.id,\n avatar: undefined, // Microsoft Graph doesn't include avatar in basic profile\n username: rawData.userPrincipalName,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface ProfileMapping {\n email: string;\n name?: string;\n id?: string;\n avatar?: string;\n username?: string;\n}\n\nexport class GenericProfileFetcher extends BaseProfileFetcher {\n constructor(\n profileEndpoint: string,\n private mapping?: ProfileMapping,\n private additionalHeaders?: Record<string, string>,\n ) {\n super(profileEndpoint);\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n if (this.mapping) {\n return {\n email: this.getNestedProperty(rawData, this.mapping.email),\n name: this.mapping.name ? this.getNestedProperty(rawData, this.mapping.name) : undefined,\n id: this.mapping.id ? this.getNestedProperty(rawData, this.mapping.id) : undefined,\n avatar: this.mapping.avatar\n ? this.getNestedProperty(rawData, this.mapping.avatar)\n : undefined,\n username: this.mapping.username\n ? this.getNestedProperty(rawData, this.mapping.username)\n : undefined,\n raw: rawData,\n };\n }\n\n // Default generic mapping\n return {\n email: rawData.email || rawData.mail || rawData.emailAddress,\n name: rawData.name || rawData.displayName || rawData.full_name,\n id: rawData.id || rawData.sub || rawData.user_id,\n avatar: rawData.avatar || rawData.picture || rawData.avatar_url,\n username: rawData.username || rawData.login || rawData.preferred_username,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return this.additionalHeaders || {};\n }\n\n private getNestedProperty(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { GoogleProfileFetcher } from './google-profile-fetcher';\nimport { GitHubProfileFetcher } from './github-profile-fetcher';\nimport { MicrosoftProfileFetcher } from './microsoft-profile-fetcher';\nimport { GenericProfileFetcher, ProfileMapping } from './generic-profile-fetcher';\nimport { ProviderType } from '../providers/provider.factory';\nimport { OAuth2Config } from '../types';\n\nexport interface ProfileFetcherOptions {\n profileUrl?: string;\n profileMapping?: ProfileMapping;\n profileHeaders?: Record<string, string>;\n}\n\nexport class ProfileFetcherFactory {\n static createProfileFetcher(\n providerType: ProviderType,\n config: OAuth2Config,\n options?: ProfileFetcherOptions,\n ): BaseProfileFetcher {\n // If custom options are provided, use GenericProfileFetcher\n if (options?.profileUrl) {\n return new GenericProfileFetcher(\n options.profileUrl,\n options.profileMapping,\n options.profileHeaders,\n );\n }\n\n // Use provider-specific fetchers for known providers\n switch (providerType) {\n case 'google':\n return new GoogleProfileFetcher();\n case 'github':\n return new GitHubProfileFetcher();\n case 'microsoft':\n case 'outlook':\n return new MicrosoftProfileFetcher();\n case 'facebook':\n return new GenericProfileFetcher(\n 'https://graph.facebook.com/me?fields=id,name,email,picture',\n );\n case 'generic':\n default:\n // For generic providers, use the profileUrl from config\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n throw new Error(`Profile URL must be provided for ${providerType} provider`);\n }\n return new GenericProfileFetcher(profileUrl);\n }\n }\n\n static registerCustomProfileFetcher(\n providerName: string,\n profileFetcher: BaseProfileFetcher,\n ): void {\n // Store custom profile fetchers for later use\n this.customFetchers.set(providerName, profileFetcher);\n }\n\n private static customFetchers = new Map<string, BaseProfileFetcher>();\n\n static getCustomProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.customFetchers.get(providerName);\n }\n}\n","import { OAuth2Config } from '../types';\nimport { OAuth2Provider } from './base.provider';\nimport { GenericOAuth2Provider } from './generic.provider';\nimport { ProfileFetcherFactory } from '../profile/profile-fetcher-factory';\n\nexport type ProviderType = 'google' | 'github' | 'microsoft' | 'outlook' | 'facebook' | 'generic';\n\nexport interface ProviderFactory {\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider;\n}\n\nexport class OAuth2ProviderFactory implements ProviderFactory {\n private static presetConfigs: Record<string, Partial<OAuth2Config>> = {\n google: {\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n profileUrl: 'https://www.googleapis.com/oauth2/v2/userinfo',\n usePKCE: true,\n extraAuthParams: {\n access_type: 'offline',\n prompt: 'consent',\n },\n },\n github: {\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n profileUrl: 'https://api.github.com/user',\n },\n microsoft: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n },\n outlook: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n extraAuthParams: {\n prompt: 'select_account',\n },\n },\n facebook: {\n authorizationUrl: 'https://www.facebook.com/v12.0/dialog/oauth',\n tokenUrl: 'https://graph.facebook.com/v12.0/oauth/access_token',\n profileUrl: 'https://graph.facebook.com/me?fields=id,name,email,picture',\n },\n };\n\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider {\n const presetConfig = type !== 'generic' ? OAuth2ProviderFactory.presetConfigs[type] || {} : {};\n\n // Only override preset values if the user explicitly provides them (not empty strings)\n const mergedConfig: OAuth2Config = {\n ...presetConfig,\n ...config,\n // Don't override preset URLs with empty strings\n authorizationUrl: config.authorizationUrl || presetConfig.authorizationUrl || '',\n tokenUrl: config.tokenUrl || presetConfig.tokenUrl || '',\n profileUrl: config.profileUrl || presetConfig.profileUrl,\n extraAuthParams: {\n ...(presetConfig.extraAuthParams || {}),\n ...(config.extraAuthParams || {}),\n },\n };\n\n const profileFetcher = ProfileFetcherFactory.createProfileFetcher(type, mergedConfig);\n\n return new GenericOAuth2Provider(mergedConfig, undefined, undefined, profileFetcher);\n }\n\n static registerPreset(name: string, config: Partial<OAuth2Config>): void {\n OAuth2ProviderFactory.presetConfigs[name] = config;\n }\n\n static getPresetConfig(name: string): Partial<OAuth2Config> | undefined {\n return OAuth2ProviderFactory.presetConfigs[name];\n }\n}\n","import { AuthorizationState } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class InMemoryStorageAdapter implements StorageAdapter {\n private tokens: Map<string, StoredToken> = new Map();\n private states: Map<string, AuthorizationState> = new Map();\n private profileFetchers: Map<string, BaseProfileFetcher> = new Map();\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n const existingToken = await this.getToken(input.provider, input.email, input.tenant);\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...input,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n return updatedToken;\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...input,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n return newToken;\n }\n\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n let tokens = Array.from(this.tokens.values());\n\n // Apply filters\n if (query.id) {\n tokens = tokens.filter((t) => t.id === query.id);\n }\n if (query.provider) {\n tokens = tokens.filter((t) => t.provider === query.provider);\n }\n if (query.userId) {\n tokens = tokens.filter((t) => t.userId === query.userId);\n }\n if (query.email) {\n tokens = tokens.filter((t) => t.email === query.email);\n }\n if (query.tenant !== undefined) {\n tokens = tokens.filter((t) => t.tenant === query.tenant);\n }\n\n // Filter out expired tokens unless explicitly requested\n if (!query.includeExpired) {\n const now = new Date().getTime();\n tokens = tokens.filter((t) => {\n const expiresAt = new Date(t.token.expiresAt).getTime();\n return expiresAt >= now;\n });\n }\n\n // Apply pagination\n if (query.offset !== undefined) {\n tokens = tokens.slice(query.offset);\n }\n if (query.limit !== undefined) {\n tokens = tokens.slice(0, query.limit);\n }\n\n return tokens;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ provider, email, tenant, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ id, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n async getTokensByProvider(provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider });\n }\n\n async getAccounts(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async getTokensForEmail(\n userId: string,\n provider: string,\n email: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokens({ userId, provider, email });\n return results[0] || null;\n }\n\n async getTokens(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async updateToken(id: string, update: UpdateTokenInput): Promise<StoredToken | null> {\n const token = this.tokens.get(id);\n if (!token) return null;\n\n const updatedToken: StoredToken = {\n ...token,\n ...(update.token && { token: update.token }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n return updatedToken;\n }\n\n async deleteToken(id: string): Promise<boolean> {\n return this.tokens.delete(id);\n }\n\n async deleteTokenByProviderEmail(provider: string, email: string, tenant?: string): Promise<boolean> {\n const token = await this.getToken(provider, email, tenant);\n if (!token) return false;\n return this.tokens.delete(token.id);\n }\n\n async deleteExpiredTokens(): Promise<number> {\n const now = new Date().getTime();\n const expiredTokens = Array.from(this.tokens.entries())\n .filter(([, token]) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt < now;\n })\n .map(([id]) => id);\n\n expiredTokens.forEach((id) => this.tokens.delete(id));\n return expiredTokens.length;\n }\n\n // Authorization state operations\n async saveAuthorizationState(\n state: Omit<AuthorizationState, 'createdAt'>,\n ): Promise<AuthorizationState> {\n const newState: AuthorizationState = {\n ...state,\n createdAt: new Date(Date.now()),\n };\n this.states.set(state.state, newState);\n return newState;\n }\n\n async getAuthorizationState(state: string): Promise<AuthorizationState | null> {\n return this.states.get(state) || null;\n }\n\n async deleteAuthorizationState(state: string): Promise<boolean> {\n return this.states.delete(state);\n }\n\n async cleanupExpiredStates(): Promise<number> {\n const now = new Date().getTime();\n const maxAge = 10 * 60 * 1000; // 10 minutes\n\n const expiredStates = Array.from(this.states.entries())\n .filter(([, state]) => {\n const stateAge = now - state.createdAt.getTime();\n return stateAge > maxAge;\n })\n .map(([key]) => key);\n\n expiredStates.forEach((key) => this.states.delete(key));\n return expiredStates.length;\n }\n\n // Profile fetcher operations\n registerProfileFetcher(providerName: string, fetcher: BaseProfileFetcher): void {\n this.profileFetchers.set(providerName, fetcher);\n }\n\n getProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.profileFetchers.get(providerName);\n }\n\n getProfileFetchers(): Map<string, BaseProfileFetcher> {\n return new Map(this.profileFetchers);\n }\n}\n","import { createHash, randomBytes } from 'crypto';\n\nexport const createCodeVerifier = () =>\n randomBytes(32)\n .toString('base64')\n .replace(/[^a-zA-Z0-9]/g, '')\n .substring(0, 128);\n\nexport const createCodeChallenge = (verifier: string): string => {\n return createHash('sha256').update(verifier).digest('base64url');\n};\n\nexport const generateState = (): string => {\n return randomBytes(16).toString('base64url');\n};\n","import { OAuth2Config, OAuth2Token, AuthorizationState } from '../types';\nimport { OAuth2ProviderFactory, ProviderType } from '../providers/provider.factory';\nimport { StorageAdapter, StoredToken, TokenQuery } from '../storage/interfaces';\nimport { InMemoryStorageAdapter } from '../storage/memory.adapter';\nimport { ProviderFactory } from '../providers/provider.factory';\nimport { createCodeVerifier, createCodeChallenge, generateState } from '../utils/crypto';\nimport { OAuth2Provider } from '../providers/base.provider';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface OAuth2Options {\n storage?: StorageAdapter;\n providers?: Record<string, OAuth2Config>;\n autoRefresh?: AutoRefreshOptions;\n}\n\nexport interface AutoRefreshOptions {\n enabled?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n onRefreshError?: (error: Error, token: StoredToken) => void;\n}\n\nexport interface AuthorizationOptions {\n provider: string;\n userId: string;\n email: string;\n tenant?: string; // For multi-tenant providers like Slack\n tenantName?: string; // Human-readable tenant name\n scopes?: string[];\n metadata?: Record<string, any>;\n usePKCE?: boolean;\n}\n\nexport interface TokenOptions {\n autoRefresh?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n expirationBuffer?: number; // seconds before expiry to consider expired\n defaultExpiresIn?: number; // default expiration in seconds\n}\n\nexport interface CallbackResult {\n token: StoredToken;\n profile?: UserProfile;\n}\n\nexport class OAuth2Client {\n private storage: StorageAdapter;\n private providerFactory: ProviderFactory;\n private providers: Map<string, OAuth2Provider> = new Map();\n private providerConfigs: Map<string, OAuth2Config> = new Map();\n private now: () => number;\n private autoRefreshOptions: AutoRefreshOptions;\n\n constructor(options: OAuth2Options = {}) {\n this.storage = options.storage || new InMemoryStorageAdapter();\n this.providerFactory = new OAuth2ProviderFactory();\n this.now = Date.now;\n\n // Set default auto-refresh options - enabled by default\n this.autoRefreshOptions = {\n enabled: options.autoRefresh?.enabled ?? true, // Enabled by default\n refreshBuffer: options.autoRefresh?.refreshBuffer ?? 10, // 10 minutes before expiry (safe for Google's 1-hour tokens)\n onRefreshError: options.autoRefresh?.onRefreshError,\n };\n\n // Register predefined providers\n if (options.providers) {\n Object.entries(options.providers).forEach(([name, config]) => {\n this.registerProvider(name, config);\n });\n }\n }\n\n /**\n * Register a provider configuration\n */\n registerProvider(name: string, config: OAuth2Config): void {\n this.providerConfigs.set(name, config);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config);\n\n // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n if (customFetcher) {\n provider.setProfileFetcher(customFetcher);\n }\n\n this.providers.set(name, provider);\n }\n\n /**\n * Start OAuth2 authorization flow\n */\n async authorize(options: AuthorizationOptions): Promise<{ url: string; state: string }> {\n const provider = this.providers.get(options.provider);\n if (!provider) throw new Error(`Provider ${options.provider} not found`);\n\n const state = generateState();\n let authUrl: string;\n let authState: Omit<AuthorizationState, 'createdAt'>;\n\n const requiresPKCE = this.providerConfigs.get(options.provider)?.usePKCE || options.usePKCE;\n\n if (requiresPKCE) {\n const codeVerifier = createCodeVerifier();\n const codeChallenge = createCodeChallenge(codeVerifier);\n authUrl = provider.generateAuthorizationUrl(state, codeChallenge);\n authState = {\n state,\n codeVerifier,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n } else {\n authUrl = provider.generateAuthorizationUrl(state);\n authState = {\n state,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n }\n\n await this.storage.saveAuthorizationState(authState);\n return { url: authUrl, state };\n }\n\n /**\n * Handle OAuth2 callback\n */\n async handleCallback(code: string, state: string): Promise<CallbackResult> {\n const authState = await this.storage.getAuthorizationState(state);\n if (!authState) throw new Error('Invalid or expired state');\n\n const provider = authState.metadata?.provider;\n if (!provider) throw new Error('Provider not found in authorization state');\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n // Exchange code for tokens\n const tokens = await providerInstance.exchangeCodeForToken(code, authState.codeVerifier);\n\n // Extract user data from metadata\n const userId = authState.metadata?.userId;\n const email = authState.metadata?.email;\n const tenant = authState.metadata?.tenant;\n const tenantName = authState.metadata?.tenantName;\n\n if (!userId || !email) {\n throw new Error('User ID and email are required in authorization state');\n }\n\n // Fetch profile if available\n let profile: UserProfile | undefined;\n if (providerInstance.hasProfileFetcher()) {\n try {\n profile = await providerInstance.fetchProfile(tokens.accessToken);\n } catch (error) {\n console.warn('Failed to fetch user profile:', error);\n }\n }\n\n // Save token\n const savedToken = await this.storage.saveToken({\n provider,\n userId,\n email: profile?.email || email,\n tenant,\n tenantName,\n token: tokens,\n metadata: {\n ...authState.metadata,\n profileFetched: !!profile,\n },\n });\n\n // Clean up authorization state\n await this.storage.deleteAuthorizationState(state);\n\n // Call onSuccess callback if defined\n const config = this.providerConfigs.get(provider);\n if (config?.onSuccess) {\n await config.onSuccess(userId, tokens);\n }\n\n return {\n token: savedToken,\n profile,\n };\n }\n\n /**\n * Get a valid access token (auto-refresh if needed)\n */\n async getAccessToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<string> {\n const token = await this.getValidToken(provider, email, options);\n return token.accessToken;\n }\n\n /**\n * Get a valid token (auto-refresh if needed)\n */\n async getValidToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<OAuth2Token> {\n const storedToken = await this.storage.getToken(provider, email, options.tenant);\n if (!storedToken) {\n const tenantInfo = options.tenant ? ` and tenant ${options.tenant}` : '';\n throw new Error(`No token found for provider ${provider}, email ${email}${tenantInfo}`);\n }\n\n const needsRefresh =\n options.autoRefresh !== false && this.isTokenExpired(storedToken.token, options);\n\n if (!needsRefresh) {\n return storedToken.token;\n }\n\n // Refresh the token\n if (!storedToken.token.refreshToken) {\n throw new Error('Token expired and no refresh token available');\n }\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n const newToken = await providerInstance.refreshToken(storedToken.token.refreshToken);\n await this.storage.updateToken(storedToken.id, { token: newToken });\n\n return newToken;\n }\n\n /**\n * Query tokens with automatic refresh\n */\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n // When auto-refresh is enabled, we need to include expired tokens\n // so we can attempt to refresh them\n const queryWithExpired =\n this.autoRefreshOptions.enabled && !query.includeExpired\n ? { ...query, includeExpired: true }\n : query;\n\n const tokens = await this.storage.queryTokens(queryWithExpired);\n\n if (this.autoRefreshOptions.enabled && !query.includeExpired) {\n const refreshedTokens = await this.refreshTokensIfNeeded(tokens);\n // Filter out tokens that are still expired after refresh attempt\n return refreshedTokens.filter((token) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt > this.now();\n });\n }\n\n return tokens;\n }\n\n /**\n * Get all tokens for a user\n */\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n /**\n * Get all tokens for an email\n */\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n /**\n * Delete a token\n */\n async deleteToken(provider: string, email: string, tenant?: string): Promise<boolean> {\n return this.storage.deleteTokenByProviderEmail(provider, email, tenant);\n }\n\n /**\n * Delete all expired tokens\n */\n async cleanupExpiredTokens(): Promise<number> {\n return this.storage.deleteExpiredTokens();\n }\n\n /**\n * Clean up expired authorization states\n */\n async cleanupExpiredStates(): Promise<number> {\n return this.storage.cleanupExpiredStates();\n }\n\n // Helper methods\n private isTokenExpired(token: OAuth2Token, options: TokenOptions = {}): boolean {\n const { expirationBuffer = 300 } = options;\n\n if (token.createdAt && token.expiresIn !== undefined) {\n const expiresAt = token.createdAt + token.expiresIn * 1000;\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n const expiresAt = new Date(token.expiresAt).getTime();\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n private detectProviderType(name: string, config: OAuth2Config): ProviderType {\n // Try to detect based on the authorization URL\n const authUrl = config.authorizationUrl.toLowerCase();\n\n // Check for known providers that have specific implementations\n if (authUrl.includes('accounts.google.com')) return 'google';\n if (authUrl.includes('github.com')) return 'github';\n if (authUrl.includes('facebook.com')) return 'facebook';\n if (authUrl.includes('microsoft.com') || authUrl.includes('microsoftonline.com')) {\n // Check if it's specifically for Outlook\n if (\n name.toLowerCase().includes('outlook') ||\n config.scopes?.some((s) => s.includes('outlook'))\n ) {\n return 'outlook';\n }\n return 'microsoft';\n }\n\n // Default to generic provider for all others\n return 'generic';\n }\n\n /**\n * Refresh tokens if they are near expiration\n */\n private async refreshTokensIfNeeded(tokens: StoredToken[]): Promise<StoredToken[]> {\n const refreshPromises = tokens.map(async (token) => {\n if (this.shouldRefreshToken(token)) {\n try {\n const provider = this.providers.get(token.provider);\n if (!provider) {\n console.warn(`Provider ${token.provider} not found for token refresh`);\n return token;\n }\n\n if (!token.token.refreshToken) {\n console.warn(`No refresh token available for ${token.provider}:${token.email}`);\n return token;\n }\n\n const newToken = await provider.refreshToken(token.token.refreshToken);\n const updated = await this.storage.updateToken(token.id, { token: newToken });\n return updated || token;\n } catch (error) {\n if (this.autoRefreshOptions.onRefreshError) {\n this.autoRefreshOptions.onRefreshError(error as Error, token);\n }\n console.error(`Failed to refresh token for ${token.provider}:${token.email}:`, error);\n return token;\n }\n }\n return token;\n });\n\n return Promise.all(refreshPromises);\n }\n\n /**\n * Check if a token should be refreshed\n */\n private shouldRefreshToken(storedToken: StoredToken): boolean {\n // Skip if no refresh token\n if (!storedToken.token.refreshToken) {\n return false;\n }\n\n // Check if token is expired or near expiration\n const expiresAt = new Date(storedToken.token.expiresAt).getTime();\n const now = this.now();\n\n // If already expired, definitely try to refresh\n if (now >= expiresAt) {\n return true;\n }\n\n // Otherwise, check if within refresh buffer\n const bufferMs = this.autoRefreshOptions.refreshBuffer! * 60 * 1000;\n const shouldRefreshAt = expiresAt - bufferMs;\n\n return now >= shouldRefreshAt;\n }\n\n /**\n * Update auto-refresh options\n */\n updateAutoRefreshOptions(options: Partial<AutoRefreshOptions>): void {\n this.autoRefreshOptions = { ...this.autoRefreshOptions, ...options };\n }\n\n /**\n * Get all tokens for a specific provider and user across all tenants\n */\n async getTokensAcrossTenants(provider: string, userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider, userId });\n }\n\n /**\n * Get all tenants for a specific provider and email\n */\n async getTenants(provider: string, email: string): Promise<string[]> {\n const tokens = await this.queryTokens({ provider, email });\n const tenants = tokens\n .map((t) => t.tenant)\n .filter((tenant): tenant is string => tenant !== undefined);\n return [...new Set(tenants)]; // Return unique tenants\n }\n\n /**\n * Get token by tenant name (useful for Slack workspaces with human-readable names)\n */\n async getTokenByTenantName(\n provider: string,\n email: string,\n tenantName: string,\n ): Promise<StoredToken | null> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.find((t) => t.tenantName === tenantName) || null;\n }\n\n /**\n * Check if a token exists for a specific tenant\n */\n async hasTokenForTenant(\n provider: string,\n email: string,\n tenant: string,\n ): Promise<boolean> {\n const token = await this.storage.getToken(provider, email, tenant);\n return token !== null;\n }\n\n /**\n * Get all tokens with their tenant information\n */\n async getMultiTenantTokens(\n provider: string,\n email: string,\n ): Promise<Array<{ token: StoredToken; tenant?: string; tenantName?: string }>> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.map((token) => ({\n token,\n tenant: token.tenant,\n tenantName: token.tenantName,\n }));\n }\n}\n","import { sealData, unsealData } from 'iron-session';\n\nexport const seal = <T>(d: T, key: string) => sealData(d, { password: key });\nexport const unseal = <T>(s: string, key: string) => unsealData<T>(s, { password: key });\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/strategies/standard-authorization-url.strategy.ts","../src/strategies/standard-token-exchange.strategy.ts","../src/providers/base.provider.ts","../src/providers/generic.provider.ts","../src/profile/base-profile-fetcher.ts","../src/profile/google-profile-fetcher.ts","../src/profile/github-profile-fetcher.ts","../src/profile/microsoft-profile-fetcher.ts","../src/profile/generic-profile-fetcher.ts","../src/profile/profile-fetcher-factory.ts","../src/providers/provider.factory.ts","../src/storage/memory.adapter.ts","../src/utils/crypto.ts","../src/facade/oauth2.facade.ts","../src/utils/seal.ts"],"names":["StandardAuthorizationUrlStrategy","params","value","key","config","state","codeChallenge","extraParams","StandardTokenExchangeStrategy","code","codeVerifier","response","errorText","data","tokenData","refreshToken","rawResponse","refreshTokenFallback","_a","_b","_c","_d","_e","now","accessToken","rawRefreshToken","rawExpiresIn","expiresInSeconds","scope","tokenType","obj","customPaths","defaultPaths","paths","path","keys","current","OAuth2Provider","authUrlStrategy","tokenStrategy","profileFetcher","GenericOAuth2Provider","BaseProfileFetcher","profileEndpoint","rawData","GoogleProfileFetcher","GitHubProfileFetcher","MicrosoftProfileFetcher","GenericProfileFetcher","mapping","additionalHeaders","ProfileFetcherFactory","providerType","options","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","presetConfig","mergedConfig","name","InMemoryStorageAdapter","input","existingToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","token","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","customFetcher","authUrl","authState","providerInstance","tenantName","profile","error","savedToken","storedToken","tenantInfo","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData"],"mappings":"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","file":"index.js","sourcesContent":["import { OAuth2Config } from '../types';\nimport { AuthorizationUrlStrategy } from './authorization-url.strategy';\n\nexport class StandardAuthorizationUrlStrategy implements AuthorizationUrlStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n generateAuthorizationUrl(config: OAuth2Config, state: string, codeChallenge?: string): string {\n const params: Record<string, string | undefined> = {\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n response_type: 'code',\n scope: config.scopes.join(' '),\n state,\n };\n\n // Add PKCE parameters\n if ((config.usePKCE || config.pkce) && codeChallenge) {\n params.code_challenge = codeChallenge;\n params.code_challenge_method = 'S256';\n }\n\n // Merge additional parameters (for both additionalParams and extraAuthParams)\n const extraParams = {\n ...config.additionalParams,\n ...config.extraAuthParams,\n };\n\n Object.assign(params, extraParams);\n\n return `${config.authorizationUrl}?${this.buildUrlParams(params)}`;\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\nimport { TokenExchangeStrategy } from './token-exchange.strategy';\n\nexport class StandardTokenExchangeStrategy implements TokenExchangeStrategy {\n protected buildUrlParams(params: Record<string, string | undefined>): string {\n const filtered = Object.entries(params)\n .filter(([, value]) => value !== undefined)\n .map(([key, value]) => `${key}=${encodeURIComponent(value as string)}`);\n\n return filtered.join('&');\n }\n\n async exchangeCodeForToken(\n code: string,\n config: OAuth2Config,\n codeVerifier?: string,\n ): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'authorization_code',\n code,\n redirect_uri: config.redirectUri,\n client_id: config.clientId,\n };\n\n // Handle PKCE\n if ((config.usePKCE || config.pkce) && codeVerifier) {\n params.code_verifier = codeVerifier;\n } else if (config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n\n // Handle nested response (e.g., Outlook might nest tokens)\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n return this.normalizeTokenResponse(tokenData, data, undefined, config);\n }\n\n async refreshToken(refreshToken: string, config: OAuth2Config): Promise<OAuth2Token> {\n const params: Record<string, string | undefined> = {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: config.clientId,\n };\n\n // Only add client_secret if not using PKCE\n if (!(config.usePKCE || config.pkce) && config.clientSecret) {\n params.client_secret = config.clientSecret;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: this.buildUrlParams(params),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.statusText} - ${errorText}`);\n }\n\n const data = await response.json();\n const tokenData = config.responseRootKey ? data[config.responseRootKey] : data;\n\n return this.normalizeTokenResponse(tokenData, data, refreshToken, config);\n }\n\n protected normalizeTokenResponse(\n tokenData: Record<string, any>,\n rawResponse: Record<string, any>,\n refreshTokenFallback?: string,\n config?: OAuth2Config,\n ): OAuth2Token {\n const now = Date.now();\n\n // Extract values using custom paths if provided, otherwise use defaults\n const accessToken = this.extractValue(\n tokenData,\n config?.tokenPaths?.accessToken,\n // Default paths: For providers like Slack that return both bot and user tokens,\n // prioritize the user token in authed_user over the root-level bot token\n [\n 'authed_user.access_token',\n 'authed_user.accessToken',\n 'access_token',\n 'accessToken',\n 'token.access_token',\n 'token.accessToken',\n ],\n );\n\n if (!accessToken) {\n throw new Error('Token response did not include an access_token');\n }\n\n const rawRefreshToken =\n this.extractValue(tokenData, config?.tokenPaths?.refreshToken, [\n 'authed_user.refresh_token',\n 'authed_user.refreshToken',\n 'refresh_token',\n 'refreshToken',\n 'token.refresh_token',\n 'token.refreshToken',\n ]) ?? refreshTokenFallback;\n\n const rawExpiresIn = this.extractValue(tokenData, config?.tokenPaths?.expiresIn, [\n 'authed_user.expires_in',\n 'authed_user.expiresIn',\n 'expires_in',\n 'expiresIn',\n 'token.expires_in',\n 'token.expiresIn',\n ]);\n\n const parsedExpiresIn =\n typeof rawExpiresIn === 'string' ? parseInt(rawExpiresIn, 10) : rawExpiresIn;\n\n const expiresInSeconds = parsedExpiresIn || 3600;\n\n const scope = this.extractValue(tokenData, config?.tokenPaths?.scope, [\n 'authed_user.scope',\n 'scope',\n 'token.scope',\n ]);\n\n const tokenType =\n this.extractValue(tokenData, config?.tokenPaths?.tokenType, [\n 'authed_user.token_type',\n 'authed_user.tokenType',\n 'token_type',\n 'tokenType',\n 'token.token_type',\n 'token.tokenType',\n ]) ?? 'Bearer';\n\n return {\n accessToken,\n refreshToken: rawRefreshToken,\n expiresAt: new Date(now + expiresInSeconds * 1000),\n expiresIn: expiresInSeconds,\n tokenType,\n scope,\n createdAt: now,\n raw: rawResponse,\n };\n }\n\n /**\n * Extract a value from a nested object using a dot-notation path\n * @param obj The object to extract from\n * @param customPaths Custom path(s) provided by config (takes priority)\n * @param defaultPaths Default fallback paths to try\n * @returns The extracted value or undefined\n */\n private extractValue(\n obj: Record<string, any>,\n customPaths?: string | string[],\n defaultPaths?: string[],\n ): any {\n // Try custom paths first if provided\n if (customPaths) {\n const paths = Array.isArray(customPaths) ? customPaths : [customPaths];\n for (const path of paths) {\n const value = this.getNestedValue(obj, path);\n if (value !== undefined) return value;\n }\n }\n\n // Fall back to default paths\n if (defaultPaths) {\n for (const path of defaultPaths) {\n const value = this.getNestedValue(obj, path);\n if (value !== undefined) return value;\n }\n }\n\n return undefined;\n }\n\n /**\n * Get a nested value from an object using dot notation (e.g., 'authed_user.access_token')\n * @param obj The object to traverse\n * @param path The dot-notation path\n * @returns The value at the path or undefined\n */\n private getNestedValue(obj: Record<string, any>, path: string): any {\n const keys = path.split('.');\n let current: any = obj;\n\n for (const key of keys) {\n if (current && typeof current === 'object' && key in current) {\n current = current[key];\n } else {\n return undefined;\n }\n }\n\n return current;\n }\n}\n","import { OAuth2Config, OAuth2Token } from '../types';\n\nimport { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { UserProfile } from './interfaces/profile-fetcher.interface';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport abstract class OAuth2Provider {\n protected authUrlStrategy: AuthorizationUrlStrategy;\n protected tokenStrategy: TokenExchangeStrategy;\n protected profileFetcher?: BaseProfileFetcher;\n\n constructor(\n protected config: OAuth2Config,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n this.authUrlStrategy = authUrlStrategy || this.createAuthorizationUrlStrategy();\n this.tokenStrategy = tokenStrategy || this.createTokenExchangeStrategy();\n this.profileFetcher = profileFetcher;\n }\n\n // Factory methods\n protected abstract createAuthorizationUrlStrategy(): AuthorizationUrlStrategy;\n protected abstract createTokenExchangeStrategy(): TokenExchangeStrategy;\n\n // Profile fetching methods\n async fetchProfile(accessToken: string): Promise<UserProfile> {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.fetchUserInfo(accessToken);\n }\n\n getProfileEndpoint(): string {\n if (!this.profileFetcher) {\n throw new Error('Profile fetcher not configured for this provider');\n }\n return this.profileFetcher.getEndpoint();\n }\n\n setProfileFetcher(profileFetcher: BaseProfileFetcher): void {\n this.profileFetcher = profileFetcher;\n }\n\n hasProfileFetcher(): boolean {\n return !!this.profileFetcher;\n }\n\n generateAuthorizationUrl(state: string, codeChallenge?: string): string {\n return this.authUrlStrategy.generateAuthorizationUrl(this.config, state, codeChallenge);\n }\n\n async exchangeCodeForToken(code: string, codeVerifier?: string): Promise<OAuth2Token> {\n return this.tokenStrategy.exchangeCodeForToken(code, this.config, codeVerifier);\n }\n\n async refreshToken(refreshToken: string): Promise<OAuth2Token> {\n return this.tokenStrategy.refreshToken(refreshToken, this.config);\n }\n}\n","import { AuthorizationUrlStrategy } from '../strategies/authorization-url.strategy';\nimport { StandardAuthorizationUrlStrategy } from '../strategies/standard-authorization-url.strategy';\nimport { StandardTokenExchangeStrategy } from '../strategies/standard-token-exchange.strategy';\nimport { TokenExchangeStrategy } from '../strategies/token-exchange.strategy';\nimport { OAuth2Provider } from './base.provider';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class GenericOAuth2Provider extends OAuth2Provider {\n constructor(\n config: any,\n authUrlStrategy?: AuthorizationUrlStrategy,\n tokenStrategy?: TokenExchangeStrategy,\n profileFetcher?: BaseProfileFetcher,\n ) {\n super(config, authUrlStrategy, tokenStrategy, profileFetcher);\n }\n\n protected createAuthorizationUrlStrategy(): AuthorizationUrlStrategy {\n return new StandardAuthorizationUrlStrategy();\n }\n\n protected createTokenExchangeStrategy(): TokenExchangeStrategy {\n return new StandardTokenExchangeStrategy();\n }\n}\n","import { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport abstract class BaseProfileFetcher {\n constructor(protected profileEndpoint: string) {}\n\n /**\n * Fetch user profile information from the OAuth provider\n * @param accessToken The OAuth access token\n * @returns Promise resolving to standardized user profile\n */\n async fetchUserInfo(accessToken: string): Promise<UserProfile> {\n const response = await fetch(this.profileEndpoint, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n ...this.getAdditionalHeaders(),\n },\n });\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch profile from ${this.profileEndpoint}: ${response.statusText}`,\n );\n }\n\n const rawData = await response.json();\n return this.mapToUserProfile(rawData);\n }\n\n /**\n * Map the raw API response to our standardized UserProfile structure\n * Override this method to customize mapping for different providers\n * @param rawData The raw API response data\n * @returns UserProfile with optional tenant information\n */\n protected abstract mapToUserProfile(rawData: any): UserProfile;\n\n /**\n * Get additional headers if needed for the profile request\n * Override this method to add provider-specific headers\n */\n protected getAdditionalHeaders(): Record<string, string> {\n return {};\n }\n\n /**\n * Get the profile endpoint URL\n */\n getEndpoint(): string {\n return this.profileEndpoint;\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GoogleProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://www.googleapis.com/oauth2/v2/userinfo');\n }\n\n mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name,\n id: rawData.id,\n avatar: rawData.picture,\n username: rawData.email,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class GitHubProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://api.github.com/user');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.email,\n name: rawData.name || rawData.login,\n id: rawData.id?.toString(),\n avatar: rawData.avatar_url,\n username: rawData.login,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return {\n 'User-Agent': 'OAuth2-Token-Manager', // GitHub requires User-Agent\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport class MicrosoftProfileFetcher extends BaseProfileFetcher {\n constructor() {\n super('https://graph.microsoft.com/v1.0/me');\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n return {\n email: rawData.mail || rawData.userPrincipalName,\n name: rawData.displayName,\n id: rawData.id,\n avatar: undefined, // Microsoft Graph doesn't include avatar in basic profile\n username: rawData.userPrincipalName,\n raw: rawData,\n };\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface ProfileMapping {\n email: string;\n name?: string;\n id?: string;\n avatar?: string;\n username?: string;\n tenant?: string; // Path to tenant/workspace ID in the raw data\n tenantName?: string; // Path to tenant/workspace name in the raw data\n}\n\nexport class GenericProfileFetcher extends BaseProfileFetcher {\n constructor(\n profileEndpoint: string,\n private mapping?: ProfileMapping,\n private additionalHeaders?: Record<string, string>,\n ) {\n super(profileEndpoint);\n }\n\n protected mapToUserProfile(rawData: any): UserProfile {\n if (this.mapping) {\n return {\n email: this.getNestedProperty(rawData, this.mapping.email),\n name: this.mapping.name ? this.getNestedProperty(rawData, this.mapping.name) : undefined,\n id: this.mapping.id ? this.getNestedProperty(rawData, this.mapping.id) : undefined,\n avatar: this.mapping.avatar\n ? this.getNestedProperty(rawData, this.mapping.avatar)\n : undefined,\n username: this.mapping.username\n ? this.getNestedProperty(rawData, this.mapping.username)\n : undefined,\n tenant: this.mapping.tenant\n ? this.getNestedProperty(rawData, this.mapping.tenant)\n : undefined,\n tenantName: this.mapping.tenantName\n ? this.getNestedProperty(rawData, this.mapping.tenantName)\n : undefined,\n raw: rawData,\n };\n }\n\n // Default generic mapping\n return {\n email: rawData.email || rawData.mail || rawData.emailAddress,\n name: rawData.name || rawData.displayName || rawData.full_name,\n id: rawData.id || rawData.sub || rawData.user_id,\n avatar: rawData.avatar || rawData.picture || rawData.avatar_url,\n username: rawData.username || rawData.login || rawData.preferred_username,\n tenant: rawData.tenant || rawData.workspace_id || rawData.organization_id || rawData.team_id,\n tenantName:\n rawData.tenantName ||\n rawData.workspace_name ||\n rawData.organization_name ||\n rawData.team_name,\n raw: rawData,\n };\n }\n\n protected getAdditionalHeaders(): Record<string, string> {\n return this.additionalHeaders || {};\n }\n\n private getNestedProperty(obj: any, path: string): any {\n return path.split('.').reduce((current, key) => current?.[key], obj);\n }\n}\n","import { BaseProfileFetcher } from './base-profile-fetcher';\nimport { GoogleProfileFetcher } from './google-profile-fetcher';\nimport { GitHubProfileFetcher } from './github-profile-fetcher';\nimport { MicrosoftProfileFetcher } from './microsoft-profile-fetcher';\nimport { GenericProfileFetcher, ProfileMapping } from './generic-profile-fetcher';\nimport { ProviderType } from '../providers/provider.factory';\nimport { OAuth2Config } from '../types';\n\nexport interface ProfileFetcherOptions {\n profileUrl?: string;\n profileMapping?: ProfileMapping;\n profileHeaders?: Record<string, string>;\n}\n\nexport class ProfileFetcherFactory {\n static createProfileFetcher(\n providerType: ProviderType,\n config: OAuth2Config,\n options?: ProfileFetcherOptions,\n ): BaseProfileFetcher {\n // If custom options are provided, use GenericProfileFetcher\n if (options?.profileUrl) {\n return new GenericProfileFetcher(\n options.profileUrl,\n options.profileMapping,\n options.profileHeaders,\n );\n }\n\n // Use provider-specific fetchers for known providers\n switch (providerType) {\n case 'google':\n return new GoogleProfileFetcher();\n case 'github':\n return new GitHubProfileFetcher();\n case 'microsoft':\n case 'outlook':\n return new MicrosoftProfileFetcher();\n case 'facebook':\n return new GenericProfileFetcher(\n 'https://graph.facebook.com/me?fields=id,name,email,picture',\n );\n case 'generic':\n default:\n // For generic providers, use the profileUrl from config\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n throw new Error(`Profile URL must be provided for ${providerType} provider`);\n }\n return new GenericProfileFetcher(profileUrl);\n }\n }\n\n static registerCustomProfileFetcher(\n providerName: string,\n profileFetcher: BaseProfileFetcher,\n ): void {\n // Store custom profile fetchers for later use\n this.customFetchers.set(providerName, profileFetcher);\n }\n\n private static customFetchers = new Map<string, BaseProfileFetcher>();\n\n static getCustomProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.customFetchers.get(providerName);\n }\n}\n","import { OAuth2Config } from '../types';\nimport { OAuth2Provider } from './base.provider';\nimport { GenericOAuth2Provider } from './generic.provider';\nimport { ProfileFetcherFactory } from '../profile/profile-fetcher-factory';\n\nexport type ProviderType = 'google' | 'github' | 'microsoft' | 'outlook' | 'facebook' | 'generic';\n\nexport interface ProviderFactory {\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider;\n}\n\nexport class OAuth2ProviderFactory implements ProviderFactory {\n private static presetConfigs: Record<string, Partial<OAuth2Config>> = {\n google: {\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n profileUrl: 'https://www.googleapis.com/oauth2/v2/userinfo',\n usePKCE: true,\n extraAuthParams: {\n access_type: 'offline',\n prompt: 'consent',\n },\n },\n github: {\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n profileUrl: 'https://api.github.com/user',\n },\n microsoft: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n },\n outlook: {\n authorizationUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',\n tokenUrl: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',\n profileUrl: 'https://graph.microsoft.com/v1.0/me',\n usePKCE: true,\n extraAuthParams: {\n prompt: 'select_account',\n },\n },\n facebook: {\n authorizationUrl: 'https://www.facebook.com/v12.0/dialog/oauth',\n tokenUrl: 'https://graph.facebook.com/v12.0/oauth/access_token',\n profileUrl: 'https://graph.facebook.com/me?fields=id,name,email,picture',\n },\n };\n\n createProvider(type: ProviderType, config: OAuth2Config): OAuth2Provider {\n const presetConfig = type !== 'generic' ? OAuth2ProviderFactory.presetConfigs[type] || {} : {};\n\n // Only override preset values if the user explicitly provides them (not empty strings)\n const mergedConfig: OAuth2Config = {\n ...presetConfig,\n ...config,\n // Don't override preset URLs with empty strings\n authorizationUrl: config.authorizationUrl || presetConfig.authorizationUrl || '',\n tokenUrl: config.tokenUrl || presetConfig.tokenUrl || '',\n profileUrl: config.profileUrl || presetConfig.profileUrl,\n extraAuthParams: {\n ...(presetConfig.extraAuthParams || {}),\n ...(config.extraAuthParams || {}),\n },\n };\n\n const profileFetcher = ProfileFetcherFactory.createProfileFetcher(type, mergedConfig);\n\n return new GenericOAuth2Provider(mergedConfig, undefined, undefined, profileFetcher);\n }\n\n static registerPreset(name: string, config: Partial<OAuth2Config>): void {\n OAuth2ProviderFactory.presetConfigs[name] = config;\n }\n\n static getPresetConfig(name: string): Partial<OAuth2Config> | undefined {\n return OAuth2ProviderFactory.presetConfigs[name];\n }\n}\n","import { AuthorizationState } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\n\nexport class InMemoryStorageAdapter implements StorageAdapter {\n private tokens: Map<string, StoredToken> = new Map();\n private states: Map<string, AuthorizationState> = new Map();\n private profileFetchers: Map<string, BaseProfileFetcher> = new Map();\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n const existingToken = await this.getToken(input.provider, input.email, input.tenant);\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...input,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n return updatedToken;\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...input,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n return newToken;\n }\n\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n let tokens = Array.from(this.tokens.values());\n\n // Apply filters\n if (query.id) {\n tokens = tokens.filter((t) => t.id === query.id);\n }\n if (query.provider) {\n tokens = tokens.filter((t) => t.provider === query.provider);\n }\n if (query.userId) {\n tokens = tokens.filter((t) => t.userId === query.userId);\n }\n if (query.email) {\n tokens = tokens.filter((t) => t.email === query.email);\n }\n if (query.tenant !== undefined) {\n tokens = tokens.filter((t) => t.tenant === query.tenant);\n }\n\n // Filter out expired tokens unless explicitly requested\n if (!query.includeExpired) {\n const now = new Date().getTime();\n tokens = tokens.filter((t) => {\n const expiresAt = new Date(t.token.expiresAt).getTime();\n return expiresAt >= now;\n });\n }\n\n // Apply pagination\n if (query.offset !== undefined) {\n tokens = tokens.slice(query.offset);\n }\n if (query.limit !== undefined) {\n tokens = tokens.slice(0, query.limit);\n }\n\n return tokens;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ provider, email, tenant, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokens({ id, includeExpired: true });\n return results[0] || null;\n }\n\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n async getTokensByProvider(provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider });\n }\n\n async getAccounts(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async getTokensForEmail(\n userId: string,\n provider: string,\n email: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokens({ userId, provider, email });\n return results[0] || null;\n }\n\n async getTokens(userId: string, provider: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId, provider });\n }\n\n async updateToken(id: string, update: UpdateTokenInput): Promise<StoredToken | null> {\n const token = this.tokens.get(id);\n if (!token) return null;\n\n const updatedToken: StoredToken = {\n ...token,\n ...(update.token && { token: update.token }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n return updatedToken;\n }\n\n async deleteToken(id: string): Promise<boolean> {\n return this.tokens.delete(id);\n }\n\n async deleteTokenByProviderEmail(\n provider: string,\n email: string,\n tenant?: string,\n ): Promise<boolean> {\n const token = await this.getToken(provider, email, tenant);\n if (!token) return false;\n return this.tokens.delete(token.id);\n }\n\n async deleteExpiredTokens(): Promise<number> {\n const now = new Date().getTime();\n const expiredTokens = Array.from(this.tokens.entries())\n .filter(([, token]) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt < now;\n })\n .map(([id]) => id);\n\n expiredTokens.forEach((id) => this.tokens.delete(id));\n return expiredTokens.length;\n }\n\n // Authorization state operations\n async saveAuthorizationState(\n state: Omit<AuthorizationState, 'createdAt'>,\n ): Promise<AuthorizationState> {\n const newState: AuthorizationState = {\n ...state,\n createdAt: new Date(Date.now()),\n };\n this.states.set(state.state, newState);\n return newState;\n }\n\n async getAuthorizationState(state: string): Promise<AuthorizationState | null> {\n return this.states.get(state) || null;\n }\n\n async deleteAuthorizationState(state: string): Promise<boolean> {\n return this.states.delete(state);\n }\n\n async cleanupExpiredStates(): Promise<number> {\n const now = new Date().getTime();\n const maxAge = 10 * 60 * 1000; // 10 minutes\n\n const expiredStates = Array.from(this.states.entries())\n .filter(([, state]) => {\n const stateAge = now - state.createdAt.getTime();\n return stateAge > maxAge;\n })\n .map(([key]) => key);\n\n expiredStates.forEach((key) => this.states.delete(key));\n return expiredStates.length;\n }\n\n // Profile fetcher operations\n registerProfileFetcher(providerName: string, fetcher: BaseProfileFetcher): void {\n this.profileFetchers.set(providerName, fetcher);\n }\n\n getProfileFetcher(providerName: string): BaseProfileFetcher | undefined {\n return this.profileFetchers.get(providerName);\n }\n\n getProfileFetchers(): Map<string, BaseProfileFetcher> {\n return new Map(this.profileFetchers);\n }\n}\n","import { createHash, randomBytes } from 'crypto';\n\nexport const createCodeVerifier = () =>\n randomBytes(32)\n .toString('base64')\n .replace(/[^a-zA-Z0-9]/g, '')\n .substring(0, 128);\n\nexport const createCodeChallenge = (verifier: string): string => {\n return createHash('sha256').update(verifier).digest('base64url');\n};\n\nexport const generateState = (): string => {\n return randomBytes(16).toString('base64url');\n};\n","import { OAuth2Config, OAuth2Token, AuthorizationState } from '../types';\nimport { OAuth2ProviderFactory, ProviderType } from '../providers/provider.factory';\nimport { StorageAdapter, StoredToken, TokenQuery } from '../storage/interfaces';\nimport { InMemoryStorageAdapter } from '../storage/memory.adapter';\nimport { ProviderFactory } from '../providers/provider.factory';\nimport { createCodeVerifier, createCodeChallenge, generateState } from '../utils/crypto';\nimport { OAuth2Provider } from '../providers/base.provider';\nimport { UserProfile } from '../providers/interfaces/profile-fetcher.interface';\n\nexport interface OAuth2Options {\n storage?: StorageAdapter;\n providers?: Record<string, OAuth2Config>;\n autoRefresh?: AutoRefreshOptions;\n}\n\nexport interface AutoRefreshOptions {\n enabled?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n onRefreshError?: (error: Error, token: StoredToken) => void;\n}\n\nexport interface AuthorizationOptions {\n provider: string;\n userId: string;\n email: string;\n tenant?: string; // For multi-tenant providers like Slack\n tenantName?: string; // Human-readable tenant name\n scopes?: string[];\n metadata?: Record<string, any>;\n usePKCE?: boolean;\n}\n\nexport interface TokenOptions {\n autoRefresh?: boolean;\n refreshBuffer?: number; // minutes before expiry to refresh\n expirationBuffer?: number; // seconds before expiry to consider expired\n defaultExpiresIn?: number; // default expiration in seconds\n}\n\nexport interface CallbackResult {\n token: StoredToken;\n profile?: UserProfile;\n}\n\nexport class OAuth2Client {\n private storage: StorageAdapter;\n private providerFactory: ProviderFactory;\n private providers: Map<string, OAuth2Provider> = new Map();\n private providerConfigs: Map<string, OAuth2Config> = new Map();\n private now: () => number;\n private autoRefreshOptions: AutoRefreshOptions;\n\n constructor(options: OAuth2Options = {}) {\n this.storage = options.storage || new InMemoryStorageAdapter();\n this.providerFactory = new OAuth2ProviderFactory();\n this.now = Date.now;\n\n // Set default auto-refresh options - enabled by default\n this.autoRefreshOptions = {\n enabled: options.autoRefresh?.enabled ?? true, // Enabled by default\n refreshBuffer: options.autoRefresh?.refreshBuffer ?? 10, // 10 minutes before expiry (safe for Google's 1-hour tokens)\n onRefreshError: options.autoRefresh?.onRefreshError,\n };\n\n // Register predefined providers\n if (options.providers) {\n Object.entries(options.providers).forEach(([name, config]) => {\n this.registerProvider(name, config);\n });\n }\n }\n\n /**\n * Register a provider configuration\n */\n registerProvider(name: string, config: OAuth2Config): void {\n this.providerConfigs.set(name, config);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config);\n\n // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n if (customFetcher) {\n provider.setProfileFetcher(customFetcher);\n }\n\n this.providers.set(name, provider);\n }\n\n /**\n * Start OAuth2 authorization flow\n */\n async authorize(options: AuthorizationOptions): Promise<{ url: string; state: string }> {\n const provider = this.providers.get(options.provider);\n if (!provider) throw new Error(`Provider ${options.provider} not found`);\n\n const state = generateState();\n let authUrl: string;\n let authState: Omit<AuthorizationState, 'createdAt'>;\n\n const requiresPKCE = this.providerConfigs.get(options.provider)?.usePKCE || options.usePKCE;\n\n if (requiresPKCE) {\n const codeVerifier = createCodeVerifier();\n const codeChallenge = createCodeChallenge(codeVerifier);\n authUrl = provider.generateAuthorizationUrl(state, codeChallenge);\n authState = {\n state,\n codeVerifier,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n } else {\n authUrl = provider.generateAuthorizationUrl(state);\n authState = {\n state,\n config: this.providerConfigs.get(options.provider)!,\n metadata: {\n ...options.metadata,\n userId: options.userId,\n email: options.email,\n provider: options.provider,\n tenant: options.tenant,\n tenantName: options.tenantName,\n },\n };\n }\n\n await this.storage.saveAuthorizationState(authState);\n return { url: authUrl, state };\n }\n\n /**\n * Handle OAuth2 callback\n */\n async handleCallback(code: string, state: string): Promise<CallbackResult> {\n const authState = await this.storage.getAuthorizationState(state);\n if (!authState) throw new Error('Invalid or expired state');\n\n const provider = authState.metadata?.provider;\n if (!provider) throw new Error('Provider not found in authorization state');\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n // Exchange code for tokens\n const tokens = await providerInstance.exchangeCodeForToken(code, authState.codeVerifier);\n\n // Extract user data from metadata\n const userId = authState.metadata?.userId;\n const email = authState.metadata?.email;\n const tenant = authState.metadata?.tenant;\n const tenantName = authState.metadata?.tenantName;\n\n if (!userId || !email) {\n throw new Error('User ID and email are required in authorization state');\n }\n\n // Fetch profile if available\n let profile: UserProfile | undefined;\n if (providerInstance.hasProfileFetcher()) {\n try {\n profile = await providerInstance.fetchProfile(tokens.accessToken);\n } catch (error) {\n console.warn('Failed to fetch user profile:', error);\n }\n }\n\n // Save token - use profile data if available, otherwise fall back to authorization state\n const savedToken = await this.storage.saveToken({\n provider,\n userId,\n email: profile?.email || email,\n tenant: profile?.tenant || tenant,\n tenantName: profile?.tenantName || tenantName,\n token: tokens,\n metadata: {\n ...authState.metadata,\n profileFetched: !!profile,\n },\n });\n\n // Clean up authorization state\n await this.storage.deleteAuthorizationState(state);\n\n // Call onSuccess callback if defined\n const config = this.providerConfigs.get(provider);\n if (config?.onSuccess) {\n await config.onSuccess(userId, tokens);\n }\n\n return {\n token: savedToken,\n profile,\n };\n }\n\n /**\n * Get a valid access token (auto-refresh if needed)\n */\n async getAccessToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<string> {\n const token = await this.getValidToken(provider, email, options);\n return token.accessToken;\n }\n\n /**\n * Get a valid token (auto-refresh if needed)\n */\n async getValidToken(\n provider: string,\n email: string,\n options: TokenOptions & { tenant?: string } = {},\n ): Promise<OAuth2Token> {\n const storedToken = await this.storage.getToken(provider, email, options.tenant);\n if (!storedToken) {\n const tenantInfo = options.tenant ? ` and tenant ${options.tenant}` : '';\n throw new Error(`No token found for provider ${provider}, email ${email}${tenantInfo}`);\n }\n\n const needsRefresh =\n options.autoRefresh !== false && this.isTokenExpired(storedToken.token, options);\n\n if (!needsRefresh) {\n return storedToken.token;\n }\n\n // Refresh the token\n if (!storedToken.token.refreshToken) {\n throw new Error('Token expired and no refresh token available');\n }\n\n const providerInstance = this.providers.get(provider);\n if (!providerInstance) throw new Error(`Provider ${provider} not found`);\n\n const newToken = await providerInstance.refreshToken(storedToken.token.refreshToken);\n await this.storage.updateToken(storedToken.id, { token: newToken });\n\n return newToken;\n }\n\n /**\n * Query tokens with automatic refresh\n */\n async queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n // When auto-refresh is enabled, we need to include expired tokens\n // so we can attempt to refresh them\n const queryWithExpired =\n this.autoRefreshOptions.enabled && !query.includeExpired\n ? { ...query, includeExpired: true }\n : query;\n\n const tokens = await this.storage.queryTokens(queryWithExpired);\n\n if (this.autoRefreshOptions.enabled && !query.includeExpired) {\n const refreshedTokens = await this.refreshTokensIfNeeded(tokens);\n // Filter out tokens that are still expired after refresh attempt\n return refreshedTokens.filter((token) => {\n const expiresAt = new Date(token.token.expiresAt).getTime();\n return expiresAt > this.now();\n });\n }\n\n return tokens;\n }\n\n /**\n * Get all tokens for a user\n */\n async getTokensByUserId(userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ userId });\n }\n\n /**\n * Get all tokens for an email\n */\n async getTokensByEmail(email: string): Promise<StoredToken[]> {\n return this.queryTokens({ email });\n }\n\n /**\n * Delete a token\n */\n async deleteToken(provider: string, email: string, tenant?: string): Promise<boolean> {\n return this.storage.deleteTokenByProviderEmail(provider, email, tenant);\n }\n\n /**\n * Delete all expired tokens\n */\n async cleanupExpiredTokens(): Promise<number> {\n return this.storage.deleteExpiredTokens();\n }\n\n /**\n * Clean up expired authorization states\n */\n async cleanupExpiredStates(): Promise<number> {\n return this.storage.cleanupExpiredStates();\n }\n\n // Helper methods\n private isTokenExpired(token: OAuth2Token, options: TokenOptions = {}): boolean {\n const { expirationBuffer = 300 } = options;\n\n if (token.createdAt && token.expiresIn !== undefined) {\n const expiresAt = token.createdAt + token.expiresIn * 1000;\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n const expiresAt = new Date(token.expiresAt).getTime();\n const effectiveNow = this.now() + expirationBuffer * 1000;\n return effectiveNow >= expiresAt;\n }\n\n private detectProviderType(name: string, config: OAuth2Config): ProviderType {\n // Try to detect based on the authorization URL\n const authUrl = config.authorizationUrl.toLowerCase();\n\n // Check for known providers that have specific implementations\n if (authUrl.includes('accounts.google.com')) return 'google';\n if (authUrl.includes('github.com')) return 'github';\n if (authUrl.includes('facebook.com')) return 'facebook';\n if (authUrl.includes('microsoft.com') || authUrl.includes('microsoftonline.com')) {\n // Check if it's specifically for Outlook\n if (\n name.toLowerCase().includes('outlook') ||\n config.scopes?.some((s) => s.includes('outlook'))\n ) {\n return 'outlook';\n }\n return 'microsoft';\n }\n\n // Default to generic provider for all others\n return 'generic';\n }\n\n /**\n * Refresh tokens if they are near expiration\n */\n private async refreshTokensIfNeeded(tokens: StoredToken[]): Promise<StoredToken[]> {\n const refreshPromises = tokens.map(async (token) => {\n if (this.shouldRefreshToken(token)) {\n try {\n const provider = this.providers.get(token.provider);\n if (!provider) {\n console.warn(`Provider ${token.provider} not found for token refresh`);\n return token;\n }\n\n if (!token.token.refreshToken) {\n console.warn(`No refresh token available for ${token.provider}:${token.email}`);\n return token;\n }\n\n const newToken = await provider.refreshToken(token.token.refreshToken);\n const updated = await this.storage.updateToken(token.id, { token: newToken });\n return updated || token;\n } catch (error) {\n if (this.autoRefreshOptions.onRefreshError) {\n this.autoRefreshOptions.onRefreshError(error as Error, token);\n }\n console.error(`Failed to refresh token for ${token.provider}:${token.email}:`, error);\n return token;\n }\n }\n return token;\n });\n\n return Promise.all(refreshPromises);\n }\n\n /**\n * Check if a token should be refreshed\n */\n private shouldRefreshToken(storedToken: StoredToken): boolean {\n // Skip if no refresh token\n if (!storedToken.token.refreshToken) {\n return false;\n }\n\n // Check if token is expired or near expiration\n const expiresAt = new Date(storedToken.token.expiresAt).getTime();\n const now = this.now();\n\n // If already expired, definitely try to refresh\n if (now >= expiresAt) {\n return true;\n }\n\n // Otherwise, check if within refresh buffer\n const bufferMs = this.autoRefreshOptions.refreshBuffer! * 60 * 1000;\n const shouldRefreshAt = expiresAt - bufferMs;\n\n return now >= shouldRefreshAt;\n }\n\n /**\n * Update auto-refresh options\n */\n updateAutoRefreshOptions(options: Partial<AutoRefreshOptions>): void {\n this.autoRefreshOptions = { ...this.autoRefreshOptions, ...options };\n }\n\n /**\n * Get all tokens for a specific provider and user across all tenants\n */\n async getTokensAcrossTenants(provider: string, userId: string): Promise<StoredToken[]> {\n return this.queryTokens({ provider, userId });\n }\n\n /**\n * Get all tenants for a specific provider and email\n */\n async getTenants(provider: string, email: string): Promise<string[]> {\n const tokens = await this.queryTokens({ provider, email });\n const tenants = tokens\n .map((t) => t.tenant)\n .filter((tenant): tenant is string => tenant !== undefined);\n return [...new Set(tenants)]; // Return unique tenants\n }\n\n /**\n * Get token by tenant name (useful for Slack workspaces with human-readable names)\n */\n async getTokenByTenantName(\n provider: string,\n email: string,\n tenantName: string,\n ): Promise<StoredToken | null> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.find((t) => t.tenantName === tenantName) || null;\n }\n\n /**\n * Check if a token exists for a specific tenant\n */\n async hasTokenForTenant(provider: string, email: string, tenant: string): Promise<boolean> {\n const token = await this.storage.getToken(provider, email, tenant);\n return token !== null;\n }\n\n /**\n * Get all tokens with their tenant information\n */\n async getMultiTenantTokens(\n provider: string,\n email: string,\n ): Promise<Array<{ token: StoredToken; tenant?: string; tenantName?: string }>> {\n const tokens = await this.queryTokens({ provider, email });\n return tokens.map((token) => ({\n token,\n tenant: token.tenant,\n tenantName: token.tenantName,\n }));\n }\n}\n","import { sealData, unsealData } from 'iron-session';\n\nexport const seal = <T>(d: T, key: string) => sealData(d, { password: key });\nexport const unseal = <T>(s: string, key: string) => unsealData<T>(s, { password: key });\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dainprotocol/oauth2-token-manager",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "A scalable OAuth2 token management library with multi-system support",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oauth2",
|
|
@@ -34,31 +34,6 @@
|
|
|
34
34
|
"README.md",
|
|
35
35
|
"LICENSE"
|
|
36
36
|
],
|
|
37
|
-
"scripts": {
|
|
38
|
-
"dev": "tsx watch src/index.ts",
|
|
39
|
-
"dev:example": "tsx src/examples/basic.ts",
|
|
40
|
-
"build": "tsup",
|
|
41
|
-
"build:watch": "tsup --watch",
|
|
42
|
-
"test": "vitest",
|
|
43
|
-
"test:ui": "vitest --ui",
|
|
44
|
-
"test:coverage": "vitest run --coverage",
|
|
45
|
-
"test:watch": "vitest watch",
|
|
46
|
-
"lint": "eslint .",
|
|
47
|
-
"lint:fix": "eslint --fix .",
|
|
48
|
-
"lint:config": "eslint --print-config src/index.ts",
|
|
49
|
-
"format": "prettier --write",
|
|
50
|
-
"format:check": "prettier",
|
|
51
|
-
"typecheck": "tsc --noEmit",
|
|
52
|
-
"docs": "typedoc",
|
|
53
|
-
"docs:watch": "typedoc --watch",
|
|
54
|
-
"ci": "npm run lint && npm run typecheck && npm run test:coverage && npm run build",
|
|
55
|
-
"prepublishOnly": "npm run ci",
|
|
56
|
-
"prepare": "husky install",
|
|
57
|
-
"release": "npm run ci:all && changeset publish",
|
|
58
|
-
"_postinstall": "husky",
|
|
59
|
-
"prepack": "pinst --disable",
|
|
60
|
-
"postpack": "pinst --enable"
|
|
61
|
-
},
|
|
62
37
|
"dependencies": {
|
|
63
38
|
"@changesets/cli": "^2.29.4",
|
|
64
39
|
"@types/node": "^22.15.29",
|
|
@@ -92,5 +67,26 @@
|
|
|
92
67
|
},
|
|
93
68
|
"publishConfig": {
|
|
94
69
|
"access": "public"
|
|
70
|
+
},
|
|
71
|
+
"scripts": {
|
|
72
|
+
"dev": "tsx watch src/index.ts",
|
|
73
|
+
"dev:example": "tsx src/examples/basic.ts",
|
|
74
|
+
"build": "tsup",
|
|
75
|
+
"build:watch": "tsup --watch",
|
|
76
|
+
"test": "vitest",
|
|
77
|
+
"test:ui": "vitest --ui",
|
|
78
|
+
"test:coverage": "vitest run --coverage",
|
|
79
|
+
"test:watch": "vitest watch",
|
|
80
|
+
"lint": "eslint .",
|
|
81
|
+
"lint:fix": "eslint --fix .",
|
|
82
|
+
"lint:config": "eslint --print-config src/index.ts",
|
|
83
|
+
"format": "prettier --write",
|
|
84
|
+
"format:check": "prettier",
|
|
85
|
+
"typecheck": "tsc --noEmit",
|
|
86
|
+
"docs": "typedoc",
|
|
87
|
+
"docs:watch": "typedoc --watch",
|
|
88
|
+
"ci": "npm run lint && npm run typecheck && npm run test:coverage && npm run build",
|
|
89
|
+
"release": "npm run ci:all && changeset publish",
|
|
90
|
+
"_postinstall": "husky"
|
|
95
91
|
}
|
|
96
|
-
}
|
|
92
|
+
}
|