UNPKG

altair-graphql-core

Version:

Several of the core logic for altair graphql client

150 lines (149 loc) 5.53 kB
import { base64EncodeSafe, getCodeChallenge } from './helpers'; import { AuthFormat, OAuth2Type, RequestFormat, } from './types'; export class OAuth2Client { constructor(options) { this.options = options; } async getAuthorizationUrl() { if (this.options.type === OAuth2Type.CLIENT_CREDENTIALS) { throw new Error('Client Credentials flow not supported for authorization code'); } const params = { response_type: 'code', client_id: this.options.clientId, redirect_uri: this.options.redirectUri, state: this.options.state, scope: this.options.scopes.join(' '), ...(this.options.type === 'auth_code_pkce' ? { code_challenge: await getCodeChallenge(this.options.codeVerifier), code_challenge_method: 'S256', } : {}), }; const urlParams = new URLSearchParams(params); const u = new URL(this.options.authorizationEndpoint); const url = new URL(`${u.origin}${u.pathname}?${urlParams.toString()}`); return url.toString(); } async getAuthorizationRedirectResponse() { if (this.options.type === OAuth2Type.CLIENT_CREDENTIALS) { throw new Error('Client Credentials flow not supported for authorization code'); } // Get params from url const url = new URL(window.location.href); const obj = Object.fromEntries(url.searchParams.entries()); if (obj.error) { return { error: obj.error, state: obj.state ?? '', error_description: obj.error_description, error_uri: obj.error_uri, }; } // Validate params if (!obj.code || !obj.state) { return; } // verify state is the same as the one generated if (obj.state !== this.options.state) { return { error: 'invalid_state', state: obj.state, error_description: 'The state is invalid', }; } // Return params return { code: obj.code, state: obj.state }; } // Since this will be a CORS request, we only support it in the desktop app for now async getAccessTokenFromCode(code) { if (this.options.type === OAuth2Type.CLIENT_CREDENTIALS) { throw new Error('Client Credentials flow not supported'); } const params = { grant_type: 'authorization_code', code, redirect_uri: this.options.redirectUri, client_id: this.options.clientId, client_secret: this.options.clientSecret, ...(this.options.type === 'auth_code_pkce' ? { code_verifier: this.options.codeVerifier } : {}), }; return this.makeAccessTokenRequest(params); } async getAccessTokenFromClientCredentials() { if (this.options.type !== OAuth2Type.CLIENT_CREDENTIALS) { throw new Error('Only Client Credentials flow is supported'); } const params = { grant_type: 'client_credentials', client_id: this.options.clientId, client_secret: this.options.clientSecret, scope: this.options.scopes.join(' '), }; return this.makeAccessTokenRequest(params); } getAccessTokenRequestHeaders() { const headers = {}; switch (this.options.authFormat) { case AuthFormat.BASIC_AUTH: { headers.Authorization = `Basic ${base64EncodeSafe(`${this.options.clientId}:${this.options.clientSecret}`)}`; break; } } switch (this.options.requestFormat) { case RequestFormat.JSON: { headers.Accept = 'application/json'; headers['Content-Type'] = 'application/json'; break; } case RequestFormat.FORM: { headers['Content-Type'] = 'application/x-www-form-urlencoded'; break; } } return headers; } getAccessTokenRequestBody(params) { let bodyParams = structuredClone(params); switch (this.options.authFormat) { case AuthFormat.BASIC_AUTH: { const { client_id, client_secret, ...rest } = params; bodyParams = rest; break; } } switch (this.options.requestFormat) { case RequestFormat.JSON: return JSON.stringify(bodyParams); case RequestFormat.FORM: return new URLSearchParams({ ...bodyParams }).toString(); } } async makeAccessTokenRequest(params) { const response = await fetch(this.options.tokenEndpoint, { method: 'POST', headers: this.getAccessTokenRequestHeaders(), body: this.getAccessTokenRequestBody(params), }); const data = await response.json(); return data; } } /* in app: listen for ready message from auth window send [options + action] to the auth window listen for authorization code from auth window close auth window exchange code for access token in auth window: send ready message to app listen for options message from app - redirect to authorization url - get code from url - send code to app */ //# sourceMappingURL=client.js.map