UNPKG

@datalayer/core

Version:

[![Datalayer](https://assets.datalayer.tech/datalayer-25.svg)](https://datalayer.io)

310 lines (309 loc) 11.6 kB
/* * Copyright (c) 2023-2025 Datalayer, Inc. * Distributed under the terms of the Modified BSD License. */ /** * OAuth2 API functions for the Datalayer platform. * * Provides functions for OAuth2 authorization flows with various providers. * * @module api/iam/oauth2 */ import { requestDatalayerAPI } from '../DatalayerApi'; import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants'; /** * Get the OAuth2 authorization URL for a specific provider * @param provider - OAuth2 provider (bluesky, github, linkedin, okta) * @param callbackUri - Server endpoint to call with the authz token * @param nonce - Optional nonce for security * @param baseUrl - Base URL for the API (defaults to production IAM URL) * @returns OAuth2 authorization URL response * @throws {Error} If required parameters are missing or invalid * * @remarks * This endpoint generates the OAuth2 authorization URL for the specified provider. * Users should be redirected to the returned loginURL to begin the OAuth2 flow. * * Expected status codes: * - 200: Successfully generated authorization URL * - 400: Invalid parameters * - 404: Provider not found or not configured */ export const getOAuth2AuthzUrl = async (provider, callbackUri, nonce, baseUrl = DEFAULT_SERVICE_URLS.IAM) => { if (!provider) { throw new Error('OAuth2 provider is required'); } if (!callbackUri) { throw new Error('Callback URI is required'); } // Build query parameters const queryParams = new URLSearchParams({ provider, callback_uri: callbackUri, }); if (nonce) { queryParams.append('nonce', nonce); } try { const response = await requestDatalayerAPI({ url: `${baseUrl}${API_BASE_PATHS.IAM}/oauth2/authz/url?${queryParams.toString()}`, method: 'GET', }); return response; } catch (error) { // Check if it's a response error with status code information if (error.response) { const status = error.response.status; // Expected errors if (status === 400) { throw new Error(`Invalid OAuth2 parameters: ${error.message}`); } if (status === 404) { throw new Error(`OAuth2 provider '${provider}' not found or not configured`); } // Unexpected status codes throw new Error(`Failed to get OAuth2 authorization URL: ${status} - ${error.message}`); } // Re-throw other errors (network errors, etc.) throw error; } }; /** * Get the OAuth2 authorization URL for linking a provider to an existing account * @param provider - OAuth2 provider (bluesky, github, linkedin, okta) * @param callbackUri - Server endpoint to call with the authz token * @param baseUrl - Base URL for the API (defaults to production IAM URL) * @returns OAuth2 authorization URL response * @throws {Error} If required parameters are missing or invalid * * @remarks * This endpoint generates the OAuth2 authorization URL for linking a provider to an existing account. * Users should be redirected to the returned loginURL to begin the OAuth2 linking flow. * This is different from the regular OAuth2 login flow as it links the provider to an existing account. * * Expected status codes: * - 200: Successfully generated authorization URL * - 400: Invalid parameters * - 404: Provider not found or not configured */ export const getOAuth2AuthzUrlForLink = async (provider, callbackUri, baseUrl = DEFAULT_SERVICE_URLS.IAM) => { if (!provider) { throw new Error('OAuth2 provider is required'); } if (!callbackUri) { throw new Error('Callback URI is required'); } // Build query parameters const queryParams = new URLSearchParams({ provider, callback_uri: callbackUri, }); try { const response = await requestDatalayerAPI({ url: `${baseUrl}${API_BASE_PATHS.IAM}/oauth2/authz/url/link?${queryParams.toString()}`, method: 'GET', }); return response; } catch (error) { // Check if it's a response error with status code information if (error.response) { const status = error.response.status; // Expected errors if (status === 400) { throw new Error(`Invalid OAuth2 link parameters: ${error.message}`); } if (status === 404) { throw new Error(`OAuth2 provider '${provider}' not found or not configured for linking`); } // Unexpected status codes throw new Error(`Failed to get OAuth2 link authorization URL: ${status} - ${error.message}`); } // Re-throw other errors (network errors, etc.) throw error; } }; /** * Handle GitHub OAuth2 callback * @param params - OAuth2 callback parameters * @param baseUrl - Base URL for the API (defaults to production IAM URL) * @returns HTML response from the callback handler * @throws {Error} If state parameter is missing * @throws {Error} If the callback fails * * @remarks * This endpoint handles the callback from GitHub after the user authorizes the application. * It returns HTML content that typically includes JavaScript to handle the OAuth flow completion. * * Expected status codes: * - 200: Callback processed successfully (returns HTML) * - 403: Unauthorized */ export const handleGitHubOAuth2Callback = async (params, baseUrl = DEFAULT_SERVICE_URLS.IAM) => { if (!params.state) { throw new Error('State parameter is required for OAuth2 callback'); } // Build query parameters const queryParams = new URLSearchParams(); queryParams.append('state', params.state); if (params.code) { queryParams.append('code', params.code); } if (params.error) { queryParams.append('error', params.error); } if (params.error_description) { queryParams.append('error_description', params.error_description); } if (params.error_uri) { queryParams.append('error_uri', params.error_uri); } try { const response = await requestDatalayerAPI({ url: `${baseUrl}${API_BASE_PATHS.IAM}/oauth2/github/callback?${queryParams.toString()}`, method: 'GET', // Note: This endpoint returns HTML, not JSON headers: { Accept: 'text/html', }, }); return response; } catch (error) { // Check if it's a response error with status code information if (error.response) { const status = error.response.status; // Expected errors if (status === 403) { throw new Error(`GitHub OAuth2 callback unauthorized: ${error.message}`); } // Unexpected status codes throw new Error(`GitHub OAuth2 callback failed: ${status} - ${error.message}`); } // Re-throw other errors (network errors, etc.) throw error; } }; /** * Handle LinkedIn OAuth2 callback * @param params - OAuth2 callback parameters * @param baseUrl - Base URL for the API (defaults to production IAM URL) * @returns HTML response from the callback handler * @throws {Error} If state parameter is missing * @throws {Error} If the callback fails * * @remarks * This endpoint handles the callback from LinkedIn after the user authorizes the application. * It returns HTML content that typically includes JavaScript to handle the OAuth flow completion. * * Expected status codes: * - 200: Callback processed successfully (returns HTML) * - 403: Unauthorized */ export const handleLinkedInOAuth2Callback = async (params, baseUrl = DEFAULT_SERVICE_URLS.IAM) => { if (!params.state) { throw new Error('State parameter is required for OAuth2 callback'); } // Build query parameters const queryParams = new URLSearchParams(); queryParams.append('state', params.state); if (params.code) { queryParams.append('code', params.code); } if (params.error) { queryParams.append('error', params.error); } if (params.error_description) { queryParams.append('error_description', params.error_description); } if (params.error_uri) { queryParams.append('error_uri', params.error_uri); } try { const response = await requestDatalayerAPI({ url: `${baseUrl}${API_BASE_PATHS.IAM}/oauth2/linkedin/callback?${queryParams.toString()}`, method: 'GET', // Note: This endpoint returns HTML, not JSON headers: { Accept: 'text/html', }, }); return response; } catch (error) { // Check if it's a response error with status code information if (error.response) { const status = error.response.status; // Expected errors if (status === 403) { throw new Error(`LinkedIn OAuth2 callback unauthorized: ${error.message}`); } // Unexpected status codes throw new Error(`LinkedIn OAuth2 callback failed: ${status} - ${error.message}`); } // Re-throw other errors (network errors, etc.) throw error; } }; /** * Handle Okta OAuth2 callback * @param params - OAuth2 callback parameters * @param baseUrl - Base URL for the API (defaults to production IAM URL) * @returns HTML response from the callback handler * @throws {Error} If state parameter is missing * @throws {Error} If the callback fails * * @remarks * This endpoint handles the callback from Okta after the user authorizes the application. * It returns HTML content that typically includes JavaScript to handle the OAuth flow completion. * * Expected status codes: * - 200: Callback processed successfully (returns HTML) * - 403: Unauthorized */ export const handleOktaOAuth2Callback = async (params, baseUrl = DEFAULT_SERVICE_URLS.IAM) => { if (!params.state) { throw new Error('State parameter is required for OAuth2 callback'); } // Build query parameters const queryParams = new URLSearchParams(); queryParams.append('state', params.state); if (params.code) { queryParams.append('code', params.code); } if (params.error) { queryParams.append('error', params.error); } if (params.error_description) { queryParams.append('error_description', params.error_description); } if (params.error_uri) { queryParams.append('error_uri', params.error_uri); } try { const response = await requestDatalayerAPI({ url: `${baseUrl}${API_BASE_PATHS.IAM}/oauth2/okta/callback?${queryParams.toString()}`, method: 'GET', // Note: This endpoint returns HTML, not JSON headers: { Accept: 'text/html', }, }); return response; } catch (error) { // Check if it's a response error with status code information if (error.response) { const status = error.response.status; // Expected errors if (status === 403) { throw new Error(`Okta OAuth2 callback unauthorized: ${error.message}`); } // Unexpected status codes throw new Error(`Okta OAuth2 callback failed: ${status} - ${error.message}`); } // Re-throw other errors (network errors, etc.) throw error; } };