UNPKG

@ioloco/oauth

Version:

OAuth 2.0 utility library that provides helper functions for integrating third-party login providers. Designed to simplify the token exchange and user-fetch flows, while leaving API route implementation to the developer.

1 lines 2.78 kB
import{z as e}from"zod";import{createHash as t,randomBytes as r}from"crypto";import{InvalidTokenError as o,InvalidStateError as s,InvalidUserError as i,InvalidCodeVerifierError as c}from"../Error/errors.js";import{fetchOAuthToken as n}from"../@Queries/fetchOauthToken.js";import{fetchOAuthUser as h}from"../@Queries/fetchOauthUser.js";class a{constructor({provider:t,urls:r,clientId:o,clientSecret:s,scopes:i,userInfo:c}){this.tokenSchema=e.object({access_token:e.string(),token_type:e.string().optional(),refresh_token:e.string().optional(),expires_in:e.number().optional(),scope:e.string().optional()}),this.provider=t,this.urls=r,this.clientId=o,this.clientSecret=s,this.scopes=i,this.userInfo=c}async createAuthUrl(e,o){const s=(e=>{const t=r(64).toString("hex").normalize();return e.set("oauth_validate_cookie",t,{secure:"production"===process.env.NODE_ENV,httpOnly:!0,sameSite:"lax",expires:new Date(Date.now()+6e5)}),t})(e),i=(e=>{const t=r(64).toString("hex").normalize();return e.set("oauth_code_verifier",t,{secure:"production"===process.env.NODE_ENV,httpOnly:!0,sameSite:"lax",expires:new Date(Date.now()+6e5)}),t})(e),c=new URL(this.urls.auth);c.searchParams.set("client_id",this.clientId),c.searchParams.set("redirect_uri",this.urls.redirect_base.toString()),c.searchParams.set("response_type","code"),c.searchParams.set("scope",this.scopes.join(" ")),c.searchParams.set("state",s),c.searchParams.set("code_challenge_method","S256");const n=t("sha256").update(i).digest("base64url");return c.searchParams.set("code_challenge",n),"google"===this.provider&&(c.searchParams.set("access_type","offline"),o?.forceConsent&&c.searchParams.set("prompt","consent")),c.toString()}async fetchToken({code:e,codeVerifier:t}){const r=await n({tokenUrl:this.urls.token,clientId:this.clientId,clientSecret:this.clientSecret,redirectUri:this.urls.redirect_base,code:e,codeVerifier:t}),s=this.tokenSchema.safeParse(r);if(!s.success)throw new o(s.error);return{accessToken:s.data.access_token,tokenType:s.data.token_type??"Bearer",refreshToken:s.data.refresh_token,expiresIn:s.data.expires_in,scope:s.data.scope}}async fetchUser({code:e,state:t,cookies:r}){const o=await((e,t)=>{const r=t.get("oauth_validate_cookie")?.value;return r===e})(t,r);if(!o)throw new s;const{accessToken:c,tokenType:n,refreshToken:a,expiresIn:u,scope:f}=await this.fetchToken({code:e,codeVerifier:p(r)}),d=await h({userUrl:this.urls.user,accessToken:c,tokenType:n}),l=this.userInfo.schema.safeParse(d);if(!l.success)throw new i(l.error);return r.delete("oauth_validate_cookie"),r.delete("oauth_code_verifier"),{user:this.userInfo.parser(l.data),accessToken:c,refreshToken:a,expiresIn:u,scope:f}}}function p(e){const t=e.get("oauth_code_verifier")?.value;if(null==t)throw new c;return t}export{a as OAuthClient};