UNPKG

nylas

Version:

A NodeJS wrapper for the Nylas REST API for email, contacts, and calendar.

177 lines (176 loc) 6.27 kB
import { v4 as uuid } from 'uuid'; import { createHash } from 'node:crypto'; import { Resource } from './resource.js'; import { makePathParams } from '../utils.js'; /** * A collection of authentication related API endpoints * * These endpoints allow for various functionality related to authentication. * Also contains the Grants API and collection of provider API endpoints. */ export class Auth extends Resource { /** * Build the URL for authenticating users to your application with OAuth 2.0 * @param config The configuration for building the URL * @return The URL for hosted authentication */ urlForOAuth2(config) { return this.urlAuthBuilder(config).toString(); } /** * Exchange an authorization code for an access token * @param request The request parameters for the code exchange * @return Information about the Nylas application */ exchangeCodeForToken(request) { if (!request.clientSecret) { request.clientSecret = this.apiClient.apiKey; } return this.apiClient.request({ method: 'POST', path: makePathParams('/v3/connect/token', {}), body: { ...request, grantType: 'authorization_code', }, }); } /** * Refresh an access token * @param request The refresh token request * @return The response containing the new access token */ refreshAccessToken(request) { if (!request.clientSecret) { request.clientSecret = this.apiClient.apiKey; } return this.apiClient.request({ method: 'POST', path: makePathParams('/v3/connect/token', {}), body: { ...request, grantType: 'refresh_token', }, }); } /** * Build the URL for authenticating users to your application with OAuth 2.0 and PKCE * IMPORTANT: YOU WILL NEED TO STORE THE 'secret' returned to use it inside the CodeExchange flow * @param config The configuration for building the URL * @return The URL for hosted authentication */ urlForOAuth2PKCE(config) { const url = this.urlAuthBuilder(config); // Add code challenge to URL generation url.searchParams.set('code_challenge_method', 's256'); const secret = uuid(); const secretHash = this.hashPKCESecret(secret); url.searchParams.set('code_challenge', secretHash); // Return the url with secret & hashed secret return { secret, secretHash, url: url.toString() }; } /** * Build the URL for admin consent authentication for Microsoft * @param config The configuration for building the URL * @return The URL for admin consent authentication */ urlForAdminConsent(config) { const configWithProvider = { ...config, provider: 'microsoft' }; const url = this.urlAuthBuilder(configWithProvider); url.searchParams.set('response_type', 'adminconsent'); url.searchParams.set('credential_id', config.credentialId); return url.toString(); } /** * Create a grant via Custom Authentication * @return The created grant */ customAuthentication({ requestBody, overrides, }) { return this.apiClient.request({ method: 'POST', path: makePathParams('/v3/connect/custom', {}), body: requestBody, overrides, }); } /** * Revoke a token (and the grant attached to the token) * @param token The token to revoke * @return True if the token was revoked successfully */ async revoke(token) { await this.apiClient.request({ method: 'POST', path: makePathParams('/v3/connect/revoke', {}), queryParams: { token, }, }); return true; } /** * Detect provider from email address * @param params The parameters to include in the request * @return The detected provider, if found */ async detectProvider(params) { return this.apiClient.request({ method: 'POST', path: makePathParams('/v3/providers/detect', {}), queryParams: params, }); } /** * Get info about an ID token * @param idToken The ID token to query. * @return The token information */ idTokenInfo(idToken) { return this.getTokenInfo({ id_token: idToken }); } /** * Get info about an access token * @param accessToken The access token to query. * @return The token information */ accessTokenInfo(accessToken) { return this.getTokenInfo({ access_token: accessToken }); } urlAuthBuilder(config) { const url = new URL(`${this.apiClient.serverUrl}/v3/connect/auth`); url.searchParams.set('client_id', config.clientId); url.searchParams.set('redirect_uri', config.redirectUri); url.searchParams.set('access_type', config.accessType ? config.accessType : 'online'); url.searchParams.set('response_type', 'code'); if (config.provider) { url.searchParams.set('provider', config.provider); } if (config.loginHint) { url.searchParams.set('login_hint', config.loginHint); } if (config.includeGrantScopes !== undefined) { url.searchParams.set('include_grant_scopes', config.includeGrantScopes.toString()); } if (config.scope) { url.searchParams.set('scope', config.scope.join(' ')); } if (config.prompt) { url.searchParams.set('prompt', config.prompt); } if (config.state) { url.searchParams.set('state', config.state); } return url; } hashPKCESecret(secret) { const hash = createHash('sha256').update(secret).digest('hex'); return Buffer.from(hash).toString('base64').replace(/=+$/, ''); } getTokenInfo(params) { return this.apiClient.request({ method: 'GET', path: makePathParams('/v3/connect/tokeninfo', {}), queryParams: params, }); } }