@dainprotocol/oauth2-token-manager 0.3.0 → 0.3.2
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/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +23 -27
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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 A=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 p=await n.text();throw new Error(`Token exchange failed: ${n.statusText} - ${p}`)}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 h,l,f,m,g;let n=Date.now(),i=this.extractValue(e,(h=o==null?void 0:o.tokenPaths)==null?void 0:h.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,p=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"]),P=(typeof p=="string"?parseInt(p,10):p)||3600,c=this.extractValue(e,(m=o==null?void 0:o.tokenPaths)==null?void 0:m.scope,["authed_user.scope","scope","token.scope"]),F=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+P*1e3),expiresIn:P,tokenType:F,scope:c,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 x=class extends k{constructor(e,t,r,o){super(e,t,r,o);}createAuthorizationUrlStrategy(){return new v}createTokenExchangeStrategy(){return new A}};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 S=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 w=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 U=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 u=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,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,o){if(o)return o;if(r!=null&&r.profileUrl)return new u(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 u("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let n=t.profileUrl||t.userInfoUrl;return n?new u(n):void 0}}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,r){let o=e!=="generic"?s.presetConfigs[e]||{}:{},n={...o,...t,authorizationUrl:t.authorizationUrl||o.authorizationUrl||"",tokenUrl:t.tokenUrl||o.tokenUrl||"",profileUrl:t.profileUrl||o.profileUrl,extraAuthParams:{...o.extraAuthParams||{},...t.extraAuthParams||{}}},i=E.createProfileFetcher(e,n,void 0,r);return new x(n,void 0,void 0,i)}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;encryption;constructor(e){this.encryption=e==null?void 0:e.encryption;}generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async encryptToken(e){if(!this.encryption)return e;let t=await this.encryption.encryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptToken(e){if(!this.encryption||!this.encryption.isEncrypted(e.accessToken))return e;let t=await this.encryption.decryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptStoredToken(e){return this.encryption?{...e,token:await this.decryptToken(e.token)}:e}async saveToken(e){let t=await this.getTokenInternal(e.provider,e.email,e.tenant),r=await this.encryptToken(e.token),o={...e,token:r};if(t){let i={...t,...o,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,i),this.decryptStoredToken(i)}let n={...o,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(n.id,n),this.decryptStoredToken(n)}async queryTokensInternal(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 queryTokens(e){let t=await this.queryTokensInternal(e);return Promise.all(t.map(r=>this.decryptStoredToken(r)))}async getTokenInternal(e,t,r){return (await this.queryTokensInternal({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getToken(e,t,r){let o=await this.getTokenInternal(e,t,r);return o?this.decryptStoredToken(o):null}async getTokenById(e){let r=(await this.queryTokensInternal({id:e,includeExpired:true}))[0]||null;return r?this.decryptStoredToken(r):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=t.token;t.token&&this.encryption&&(o=await this.encryptToken(t.token));let n={...r,...o&&{token:o},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,n),this.decryptStoredToken(n)}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let o=await this.getTokenInternal(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 N=()=>crypto.randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),B=s=>crypto.createHash("sha256").update(s).digest("base64url"),M=()=>crypto.randomBytes(16).toString("base64url");var b=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.storage.getProfileFetcher(e),o=this.detectProviderType(e,t),n=this.providerFactory.createProvider(o,t,r);this.providers.set(e,n);}async authorize(e){var a;let t=this.providers.get(e.provider);if(!t)throw new Error(`Provider ${e.provider} not found`);let r=M(),o,n;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let p=N(),y=B(p);o=t.generateAuthorizationUrl(r,y),n={state:r,codeVerifier:p,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,z;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,p=(m=r.metadata)==null?void 0:m.email,y=(g=r.metadata)==null?void 0:g.tenant,P=(z=r.metadata)==null?void 0:z.tenantName;if(!a||!p)throw new Error("User ID and email are required in authorization state");let c;if(n.hasProfileFetcher())try{c=await n.fetchProfile(i.accessToken);}catch(K){console.warn("Failed to fetch user profile:",K);}let F=await this.storage.saveToken({provider:o,userId:a,email:(c==null?void 0:c.email)||p,tenant:(c==null?void 0:c.tenant)||y,tenantName:(c==null?void 0:c.tenantName)||P,token:i,metadata:{...r.metadata,profileFetched:!!c}});await this.storage.deleteAuthorizationState(t);let h=this.providerConfigs.get(o);return h!=null&&h.onSuccess&&await h.onSuccess(a,i),{token:F,profile:c}}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 p=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${p}`)}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 C=(s,e)=>ironSession.sealData(s,{password:e}),R=(s,e)=>ironSession.unsealData(s,{password:e});var I=class{encryptionKey;constructor(e){if(!e.encryptionKey||e.encryptionKey.length<32)throw new Error("Encryption key must be at least 32 characters long");this.encryptionKey=e.encryptionKey;}async encryptTokenFields(e){let t=await C(e.accessToken,this.encryptionKey),r;return e.refreshToken&&(r=await C(e.refreshToken,this.encryptionKey)),{accessToken:t,refreshToken:r}}async decryptTokenFields(e){let t=await R(e.accessToken,this.encryptionKey),r;if(e.refreshToken&&(r=await R(e.refreshToken,this.encryptionKey)),!t||typeof t=="object"&&Object.keys(t).length===0)throw new Error("Failed to decrypt access token - invalid encryption key or corrupted data");return {accessToken:t,refreshToken:r||void 0}}isEncrypted(e){return e.startsWith("Fe26.2")}};
|
|
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,n])=>`${r}=${encodeURIComponent(n)}`).join("&")}generateAuthorizationUrl(e,t,r){let n={client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scopes.join(" "),state:t};(e.usePKCE||e.pkce)&&r&&(n.code_challenge=r,n.code_challenge_method="S256");let o={...e.additionalParams,...e.extraAuthParams};return Object.assign(n,o),`${e.authorizationUrl}?${this.buildUrlParams(n)}`}};var A=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,n])=>`${r}=${encodeURIComponent(n)}`).join("&")}async exchangeCodeForToken(e,t,r){let n={grant_type:"authorization_code",code:e,redirect_uri:t.redirectUri,client_id:t.clientId};(t.usePKCE||t.pkce)&&r?n.code_verifier=r:t.clientSecret&&(n.client_secret=t.clientSecret);let o={"Content-Type":"application/x-www-form-urlencoded"};if(t.useBasicAuth&&t.clientId&&t.clientSecret){let d=Buffer.from(`${t.clientId}:${t.clientSecret}`).toString("base64");o.Authorization=`Basic ${d}`;}let i=await fetch(t.tokenUrl,{method:"POST",headers:o,body:this.buildUrlParams(n)});if(!i.ok){let d=await i.text();throw new Error(`Token exchange failed: ${i.statusText} - ${d}`)}let a=await i.json(),c=t.responseRootKey?a[t.responseRootKey]:a;return this.normalizeTokenResponse(c,a,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 n={"Content-Type":"application/x-www-form-urlencoded"};if(t.useBasicAuth&&t.clientId&&t.clientSecret){let c=Buffer.from(`${t.clientId}:${t.clientSecret}`).toString("base64");n.Authorization=`Basic ${c}`;}let o=await fetch(t.tokenUrl,{method:"POST",headers:n,body:this.buildUrlParams(r)});if(!o.ok){let c=await o.text();throw new Error(`Token refresh failed: ${o.statusText} - ${c}`)}let i=await o.json(),a=t.responseRootKey?i[t.responseRootKey]:i;return this.normalizeTokenResponse(a,i,e,t)}normalizeTokenResponse(e,t,r,n){var u,f,m,g,k;let o=Date.now(),i=this.extractValue(e,(u=n==null?void 0:n.tokenPaths)==null?void 0:u.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,(f=n==null?void 0:n.tokenPaths)==null?void 0:f.refreshToken,["authed_user.refresh_token","authed_user.refreshToken","refresh_token","refreshToken","token.refresh_token","token.refreshToken"])??r,c=this.extractValue(e,(m=n==null?void 0:n.tokenPaths)==null?void 0:m.expiresIn,["authed_user.expires_in","authed_user.expiresIn","expires_in","expiresIn","token.expires_in","token.expiresIn"]),P=(typeof c=="string"?parseInt(c,10):c)||3600,p=this.extractValue(e,(g=n==null?void 0:n.tokenPaths)==null?void 0:g.scope,["authed_user.scope","scope","token.scope"]),b=this.extractValue(e,(k=n==null?void 0:n.tokenPaths)==null?void 0:k.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(o+P*1e3),expiresIn:P,tokenType:b,scope:p,createdAt:o,raw:t}}extractValue(e,t,r){if(t){let n=Array.isArray(t)?t:[t];for(let o of n){let i=this.getNestedValue(e,o);if(i!==void 0)return i}}if(r)for(let n of r){let o=this.getNestedValue(e,n);if(o!==void 0)return o}}getNestedValue(e,t){let r=t.split("."),n=e;for(let o of r)if(n&&typeof n=="object"&&o in n)n=n[o];else return;return n}};var T=class{constructor(e,t,r,n){this.config=e;this.authUrlStrategy=t||this.createAuthorizationUrlStrategy(),this.tokenStrategy=r||this.createTokenExchangeStrategy(),this.profileFetcher=n;}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 x=class extends T{constructor(e,t,r,n){super(e,t,r,n);}createAuthorizationUrlStrategy(){return new v}createTokenExchangeStrategy(){return new A}};var h=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 h{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 h{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 h{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 l=class extends h{constructor(t,r,n){super(t);this.mapping=r;this.additionalHeaders=n;}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((n,o)=>n==null?void 0:n[o],t)}};var E=class{static createProfileFetcher(e,t,r,n){if(n)return n;if(r!=null&&r.profileUrl)return new l(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 l("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let o=t.profileUrl||t.userInfoUrl;return o?new l(o):void 0}}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,r){let n=e!=="generic"?s.presetConfigs[e]||{}:{},o={...n,...t,authorizationUrl:t.authorizationUrl||n.authorizationUrl||"",tokenUrl:t.tokenUrl||n.tokenUrl||"",profileUrl:t.profileUrl||n.profileUrl,extraAuthParams:{...n.extraAuthParams||{},...t.extraAuthParams||{}}},i=E.createProfileFetcher(e,o,void 0,r);return new x(o,void 0,void 0,i)}static registerPreset(e,t){s.presetConfigs[e]=t;}static getPresetConfig(e){return s.presetConfigs[e]}};var y=class{tokens=new Map;states=new Map;profileFetchers=new Map;encryption;constructor(e){this.encryption=e==null?void 0:e.encryption;}generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async encryptToken(e){if(!this.encryption)return e;let t=await this.encryption.encryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptToken(e){if(!this.encryption||!this.encryption.isEncrypted(e.accessToken))return e;let t=await this.encryption.decryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptStoredToken(e){return this.encryption?{...e,token:await this.decryptToken(e.token)}:e}async saveToken(e){let t=await this.getTokenInternal(e.provider,e.email,e.tenant),r=await this.encryptToken(e.token),n={...e,token:r};if(t){let i={...t,...n,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,i),this.decryptStoredToken(i)}let o={...n,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(o.id,o),this.decryptStoredToken(o)}async queryTokensInternal(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(n=>new Date(n.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 queryTokens(e){let t=await this.queryTokensInternal(e);return Promise.all(t.map(r=>this.decryptStoredToken(r)))}async getTokenInternal(e,t,r){return (await this.queryTokensInternal({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getToken(e,t,r){let n=await this.getTokenInternal(e,t,r);return n?this.decryptStoredToken(n):null}async getTokenById(e){let r=(await this.queryTokensInternal({id:e,includeExpired:true}))[0]||null;return r?this.decryptStoredToken(r):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 n=t.token;t.token&&this.encryption&&(n=await this.encryptToken(t.token));let o={...r,...n&&{token:n},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,o),this.decryptStoredToken(o)}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let n=await this.getTokenInternal(e,t,r);return n?this.tokens.delete(n.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(([,n])=>e-n.createdAt.getTime()>t).map(([n])=>n);return r.forEach(n=>this.states.delete(n)),r.length}registerProfileFetcher(e,t){this.profileFetchers.set(e,t);}getProfileFetcher(e){return this.profileFetchers.get(e)}getProfileFetchers(){return new Map(this.profileFetchers)}};var B=()=>crypto.randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),N=s=>crypto.createHash("sha256").update(s).digest("base64url"),$=()=>crypto.randomBytes(16).toString("base64url");var F=class{storage;providerFactory;providers=new Map;providerConfigs=new Map;now;autoRefreshOptions;constructor(e={}){var t,r,n;this.storage=e.storage||new y,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:(n=e.autoRefresh)==null?void 0:n.onRefreshError},e.providers&&Object.entries(e.providers).forEach(([o,i])=>{this.registerProvider(o,i);});}registerProvider(e,t){this.providerConfigs.set(e,t);let r=this.storage.getProfileFetcher(e),n=this.detectProviderType(e,t),o=this.providerFactory.createProvider(n,t,r);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=$(),n,o;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let c=B(),d=N(c);n=t.generateAuthorizationUrl(r,d),o={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 n=t.generateAuthorizationUrl(r),o={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(o),{url:n,state:r}}async handleCallback(e,t){var f,m,g,k,z;let r=await this.storage.getAuthorizationState(t);if(!r)throw new Error("Invalid or expired state");let n=(f=r.metadata)==null?void 0:f.provider;if(!n)throw new Error("Provider not found in authorization state");let o=this.providers.get(n);if(!o)throw new Error(`Provider ${n} not found`);let i=await o.exchangeCodeForToken(e,r.codeVerifier),a=(m=r.metadata)==null?void 0:m.userId,c=(g=r.metadata)==null?void 0:g.email,d=(k=r.metadata)==null?void 0:k.tenant,P=(z=r.metadata)==null?void 0:z.tenantName;if(!a||!c)throw new Error("User ID and email are required in authorization state");let p;if(o.hasProfileFetcher())try{p=await o.fetchProfile(i.accessToken);}catch(M){console.warn("Failed to fetch user profile:",M);}let b=await this.storage.saveToken({provider:n,userId:a,email:(p==null?void 0:p.email)||c,tenant:(p==null?void 0:p.tenant)||d,tenantName:(p==null?void 0:p.tenantName)||P,token:i,metadata:{...r.metadata,profileFetched:!!p}});await this.storage.deleteAuthorizationState(t);let u=this.providerConfigs.get(n);return u!=null&&u.onSuccess&&await u.onSuccess(a,i),{token:b,profile:p}}async getAccessToken(e,t,r={}){return (await this.getValidToken(e,t,r)).accessToken}async getValidToken(e,t,r={}){let n=await this.storage.getToken(e,t,r.tenant);if(!n){let d=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${d}`)}let o=this.providerConfigs.get(e);if(o&&o.refreshable===false||!(r.autoRefresh!==false&&this.isTokenExpired(n.token,r)))return n.token;if(!n.token.refreshToken)throw new Error("Token expired and no refresh token available");let a=this.providers.get(e);if(!a)throw new Error(`Provider ${e} not found`);let c=await a.refreshToken(n.token.refreshToken);return await this.storage.updateToken(n.id,{token:c}),c}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(o=>new Date(o.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 n=new Date(e.expiresAt).getTime();return this.now()+r*1e3>=n}detectProviderType(e,t){var n;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")||(n=t.scopes)!=null&&n.some(o=>o.includes("outlook"))?"outlook":"microsoft":"generic"}async refreshTokensIfNeeded(e){let t=e.map(async r=>{if(this.shouldRefreshToken(r))try{let n=this.providers.get(r.provider);if(!n)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 o=await n.refreshToken(r.token.refreshToken);return await this.storage.updateToken(r.id,{token:o})||r}catch(n){return this.autoRefreshOptions.onRefreshError&&this.autoRefreshOptions.onRefreshError(n,r),console.error(`Failed to refresh token for ${r.provider}:${r.email}:`,n),r}return r});return Promise.all(t)}shouldRefreshToken(e){let t=this.providerConfigs.get(e.provider);if(t&&t.refreshable===false||!e.token.refreshToken)return false;let r=new Date(e.token.expiresAt).getTime(),n=this.now();if(n>=r)return true;let o=this.autoRefreshOptions.refreshBuffer*60*1e3,i=r-o;return n>=i}updateAutoRefreshOptions(e){this.autoRefreshOptions={...this.autoRefreshOptions,...e};}async getTokensAcrossTenants(e,t){return this.queryTokens({provider:e,userId:t})}async getTenants(e,t){let n=(await this.queryTokens({provider:e,email:t})).map(o=>o.tenant).filter(o=>o!==void 0);return [...new Set(n)]}async getTokenByTenantName(e,t,r){return (await this.queryTokens({provider:e,email:t})).find(o=>o.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(n=>({token:n,tenant:n.tenant,tenantName:n.tenantName}))}};var C=(s,e)=>ironSession.sealData(s,{password:e}),R=(s,e)=>ironSession.unsealData(s,{password:e});var I=class{encryptionKey;constructor(e){if(!e.encryptionKey||e.encryptionKey.length<32)throw new Error("Encryption key must be at least 32 characters long");this.encryptionKey=e.encryptionKey;}async encryptTokenFields(e){let t=await C(e.accessToken,this.encryptionKey),r;return e.refreshToken&&(r=await C(e.refreshToken,this.encryptionKey)),{accessToken:t,refreshToken:r}}async decryptTokenFields(e){let t=await R(e.accessToken,this.encryptionKey),r;if(e.refreshToken&&(r=await R(e.refreshToken,this.encryptionKey)),!t||typeof t=="object"&&Object.keys(t).length===0)throw new Error("Failed to decrypt access token - invalid encryption key or corrupted data");return {accessToken:t,refreshToken:r||void 0}}isEncrypted(e){return e.startsWith("Fe26.2")}};
|
|
2
|
+
exports.BaseProfileFetcher=h;exports.GenericOAuth2Provider=x;exports.GenericProfileFetcher=l;exports.GitHubProfileFetcher=w;exports.GoogleProfileFetcher=S;exports.InMemoryStorageAdapter=y;exports.MicrosoftProfileFetcher=U;exports.OAuth2Client=F;exports.OAuth2Provider=T;exports.ProfileFetcherFactory=E;exports.StandardAuthorizationUrlStrategy=v;exports.StandardTokenExchangeStrategy=A;exports.TokenEncryption=I;exports.createCodeChallenge=N;exports.createCodeVerifier=B;exports.generateState=$;exports.seal=C;exports.unseal=R;//# 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","../src/encryption/token-encryption.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","customFetcher","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","customProfileFetcher","presetConfig","mergedConfig","name","InMemoryStorageAdapter","token","encrypted","decrypted","storedToken","input","existingToken","encryptedToken","inputWithEncryptedToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","encryptedUpdateToken","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","authUrl","authState","providerInstance","tenantName","profile","error","savedToken","tenantInfo","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData","TokenEncryption","fields","encryptedAccessToken","encryptedRefreshToken","decryptedAccessToken","decryptedRefreshToken"],"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 customFetcher?: BaseProfileFetcher,\n ): BaseProfileFetcher | undefined {\n // If a custom fetcher is provided, use it directly\n if (customFetcher) {\n return customFetcher;\n }\n\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 if available\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n // Return undefined instead of throwing - profileUrl is optional if custom fetcher will be set later\n return undefined;\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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type,\n mergedConfig,\n undefined,\n customProfileFetcher,\n );\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, OAuth2Token } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n EncryptionOptions,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\nimport { TokenEncryption } from '../encryption';\n\nexport type InMemoryStorageAdapterOptions = EncryptionOptions;\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 private encryption?: TokenEncryption;\n\n constructor(options?: InMemoryStorageAdapterOptions) {\n this.encryption = options?.encryption;\n }\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n /**\n * Encrypt token fields if encryption is enabled\n */\n private async encryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n const encrypted = await this.encryption.encryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: encrypted.accessToken,\n refreshToken: encrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt token fields if encryption is enabled\n */\n private async decryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n // Check if the token is actually encrypted\n if (!this.encryption.isEncrypted(token.accessToken)) {\n return token;\n }\n\n const decrypted = await this.encryption.decryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: decrypted.accessToken,\n refreshToken: decrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt a stored token before returning it\n */\n private async decryptStoredToken(storedToken: StoredToken): Promise<StoredToken> {\n if (!this.encryption) {\n return storedToken;\n }\n\n return {\n ...storedToken,\n token: await this.decryptToken(storedToken.token),\n };\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n // Use internal method that doesn't decrypt to check existence\n const existingToken = await this.getTokenInternal(input.provider, input.email, input.tenant);\n\n // Encrypt the token before storing\n const encryptedToken = await this.encryptToken(input.token);\n const inputWithEncryptedToken = { ...input, token: encryptedToken };\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...inputWithEncryptedToken,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(updatedToken);\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...inputWithEncryptedToken,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(newToken);\n }\n\n /**\n * Internal query that doesn't decrypt tokens (for existence checks)\n */\n private async queryTokensInternal(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 queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n const tokens = await this.queryTokensInternal(query);\n // Decrypt all tokens before returning\n return Promise.all(tokens.map((t) => this.decryptStoredToken(t)));\n }\n\n /**\n * Internal get that doesn't decrypt (for existence checks)\n */\n private async getTokenInternal(\n provider: string,\n email: string,\n tenant?: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({\n provider,\n email,\n tenant,\n includeExpired: true,\n });\n return results[0] || null;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const token = await this.getTokenInternal(provider, email, tenant);\n return token ? this.decryptStoredToken(token) : null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({ id, includeExpired: true });\n const token = results[0] || null;\n return token ? this.decryptStoredToken(token) : 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 let encryptedUpdateToken = update.token;\n if (update.token && this.encryption) {\n encryptedUpdateToken = await this.encryptToken(update.token);\n }\n\n const updatedToken: StoredToken = {\n ...token,\n ...(encryptedUpdateToken && { token: encryptedUpdateToken }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(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.getTokenInternal(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 // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config, customFetcher);\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","import { seal, unseal } from '../utils/seal';\n\n/**\n * Fields that will be encrypted in storage\n */\nexport interface EncryptedTokenFields {\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * Configuration for token encryption\n */\nexport interface TokenEncryptionConfig {\n /**\n * The encryption key (minimum 32 characters)\n * This should be stored securely (e.g., environment variable, secrets manager)\n */\n encryptionKey: string;\n}\n\n/**\n * Token encryption utility for encrypting sensitive OAuth2 token data at rest.\n * Uses AES-256-CBC encryption via iron-session with PBKDF2 key derivation.\n *\n * @example\n * ```typescript\n * const encryption = new TokenEncryption({\n * encryptionKey: process.env.TOKEN_ENCRYPTION_KEY!\n * });\n *\n * // Encrypt tokens before storage\n * const encrypted = await encryption.encryptTokenFields({\n * accessToken: 'ya29.xxx',\n * refreshToken: '1//xxx'\n * });\n *\n * // Decrypt tokens after retrieval\n * const decrypted = await encryption.decryptTokenFields(encrypted);\n * ```\n */\nexport class TokenEncryption {\n private readonly encryptionKey: string;\n\n constructor(config: TokenEncryptionConfig) {\n if (!config.encryptionKey || config.encryptionKey.length < 32) {\n throw new Error('Encryption key must be at least 32 characters long');\n }\n this.encryptionKey = config.encryptionKey;\n }\n\n /**\n * Encrypt token fields (accessToken and refreshToken)\n * Returns the encrypted values as strings that can be stored in the database\n */\n async encryptTokenFields(\n fields: EncryptedTokenFields,\n ): Promise<{ accessToken: string; refreshToken?: string }> {\n const encryptedAccessToken = await seal(fields.accessToken, this.encryptionKey);\n\n let encryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n encryptedRefreshToken = await seal(fields.refreshToken, this.encryptionKey);\n }\n\n return {\n accessToken: encryptedAccessToken,\n refreshToken: encryptedRefreshToken,\n };\n }\n\n /**\n * Decrypt token fields (accessToken and refreshToken)\n * Returns the original plaintext values\n */\n async decryptTokenFields(fields: {\n accessToken: string;\n refreshToken?: string;\n }): Promise<EncryptedTokenFields> {\n const decryptedAccessToken = await unseal<string>(fields.accessToken, this.encryptionKey);\n\n let decryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n decryptedRefreshToken = await unseal<string>(fields.refreshToken, this.encryptionKey);\n }\n\n // Handle case where decryption fails (returns empty object)\n if (\n !decryptedAccessToken ||\n (typeof decryptedAccessToken === 'object' && Object.keys(decryptedAccessToken).length === 0)\n ) {\n throw new Error('Failed to decrypt access token - invalid encryption key or corrupted data');\n }\n\n return {\n accessToken: decryptedAccessToken,\n refreshToken: decryptedRefreshToken || undefined,\n };\n }\n\n /**\n * Check if a string appears to be encrypted (starts with iron-session prefix)\n */\n isEncrypted(value: string): boolean {\n return value.startsWith('Fe26.2');\n }\n}\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","../src/encryption/token-encryption.ts"],"names":["StandardAuthorizationUrlStrategy","params","value","key","config","state","codeChallenge","extraParams","StandardTokenExchangeStrategy","code","codeVerifier","headers","credentials","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","customFetcher","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","customProfileFetcher","presetConfig","mergedConfig","name","InMemoryStorageAdapter","token","encrypted","decrypted","storedToken","input","existingToken","encryptedToken","inputWithEncryptedToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","encryptedUpdateToken","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","authUrl","authState","providerInstance","tenantName","profile","error","savedToken","tenantInfo","providerConfig","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData","TokenEncryption","fields","encryptedAccessToken","encryptedRefreshToken","decryptedAccessToken","decryptedRefreshToken"],"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 // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n // Add Basic Auth header if useBasicAuth is enabled (required by X/Twitter OAuth2)\n if (config.useBasicAuth && config.clientId && config.clientSecret) {\n const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString(\n 'base64',\n );\n headers['Authorization'] = `Basic ${credentials}`;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers,\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 // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n // Add Basic Auth header if useBasicAuth is enabled (required by X/Twitter OAuth2)\n if (config.useBasicAuth && config.clientId && config.clientSecret) {\n const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString(\n 'base64',\n );\n headers['Authorization'] = `Basic ${credentials}`;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers,\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 customFetcher?: BaseProfileFetcher,\n ): BaseProfileFetcher | undefined {\n // If a custom fetcher is provided, use it directly\n if (customFetcher) {\n return customFetcher;\n }\n\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 if available\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n // Return undefined instead of throwing - profileUrl is optional if custom fetcher will be set later\n return undefined;\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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type,\n mergedConfig,\n undefined,\n customProfileFetcher,\n );\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, OAuth2Token } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n EncryptionOptions,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\nimport { TokenEncryption } from '../encryption';\n\nexport type InMemoryStorageAdapterOptions = EncryptionOptions;\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 private encryption?: TokenEncryption;\n\n constructor(options?: InMemoryStorageAdapterOptions) {\n this.encryption = options?.encryption;\n }\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n /**\n * Encrypt token fields if encryption is enabled\n */\n private async encryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n const encrypted = await this.encryption.encryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: encrypted.accessToken,\n refreshToken: encrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt token fields if encryption is enabled\n */\n private async decryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n // Check if the token is actually encrypted\n if (!this.encryption.isEncrypted(token.accessToken)) {\n return token;\n }\n\n const decrypted = await this.encryption.decryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: decrypted.accessToken,\n refreshToken: decrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt a stored token before returning it\n */\n private async decryptStoredToken(storedToken: StoredToken): Promise<StoredToken> {\n if (!this.encryption) {\n return storedToken;\n }\n\n return {\n ...storedToken,\n token: await this.decryptToken(storedToken.token),\n };\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n // Use internal method that doesn't decrypt to check existence\n const existingToken = await this.getTokenInternal(input.provider, input.email, input.tenant);\n\n // Encrypt the token before storing\n const encryptedToken = await this.encryptToken(input.token);\n const inputWithEncryptedToken = { ...input, token: encryptedToken };\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...inputWithEncryptedToken,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(updatedToken);\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...inputWithEncryptedToken,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(newToken);\n }\n\n /**\n * Internal query that doesn't decrypt tokens (for existence checks)\n */\n private async queryTokensInternal(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 queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n const tokens = await this.queryTokensInternal(query);\n // Decrypt all tokens before returning\n return Promise.all(tokens.map((t) => this.decryptStoredToken(t)));\n }\n\n /**\n * Internal get that doesn't decrypt (for existence checks)\n */\n private async getTokenInternal(\n provider: string,\n email: string,\n tenant?: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({\n provider,\n email,\n tenant,\n includeExpired: true,\n });\n return results[0] || null;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const token = await this.getTokenInternal(provider, email, tenant);\n return token ? this.decryptStoredToken(token) : null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({ id, includeExpired: true });\n const token = results[0] || null;\n return token ? this.decryptStoredToken(token) : 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 let encryptedUpdateToken = update.token;\n if (update.token && this.encryption) {\n encryptedUpdateToken = await this.encryptToken(update.token);\n }\n\n const updatedToken: StoredToken = {\n ...token,\n ...(encryptedUpdateToken && { token: encryptedUpdateToken }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(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.getTokenInternal(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 // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config, customFetcher);\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 // Check if provider supports token refresh\n const providerConfig = this.providerConfigs.get(provider);\n if (providerConfig && providerConfig.refreshable === false) {\n // For non-refreshable tokens (e.g., Telegram sessions), just return the token\n // These tokens are long-lived and don't expire in the traditional sense\n return storedToken.token;\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 // Check if provider supports token refresh\n const providerConfig = this.providerConfigs.get(storedToken.provider);\n if (providerConfig && providerConfig.refreshable === false) {\n // Provider explicitly marked as non-refreshable (e.g., Telegram sessions)\n return false;\n }\n\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","import { seal, unseal } from '../utils/seal';\n\n/**\n * Fields that will be encrypted in storage\n */\nexport interface EncryptedTokenFields {\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * Configuration for token encryption\n */\nexport interface TokenEncryptionConfig {\n /**\n * The encryption key (minimum 32 characters)\n * This should be stored securely (e.g., environment variable, secrets manager)\n */\n encryptionKey: string;\n}\n\n/**\n * Token encryption utility for encrypting sensitive OAuth2 token data at rest.\n * Uses AES-256-CBC encryption via iron-session with PBKDF2 key derivation.\n *\n * @example\n * ```typescript\n * const encryption = new TokenEncryption({\n * encryptionKey: process.env.TOKEN_ENCRYPTION_KEY!\n * });\n *\n * // Encrypt tokens before storage\n * const encrypted = await encryption.encryptTokenFields({\n * accessToken: 'ya29.xxx',\n * refreshToken: '1//xxx'\n * });\n *\n * // Decrypt tokens after retrieval\n * const decrypted = await encryption.decryptTokenFields(encrypted);\n * ```\n */\nexport class TokenEncryption {\n private readonly encryptionKey: string;\n\n constructor(config: TokenEncryptionConfig) {\n if (!config.encryptionKey || config.encryptionKey.length < 32) {\n throw new Error('Encryption key must be at least 32 characters long');\n }\n this.encryptionKey = config.encryptionKey;\n }\n\n /**\n * Encrypt token fields (accessToken and refreshToken)\n * Returns the encrypted values as strings that can be stored in the database\n */\n async encryptTokenFields(\n fields: EncryptedTokenFields,\n ): Promise<{ accessToken: string; refreshToken?: string }> {\n const encryptedAccessToken = await seal(fields.accessToken, this.encryptionKey);\n\n let encryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n encryptedRefreshToken = await seal(fields.refreshToken, this.encryptionKey);\n }\n\n return {\n accessToken: encryptedAccessToken,\n refreshToken: encryptedRefreshToken,\n };\n }\n\n /**\n * Decrypt token fields (accessToken and refreshToken)\n * Returns the original plaintext values\n */\n async decryptTokenFields(fields: {\n accessToken: string;\n refreshToken?: string;\n }): Promise<EncryptedTokenFields> {\n const decryptedAccessToken = await unseal<string>(fields.accessToken, this.encryptionKey);\n\n let decryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n decryptedRefreshToken = await unseal<string>(fields.refreshToken, this.encryptionKey);\n }\n\n // Handle case where decryption fails (returns empty object)\n if (\n !decryptedAccessToken ||\n (typeof decryptedAccessToken === 'object' && Object.keys(decryptedAccessToken).length === 0)\n ) {\n throw new Error('Failed to decrypt access token - invalid encryption key or corrupted data');\n }\n\n return {\n accessToken: decryptedAccessToken,\n refreshToken: decryptedRefreshToken || undefined,\n };\n }\n\n /**\n * Check if a string appears to be encrypted (starts with iron-session prefix)\n */\n isEncrypted(value: string): boolean {\n return value.startsWith('Fe26.2');\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -7,6 +7,7 @@ interface OAuth2Config {
|
|
|
7
7
|
scopes: string[];
|
|
8
8
|
usePKCE?: boolean;
|
|
9
9
|
pkce?: boolean;
|
|
10
|
+
useBasicAuth?: boolean;
|
|
10
11
|
additionalParams?: Record<string, string>;
|
|
11
12
|
extraAuthParams?: Record<string, string>;
|
|
12
13
|
responseRootKey?: string;
|
|
@@ -20,6 +21,7 @@ interface OAuth2Config {
|
|
|
20
21
|
tokenType?: string | string[];
|
|
21
22
|
scope?: string | string[];
|
|
22
23
|
};
|
|
24
|
+
refreshable?: boolean;
|
|
23
25
|
}
|
|
24
26
|
interface OAuth2Token {
|
|
25
27
|
accessToken: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ interface OAuth2Config {
|
|
|
7
7
|
scopes: string[];
|
|
8
8
|
usePKCE?: boolean;
|
|
9
9
|
pkce?: boolean;
|
|
10
|
+
useBasicAuth?: boolean;
|
|
10
11
|
additionalParams?: Record<string, string>;
|
|
11
12
|
extraAuthParams?: Record<string, string>;
|
|
12
13
|
responseRootKey?: string;
|
|
@@ -20,6 +21,7 @@ interface OAuth2Config {
|
|
|
20
21
|
tokenType?: string | string[];
|
|
21
22
|
scope?: string | string[];
|
|
22
23
|
};
|
|
24
|
+
refreshable?: boolean;
|
|
23
25
|
}
|
|
24
26
|
interface OAuth2Token {
|
|
25
27
|
accessToken: string;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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 A=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 p=await n.text();throw new Error(`Token exchange failed: ${n.statusText} - ${p}`)}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 h,l,f,m,g;let n=Date.now(),i=this.extractValue(e,(h=o==null?void 0:o.tokenPaths)==null?void 0:h.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,p=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"]),P=(typeof p=="string"?parseInt(p,10):p)||3600,c=this.extractValue(e,(m=o==null?void 0:o.tokenPaths)==null?void 0:m.scope,["authed_user.scope","scope","token.scope"]),F=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+P*1e3),expiresIn:P,tokenType:F,scope:c,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 x=class extends k{constructor(e,t,r,o){super(e,t,r,o);}createAuthorizationUrlStrategy(){return new v}createTokenExchangeStrategy(){return new A}};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 S=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 w=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 U=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 u=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,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,o){if(o)return o;if(r!=null&&r.profileUrl)return new u(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 u("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let n=t.profileUrl||t.userInfoUrl;return n?new u(n):void 0}}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,r){let o=e!=="generic"?s.presetConfigs[e]||{}:{},n={...o,...t,authorizationUrl:t.authorizationUrl||o.authorizationUrl||"",tokenUrl:t.tokenUrl||o.tokenUrl||"",profileUrl:t.profileUrl||o.profileUrl,extraAuthParams:{...o.extraAuthParams||{},...t.extraAuthParams||{}}},i=E.createProfileFetcher(e,n,void 0,r);return new x(n,void 0,void 0,i)}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;encryption;constructor(e){this.encryption=e==null?void 0:e.encryption;}generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async encryptToken(e){if(!this.encryption)return e;let t=await this.encryption.encryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptToken(e){if(!this.encryption||!this.encryption.isEncrypted(e.accessToken))return e;let t=await this.encryption.decryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptStoredToken(e){return this.encryption?{...e,token:await this.decryptToken(e.token)}:e}async saveToken(e){let t=await this.getTokenInternal(e.provider,e.email,e.tenant),r=await this.encryptToken(e.token),o={...e,token:r};if(t){let i={...t,...o,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,i),this.decryptStoredToken(i)}let n={...o,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(n.id,n),this.decryptStoredToken(n)}async queryTokensInternal(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 queryTokens(e){let t=await this.queryTokensInternal(e);return Promise.all(t.map(r=>this.decryptStoredToken(r)))}async getTokenInternal(e,t,r){return (await this.queryTokensInternal({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getToken(e,t,r){let o=await this.getTokenInternal(e,t,r);return o?this.decryptStoredToken(o):null}async getTokenById(e){let r=(await this.queryTokensInternal({id:e,includeExpired:true}))[0]||null;return r?this.decryptStoredToken(r):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=t.token;t.token&&this.encryption&&(o=await this.encryptToken(t.token));let n={...r,...o&&{token:o},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,n),this.decryptStoredToken(n)}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let o=await this.getTokenInternal(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 N=()=>randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),B=s=>createHash("sha256").update(s).digest("base64url"),M=()=>randomBytes(16).toString("base64url");var b=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.storage.getProfileFetcher(e),o=this.detectProviderType(e,t),n=this.providerFactory.createProvider(o,t,r);this.providers.set(e,n);}async authorize(e){var a;let t=this.providers.get(e.provider);if(!t)throw new Error(`Provider ${e.provider} not found`);let r=M(),o,n;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let p=N(),y=B(p);o=t.generateAuthorizationUrl(r,y),n={state:r,codeVerifier:p,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,z;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,p=(m=r.metadata)==null?void 0:m.email,y=(g=r.metadata)==null?void 0:g.tenant,P=(z=r.metadata)==null?void 0:z.tenantName;if(!a||!p)throw new Error("User ID and email are required in authorization state");let c;if(n.hasProfileFetcher())try{c=await n.fetchProfile(i.accessToken);}catch(K){console.warn("Failed to fetch user profile:",K);}let F=await this.storage.saveToken({provider:o,userId:a,email:(c==null?void 0:c.email)||p,tenant:(c==null?void 0:c.tenant)||y,tenantName:(c==null?void 0:c.tenantName)||P,token:i,metadata:{...r.metadata,profileFetched:!!c}});await this.storage.deleteAuthorizationState(t);let h=this.providerConfigs.get(o);return h!=null&&h.onSuccess&&await h.onSuccess(a,i),{token:F,profile:c}}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 p=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${p}`)}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 C=(s,e)=>sealData(s,{password:e}),R=(s,e)=>unsealData(s,{password:e});var I=class{encryptionKey;constructor(e){if(!e.encryptionKey||e.encryptionKey.length<32)throw new Error("Encryption key must be at least 32 characters long");this.encryptionKey=e.encryptionKey;}async encryptTokenFields(e){let t=await C(e.accessToken,this.encryptionKey),r;return e.refreshToken&&(r=await C(e.refreshToken,this.encryptionKey)),{accessToken:t,refreshToken:r}}async decryptTokenFields(e){let t=await R(e.accessToken,this.encryptionKey),r;if(e.refreshToken&&(r=await R(e.refreshToken,this.encryptionKey)),!t||typeof t=="object"&&Object.keys(t).length===0)throw new Error("Failed to decrypt access token - invalid encryption key or corrupted data");return {accessToken:t,refreshToken:r||void 0}}isEncrypted(e){return e.startsWith("Fe26.2")}};
|
|
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,n])=>`${r}=${encodeURIComponent(n)}`).join("&")}generateAuthorizationUrl(e,t,r){let n={client_id:e.clientId,redirect_uri:e.redirectUri,response_type:"code",scope:e.scopes.join(" "),state:t};(e.usePKCE||e.pkce)&&r&&(n.code_challenge=r,n.code_challenge_method="S256");let o={...e.additionalParams,...e.extraAuthParams};return Object.assign(n,o),`${e.authorizationUrl}?${this.buildUrlParams(n)}`}};var A=class{buildUrlParams(e){return Object.entries(e).filter(([,r])=>r!==void 0).map(([r,n])=>`${r}=${encodeURIComponent(n)}`).join("&")}async exchangeCodeForToken(e,t,r){let n={grant_type:"authorization_code",code:e,redirect_uri:t.redirectUri,client_id:t.clientId};(t.usePKCE||t.pkce)&&r?n.code_verifier=r:t.clientSecret&&(n.client_secret=t.clientSecret);let o={"Content-Type":"application/x-www-form-urlencoded"};if(t.useBasicAuth&&t.clientId&&t.clientSecret){let d=Buffer.from(`${t.clientId}:${t.clientSecret}`).toString("base64");o.Authorization=`Basic ${d}`;}let i=await fetch(t.tokenUrl,{method:"POST",headers:o,body:this.buildUrlParams(n)});if(!i.ok){let d=await i.text();throw new Error(`Token exchange failed: ${i.statusText} - ${d}`)}let a=await i.json(),c=t.responseRootKey?a[t.responseRootKey]:a;return this.normalizeTokenResponse(c,a,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 n={"Content-Type":"application/x-www-form-urlencoded"};if(t.useBasicAuth&&t.clientId&&t.clientSecret){let c=Buffer.from(`${t.clientId}:${t.clientSecret}`).toString("base64");n.Authorization=`Basic ${c}`;}let o=await fetch(t.tokenUrl,{method:"POST",headers:n,body:this.buildUrlParams(r)});if(!o.ok){let c=await o.text();throw new Error(`Token refresh failed: ${o.statusText} - ${c}`)}let i=await o.json(),a=t.responseRootKey?i[t.responseRootKey]:i;return this.normalizeTokenResponse(a,i,e,t)}normalizeTokenResponse(e,t,r,n){var u,f,m,g,k;let o=Date.now(),i=this.extractValue(e,(u=n==null?void 0:n.tokenPaths)==null?void 0:u.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,(f=n==null?void 0:n.tokenPaths)==null?void 0:f.refreshToken,["authed_user.refresh_token","authed_user.refreshToken","refresh_token","refreshToken","token.refresh_token","token.refreshToken"])??r,c=this.extractValue(e,(m=n==null?void 0:n.tokenPaths)==null?void 0:m.expiresIn,["authed_user.expires_in","authed_user.expiresIn","expires_in","expiresIn","token.expires_in","token.expiresIn"]),P=(typeof c=="string"?parseInt(c,10):c)||3600,p=this.extractValue(e,(g=n==null?void 0:n.tokenPaths)==null?void 0:g.scope,["authed_user.scope","scope","token.scope"]),b=this.extractValue(e,(k=n==null?void 0:n.tokenPaths)==null?void 0:k.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(o+P*1e3),expiresIn:P,tokenType:b,scope:p,createdAt:o,raw:t}}extractValue(e,t,r){if(t){let n=Array.isArray(t)?t:[t];for(let o of n){let i=this.getNestedValue(e,o);if(i!==void 0)return i}}if(r)for(let n of r){let o=this.getNestedValue(e,n);if(o!==void 0)return o}}getNestedValue(e,t){let r=t.split("."),n=e;for(let o of r)if(n&&typeof n=="object"&&o in n)n=n[o];else return;return n}};var T=class{constructor(e,t,r,n){this.config=e;this.authUrlStrategy=t||this.createAuthorizationUrlStrategy(),this.tokenStrategy=r||this.createTokenExchangeStrategy(),this.profileFetcher=n;}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 x=class extends T{constructor(e,t,r,n){super(e,t,r,n);}createAuthorizationUrlStrategy(){return new v}createTokenExchangeStrategy(){return new A}};var h=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 h{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 h{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 h{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 l=class extends h{constructor(t,r,n){super(t);this.mapping=r;this.additionalHeaders=n;}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((n,o)=>n==null?void 0:n[o],t)}};var E=class{static createProfileFetcher(e,t,r,n){if(n)return n;if(r!=null&&r.profileUrl)return new l(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 l("https://graph.facebook.com/me?fields=id,name,email,picture");case "generic":default:let o=t.profileUrl||t.userInfoUrl;return o?new l(o):void 0}}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,r){let n=e!=="generic"?s.presetConfigs[e]||{}:{},o={...n,...t,authorizationUrl:t.authorizationUrl||n.authorizationUrl||"",tokenUrl:t.tokenUrl||n.tokenUrl||"",profileUrl:t.profileUrl||n.profileUrl,extraAuthParams:{...n.extraAuthParams||{},...t.extraAuthParams||{}}},i=E.createProfileFetcher(e,o,void 0,r);return new x(o,void 0,void 0,i)}static registerPreset(e,t){s.presetConfigs[e]=t;}static getPresetConfig(e){return s.presetConfigs[e]}};var y=class{tokens=new Map;states=new Map;profileFetchers=new Map;encryption;constructor(e){this.encryption=e==null?void 0:e.encryption;}generateId(){return Math.random().toString(36).substring(2)+Date.now().toString(36)}async encryptToken(e){if(!this.encryption)return e;let t=await this.encryption.encryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptToken(e){if(!this.encryption||!this.encryption.isEncrypted(e.accessToken))return e;let t=await this.encryption.decryptTokenFields({accessToken:e.accessToken,refreshToken:e.refreshToken});return {...e,accessToken:t.accessToken,refreshToken:t.refreshToken}}async decryptStoredToken(e){return this.encryption?{...e,token:await this.decryptToken(e.token)}:e}async saveToken(e){let t=await this.getTokenInternal(e.provider,e.email,e.tenant),r=await this.encryptToken(e.token),n={...e,token:r};if(t){let i={...t,...n,id:t.id,createdAt:t.createdAt,updatedAt:new Date};return this.tokens.set(t.id,i),this.decryptStoredToken(i)}let o={...n,id:this.generateId(),createdAt:new Date,updatedAt:new Date};return this.tokens.set(o.id,o),this.decryptStoredToken(o)}async queryTokensInternal(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(n=>new Date(n.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 queryTokens(e){let t=await this.queryTokensInternal(e);return Promise.all(t.map(r=>this.decryptStoredToken(r)))}async getTokenInternal(e,t,r){return (await this.queryTokensInternal({provider:e,email:t,tenant:r,includeExpired:true}))[0]||null}async getToken(e,t,r){let n=await this.getTokenInternal(e,t,r);return n?this.decryptStoredToken(n):null}async getTokenById(e){let r=(await this.queryTokensInternal({id:e,includeExpired:true}))[0]||null;return r?this.decryptStoredToken(r):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 n=t.token;t.token&&this.encryption&&(n=await this.encryptToken(t.token));let o={...r,...n&&{token:n},...t.metadata&&{metadata:{...r.metadata,...t.metadata}},updatedAt:new Date};return this.tokens.set(e,o),this.decryptStoredToken(o)}async deleteToken(e){return this.tokens.delete(e)}async deleteTokenByProviderEmail(e,t,r){let n=await this.getTokenInternal(e,t,r);return n?this.tokens.delete(n.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(([,n])=>e-n.createdAt.getTime()>t).map(([n])=>n);return r.forEach(n=>this.states.delete(n)),r.length}registerProfileFetcher(e,t){this.profileFetchers.set(e,t);}getProfileFetcher(e){return this.profileFetchers.get(e)}getProfileFetchers(){return new Map(this.profileFetchers)}};var B=()=>randomBytes(32).toString("base64").replace(/[^a-zA-Z0-9]/g,"").substring(0,128),N=s=>createHash("sha256").update(s).digest("base64url"),$=()=>randomBytes(16).toString("base64url");var F=class{storage;providerFactory;providers=new Map;providerConfigs=new Map;now;autoRefreshOptions;constructor(e={}){var t,r,n;this.storage=e.storage||new y,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:(n=e.autoRefresh)==null?void 0:n.onRefreshError},e.providers&&Object.entries(e.providers).forEach(([o,i])=>{this.registerProvider(o,i);});}registerProvider(e,t){this.providerConfigs.set(e,t);let r=this.storage.getProfileFetcher(e),n=this.detectProviderType(e,t),o=this.providerFactory.createProvider(n,t,r);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=$(),n,o;if(((a=this.providerConfigs.get(e.provider))==null?void 0:a.usePKCE)||e.usePKCE){let c=B(),d=N(c);n=t.generateAuthorizationUrl(r,d),o={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 n=t.generateAuthorizationUrl(r),o={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(o),{url:n,state:r}}async handleCallback(e,t){var f,m,g,k,z;let r=await this.storage.getAuthorizationState(t);if(!r)throw new Error("Invalid or expired state");let n=(f=r.metadata)==null?void 0:f.provider;if(!n)throw new Error("Provider not found in authorization state");let o=this.providers.get(n);if(!o)throw new Error(`Provider ${n} not found`);let i=await o.exchangeCodeForToken(e,r.codeVerifier),a=(m=r.metadata)==null?void 0:m.userId,c=(g=r.metadata)==null?void 0:g.email,d=(k=r.metadata)==null?void 0:k.tenant,P=(z=r.metadata)==null?void 0:z.tenantName;if(!a||!c)throw new Error("User ID and email are required in authorization state");let p;if(o.hasProfileFetcher())try{p=await o.fetchProfile(i.accessToken);}catch(M){console.warn("Failed to fetch user profile:",M);}let b=await this.storage.saveToken({provider:n,userId:a,email:(p==null?void 0:p.email)||c,tenant:(p==null?void 0:p.tenant)||d,tenantName:(p==null?void 0:p.tenantName)||P,token:i,metadata:{...r.metadata,profileFetched:!!p}});await this.storage.deleteAuthorizationState(t);let u=this.providerConfigs.get(n);return u!=null&&u.onSuccess&&await u.onSuccess(a,i),{token:b,profile:p}}async getAccessToken(e,t,r={}){return (await this.getValidToken(e,t,r)).accessToken}async getValidToken(e,t,r={}){let n=await this.storage.getToken(e,t,r.tenant);if(!n){let d=r.tenant?` and tenant ${r.tenant}`:"";throw new Error(`No token found for provider ${e}, email ${t}${d}`)}let o=this.providerConfigs.get(e);if(o&&o.refreshable===false||!(r.autoRefresh!==false&&this.isTokenExpired(n.token,r)))return n.token;if(!n.token.refreshToken)throw new Error("Token expired and no refresh token available");let a=this.providers.get(e);if(!a)throw new Error(`Provider ${e} not found`);let c=await a.refreshToken(n.token.refreshToken);return await this.storage.updateToken(n.id,{token:c}),c}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(o=>new Date(o.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 n=new Date(e.expiresAt).getTime();return this.now()+r*1e3>=n}detectProviderType(e,t){var n;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")||(n=t.scopes)!=null&&n.some(o=>o.includes("outlook"))?"outlook":"microsoft":"generic"}async refreshTokensIfNeeded(e){let t=e.map(async r=>{if(this.shouldRefreshToken(r))try{let n=this.providers.get(r.provider);if(!n)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 o=await n.refreshToken(r.token.refreshToken);return await this.storage.updateToken(r.id,{token:o})||r}catch(n){return this.autoRefreshOptions.onRefreshError&&this.autoRefreshOptions.onRefreshError(n,r),console.error(`Failed to refresh token for ${r.provider}:${r.email}:`,n),r}return r});return Promise.all(t)}shouldRefreshToken(e){let t=this.providerConfigs.get(e.provider);if(t&&t.refreshable===false||!e.token.refreshToken)return false;let r=new Date(e.token.expiresAt).getTime(),n=this.now();if(n>=r)return true;let o=this.autoRefreshOptions.refreshBuffer*60*1e3,i=r-o;return n>=i}updateAutoRefreshOptions(e){this.autoRefreshOptions={...this.autoRefreshOptions,...e};}async getTokensAcrossTenants(e,t){return this.queryTokens({provider:e,userId:t})}async getTenants(e,t){let n=(await this.queryTokens({provider:e,email:t})).map(o=>o.tenant).filter(o=>o!==void 0);return [...new Set(n)]}async getTokenByTenantName(e,t,r){return (await this.queryTokens({provider:e,email:t})).find(o=>o.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(n=>({token:n,tenant:n.tenant,tenantName:n.tenantName}))}};var C=(s,e)=>sealData(s,{password:e}),R=(s,e)=>unsealData(s,{password:e});var I=class{encryptionKey;constructor(e){if(!e.encryptionKey||e.encryptionKey.length<32)throw new Error("Encryption key must be at least 32 characters long");this.encryptionKey=e.encryptionKey;}async encryptTokenFields(e){let t=await C(e.accessToken,this.encryptionKey),r;return e.refreshToken&&(r=await C(e.refreshToken,this.encryptionKey)),{accessToken:t,refreshToken:r}}async decryptTokenFields(e){let t=await R(e.accessToken,this.encryptionKey),r;if(e.refreshToken&&(r=await R(e.refreshToken,this.encryptionKey)),!t||typeof t=="object"&&Object.keys(t).length===0)throw new Error("Failed to decrypt access token - invalid encryption key or corrupted data");return {accessToken:t,refreshToken:r||void 0}}isEncrypted(e){return e.startsWith("Fe26.2")}};
|
|
2
|
+
export{h as BaseProfileFetcher,x as GenericOAuth2Provider,l as GenericProfileFetcher,w as GitHubProfileFetcher,S as GoogleProfileFetcher,y as InMemoryStorageAdapter,U as MicrosoftProfileFetcher,F as OAuth2Client,T as OAuth2Provider,E as ProfileFetcherFactory,v as StandardAuthorizationUrlStrategy,A as StandardTokenExchangeStrategy,I as TokenEncryption,N as createCodeChallenge,B as createCodeVerifier,$ as generateState,C as seal,R 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","../src/encryption/token-encryption.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","customFetcher","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","customProfileFetcher","presetConfig","mergedConfig","name","InMemoryStorageAdapter","token","encrypted","decrypted","storedToken","input","existingToken","encryptedToken","inputWithEncryptedToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","encryptedUpdateToken","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","authUrl","authState","providerInstance","tenantName","profile","error","savedToken","tenantInfo","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData","TokenEncryption","fields","encryptedAccessToken","encryptedRefreshToken","decryptedAccessToken","decryptedRefreshToken"],"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 customFetcher?: BaseProfileFetcher,\n ): BaseProfileFetcher | undefined {\n // If a custom fetcher is provided, use it directly\n if (customFetcher) {\n return customFetcher;\n }\n\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 if available\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n // Return undefined instead of throwing - profileUrl is optional if custom fetcher will be set later\n return undefined;\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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type,\n mergedConfig,\n undefined,\n customProfileFetcher,\n );\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, OAuth2Token } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n EncryptionOptions,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\nimport { TokenEncryption } from '../encryption';\n\nexport type InMemoryStorageAdapterOptions = EncryptionOptions;\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 private encryption?: TokenEncryption;\n\n constructor(options?: InMemoryStorageAdapterOptions) {\n this.encryption = options?.encryption;\n }\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n /**\n * Encrypt token fields if encryption is enabled\n */\n private async encryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n const encrypted = await this.encryption.encryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: encrypted.accessToken,\n refreshToken: encrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt token fields if encryption is enabled\n */\n private async decryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n // Check if the token is actually encrypted\n if (!this.encryption.isEncrypted(token.accessToken)) {\n return token;\n }\n\n const decrypted = await this.encryption.decryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: decrypted.accessToken,\n refreshToken: decrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt a stored token before returning it\n */\n private async decryptStoredToken(storedToken: StoredToken): Promise<StoredToken> {\n if (!this.encryption) {\n return storedToken;\n }\n\n return {\n ...storedToken,\n token: await this.decryptToken(storedToken.token),\n };\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n // Use internal method that doesn't decrypt to check existence\n const existingToken = await this.getTokenInternal(input.provider, input.email, input.tenant);\n\n // Encrypt the token before storing\n const encryptedToken = await this.encryptToken(input.token);\n const inputWithEncryptedToken = { ...input, token: encryptedToken };\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...inputWithEncryptedToken,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(updatedToken);\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...inputWithEncryptedToken,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(newToken);\n }\n\n /**\n * Internal query that doesn't decrypt tokens (for existence checks)\n */\n private async queryTokensInternal(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 queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n const tokens = await this.queryTokensInternal(query);\n // Decrypt all tokens before returning\n return Promise.all(tokens.map((t) => this.decryptStoredToken(t)));\n }\n\n /**\n * Internal get that doesn't decrypt (for existence checks)\n */\n private async getTokenInternal(\n provider: string,\n email: string,\n tenant?: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({\n provider,\n email,\n tenant,\n includeExpired: true,\n });\n return results[0] || null;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const token = await this.getTokenInternal(provider, email, tenant);\n return token ? this.decryptStoredToken(token) : null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({ id, includeExpired: true });\n const token = results[0] || null;\n return token ? this.decryptStoredToken(token) : 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 let encryptedUpdateToken = update.token;\n if (update.token && this.encryption) {\n encryptedUpdateToken = await this.encryptToken(update.token);\n }\n\n const updatedToken: StoredToken = {\n ...token,\n ...(encryptedUpdateToken && { token: encryptedUpdateToken }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(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.getTokenInternal(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 // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config, customFetcher);\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","import { seal, unseal } from '../utils/seal';\n\n/**\n * Fields that will be encrypted in storage\n */\nexport interface EncryptedTokenFields {\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * Configuration for token encryption\n */\nexport interface TokenEncryptionConfig {\n /**\n * The encryption key (minimum 32 characters)\n * This should be stored securely (e.g., environment variable, secrets manager)\n */\n encryptionKey: string;\n}\n\n/**\n * Token encryption utility for encrypting sensitive OAuth2 token data at rest.\n * Uses AES-256-CBC encryption via iron-session with PBKDF2 key derivation.\n *\n * @example\n * ```typescript\n * const encryption = new TokenEncryption({\n * encryptionKey: process.env.TOKEN_ENCRYPTION_KEY!\n * });\n *\n * // Encrypt tokens before storage\n * const encrypted = await encryption.encryptTokenFields({\n * accessToken: 'ya29.xxx',\n * refreshToken: '1//xxx'\n * });\n *\n * // Decrypt tokens after retrieval\n * const decrypted = await encryption.decryptTokenFields(encrypted);\n * ```\n */\nexport class TokenEncryption {\n private readonly encryptionKey: string;\n\n constructor(config: TokenEncryptionConfig) {\n if (!config.encryptionKey || config.encryptionKey.length < 32) {\n throw new Error('Encryption key must be at least 32 characters long');\n }\n this.encryptionKey = config.encryptionKey;\n }\n\n /**\n * Encrypt token fields (accessToken and refreshToken)\n * Returns the encrypted values as strings that can be stored in the database\n */\n async encryptTokenFields(\n fields: EncryptedTokenFields,\n ): Promise<{ accessToken: string; refreshToken?: string }> {\n const encryptedAccessToken = await seal(fields.accessToken, this.encryptionKey);\n\n let encryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n encryptedRefreshToken = await seal(fields.refreshToken, this.encryptionKey);\n }\n\n return {\n accessToken: encryptedAccessToken,\n refreshToken: encryptedRefreshToken,\n };\n }\n\n /**\n * Decrypt token fields (accessToken and refreshToken)\n * Returns the original plaintext values\n */\n async decryptTokenFields(fields: {\n accessToken: string;\n refreshToken?: string;\n }): Promise<EncryptedTokenFields> {\n const decryptedAccessToken = await unseal<string>(fields.accessToken, this.encryptionKey);\n\n let decryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n decryptedRefreshToken = await unseal<string>(fields.refreshToken, this.encryptionKey);\n }\n\n // Handle case where decryption fails (returns empty object)\n if (\n !decryptedAccessToken ||\n (typeof decryptedAccessToken === 'object' && Object.keys(decryptedAccessToken).length === 0)\n ) {\n throw new Error('Failed to decrypt access token - invalid encryption key or corrupted data');\n }\n\n return {\n accessToken: decryptedAccessToken,\n refreshToken: decryptedRefreshToken || undefined,\n };\n }\n\n /**\n * Check if a string appears to be encrypted (starts with iron-session prefix)\n */\n isEncrypted(value: string): boolean {\n return value.startsWith('Fe26.2');\n }\n}\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","../src/encryption/token-encryption.ts"],"names":["StandardAuthorizationUrlStrategy","params","value","key","config","state","codeChallenge","extraParams","StandardTokenExchangeStrategy","code","codeVerifier","headers","credentials","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","customFetcher","profileUrl","providerName","OAuth2ProviderFactory","_OAuth2ProviderFactory","type","customProfileFetcher","presetConfig","mergedConfig","name","InMemoryStorageAdapter","token","encrypted","decrypted","storedToken","input","existingToken","encryptedToken","inputWithEncryptedToken","updatedToken","newToken","query","tokens","t","provider","email","tenant","id","userId","update","encryptedUpdateToken","expiredTokens","newState","maxAge","expiredStates","fetcher","createCodeVerifier","randomBytes","createCodeChallenge","verifier","createHash","generateState","OAuth2Client","authUrl","authState","providerInstance","tenantName","profile","error","savedToken","tenantInfo","providerConfig","queryWithExpired","expirationBuffer","expiresAt","s","refreshPromises","bufferMs","shouldRefreshAt","tenants","seal","d","sealData","unseal","unsealData","TokenEncryption","fields","encryptedAccessToken","encryptedRefreshToken","decryptedAccessToken","decryptedRefreshToken"],"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 // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n // Add Basic Auth header if useBasicAuth is enabled (required by X/Twitter OAuth2)\n if (config.useBasicAuth && config.clientId && config.clientSecret) {\n const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString(\n 'base64',\n );\n headers['Authorization'] = `Basic ${credentials}`;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers,\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 // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n // Add Basic Auth header if useBasicAuth is enabled (required by X/Twitter OAuth2)\n if (config.useBasicAuth && config.clientId && config.clientSecret) {\n const credentials = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString(\n 'base64',\n );\n headers['Authorization'] = `Basic ${credentials}`;\n }\n\n const response = await fetch(config.tokenUrl, {\n method: 'POST',\n headers,\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 customFetcher?: BaseProfileFetcher,\n ): BaseProfileFetcher | undefined {\n // If a custom fetcher is provided, use it directly\n if (customFetcher) {\n return customFetcher;\n }\n\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 if available\n const profileUrl = config.profileUrl || config.userInfoUrl;\n if (!profileUrl) {\n // Return undefined instead of throwing - profileUrl is optional if custom fetcher will be set later\n return undefined;\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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type: ProviderType,\n config: OAuth2Config,\n customProfileFetcher?: import('../profile/base-profile-fetcher').BaseProfileFetcher,\n ): 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(\n type,\n mergedConfig,\n undefined,\n customProfileFetcher,\n );\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, OAuth2Token } from '../types';\nimport {\n StorageAdapter,\n StoredToken,\n SaveTokenInput,\n UpdateTokenInput,\n TokenQuery,\n EncryptionOptions,\n} from './interfaces';\nimport { BaseProfileFetcher } from '../profile/base-profile-fetcher';\nimport { TokenEncryption } from '../encryption';\n\nexport type InMemoryStorageAdapterOptions = EncryptionOptions;\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 private encryption?: TokenEncryption;\n\n constructor(options?: InMemoryStorageAdapterOptions) {\n this.encryption = options?.encryption;\n }\n\n private generateId(): string {\n return Math.random().toString(36).substring(2) + Date.now().toString(36);\n }\n\n /**\n * Encrypt token fields if encryption is enabled\n */\n private async encryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n const encrypted = await this.encryption.encryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: encrypted.accessToken,\n refreshToken: encrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt token fields if encryption is enabled\n */\n private async decryptToken(token: OAuth2Token): Promise<OAuth2Token> {\n if (!this.encryption) {\n return token;\n }\n\n // Check if the token is actually encrypted\n if (!this.encryption.isEncrypted(token.accessToken)) {\n return token;\n }\n\n const decrypted = await this.encryption.decryptTokenFields({\n accessToken: token.accessToken,\n refreshToken: token.refreshToken,\n });\n\n return {\n ...token,\n accessToken: decrypted.accessToken,\n refreshToken: decrypted.refreshToken,\n };\n }\n\n /**\n * Decrypt a stored token before returning it\n */\n private async decryptStoredToken(storedToken: StoredToken): Promise<StoredToken> {\n if (!this.encryption) {\n return storedToken;\n }\n\n return {\n ...storedToken,\n token: await this.decryptToken(storedToken.token),\n };\n }\n\n // Token operations\n async saveToken(input: SaveTokenInput): Promise<StoredToken> {\n // Check if token with same provider + email + tenant exists\n // Use internal method that doesn't decrypt to check existence\n const existingToken = await this.getTokenInternal(input.provider, input.email, input.tenant);\n\n // Encrypt the token before storing\n const encryptedToken = await this.encryptToken(input.token);\n const inputWithEncryptedToken = { ...input, token: encryptedToken };\n\n if (existingToken) {\n // Replace existing token\n const updatedToken: StoredToken = {\n ...existingToken,\n ...inputWithEncryptedToken,\n id: existingToken.id,\n createdAt: existingToken.createdAt,\n updatedAt: new Date(),\n };\n this.tokens.set(existingToken.id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(updatedToken);\n }\n\n // Create new token\n const newToken: StoredToken = {\n ...inputWithEncryptedToken,\n id: this.generateId(),\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n this.tokens.set(newToken.id, newToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(newToken);\n }\n\n /**\n * Internal query that doesn't decrypt tokens (for existence checks)\n */\n private async queryTokensInternal(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 queryTokens(query: TokenQuery): Promise<StoredToken[]> {\n const tokens = await this.queryTokensInternal(query);\n // Decrypt all tokens before returning\n return Promise.all(tokens.map((t) => this.decryptStoredToken(t)));\n }\n\n /**\n * Internal get that doesn't decrypt (for existence checks)\n */\n private async getTokenInternal(\n provider: string,\n email: string,\n tenant?: string,\n ): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({\n provider,\n email,\n tenant,\n includeExpired: true,\n });\n return results[0] || null;\n }\n\n async getToken(provider: string, email: string, tenant?: string): Promise<StoredToken | null> {\n const token = await this.getTokenInternal(provider, email, tenant);\n return token ? this.decryptStoredToken(token) : null;\n }\n\n async getTokenById(id: string): Promise<StoredToken | null> {\n const results = await this.queryTokensInternal({ id, includeExpired: true });\n const token = results[0] || null;\n return token ? this.decryptStoredToken(token) : 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 let encryptedUpdateToken = update.token;\n if (update.token && this.encryption) {\n encryptedUpdateToken = await this.encryptToken(update.token);\n }\n\n const updatedToken: StoredToken = {\n ...token,\n ...(encryptedUpdateToken && { token: encryptedUpdateToken }),\n ...(update.metadata && { metadata: { ...token.metadata, ...update.metadata } }),\n updatedAt: new Date(),\n };\n this.tokens.set(id, updatedToken);\n // Return decrypted version to caller\n return this.decryptStoredToken(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.getTokenInternal(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 // Check if storage has a custom profile fetcher for this provider\n const customFetcher = this.storage.getProfileFetcher(name);\n\n // Determine provider type based on configuration\n const providerType = this.detectProviderType(name, config);\n const provider = this.providerFactory.createProvider(providerType, config, customFetcher);\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 // Check if provider supports token refresh\n const providerConfig = this.providerConfigs.get(provider);\n if (providerConfig && providerConfig.refreshable === false) {\n // For non-refreshable tokens (e.g., Telegram sessions), just return the token\n // These tokens are long-lived and don't expire in the traditional sense\n return storedToken.token;\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 // Check if provider supports token refresh\n const providerConfig = this.providerConfigs.get(storedToken.provider);\n if (providerConfig && providerConfig.refreshable === false) {\n // Provider explicitly marked as non-refreshable (e.g., Telegram sessions)\n return false;\n }\n\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","import { seal, unseal } from '../utils/seal';\n\n/**\n * Fields that will be encrypted in storage\n */\nexport interface EncryptedTokenFields {\n accessToken: string;\n refreshToken?: string;\n}\n\n/**\n * Configuration for token encryption\n */\nexport interface TokenEncryptionConfig {\n /**\n * The encryption key (minimum 32 characters)\n * This should be stored securely (e.g., environment variable, secrets manager)\n */\n encryptionKey: string;\n}\n\n/**\n * Token encryption utility for encrypting sensitive OAuth2 token data at rest.\n * Uses AES-256-CBC encryption via iron-session with PBKDF2 key derivation.\n *\n * @example\n * ```typescript\n * const encryption = new TokenEncryption({\n * encryptionKey: process.env.TOKEN_ENCRYPTION_KEY!\n * });\n *\n * // Encrypt tokens before storage\n * const encrypted = await encryption.encryptTokenFields({\n * accessToken: 'ya29.xxx',\n * refreshToken: '1//xxx'\n * });\n *\n * // Decrypt tokens after retrieval\n * const decrypted = await encryption.decryptTokenFields(encrypted);\n * ```\n */\nexport class TokenEncryption {\n private readonly encryptionKey: string;\n\n constructor(config: TokenEncryptionConfig) {\n if (!config.encryptionKey || config.encryptionKey.length < 32) {\n throw new Error('Encryption key must be at least 32 characters long');\n }\n this.encryptionKey = config.encryptionKey;\n }\n\n /**\n * Encrypt token fields (accessToken and refreshToken)\n * Returns the encrypted values as strings that can be stored in the database\n */\n async encryptTokenFields(\n fields: EncryptedTokenFields,\n ): Promise<{ accessToken: string; refreshToken?: string }> {\n const encryptedAccessToken = await seal(fields.accessToken, this.encryptionKey);\n\n let encryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n encryptedRefreshToken = await seal(fields.refreshToken, this.encryptionKey);\n }\n\n return {\n accessToken: encryptedAccessToken,\n refreshToken: encryptedRefreshToken,\n };\n }\n\n /**\n * Decrypt token fields (accessToken and refreshToken)\n * Returns the original plaintext values\n */\n async decryptTokenFields(fields: {\n accessToken: string;\n refreshToken?: string;\n }): Promise<EncryptedTokenFields> {\n const decryptedAccessToken = await unseal<string>(fields.accessToken, this.encryptionKey);\n\n let decryptedRefreshToken: string | undefined;\n if (fields.refreshToken) {\n decryptedRefreshToken = await unseal<string>(fields.refreshToken, this.encryptionKey);\n }\n\n // Handle case where decryption fails (returns empty object)\n if (\n !decryptedAccessToken ||\n (typeof decryptedAccessToken === 'object' && Object.keys(decryptedAccessToken).length === 0)\n ) {\n throw new Error('Failed to decrypt access token - invalid encryption key or corrupted data');\n }\n\n return {\n accessToken: decryptedAccessToken,\n refreshToken: decryptedRefreshToken || undefined,\n };\n }\n\n /**\n * Check if a string appears to be encrypted (starts with iron-session prefix)\n */\n isEncrypted(value: string): boolean {\n return value.startsWith('Fe26.2');\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dainprotocol/oauth2-token-manager",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
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
|
+
}
|