UNPKG

@contentgrid/fetch-hook-authentication

Version:
1 lines 8.41 kB
{"version":3,"file":"contentgridTokenExchange.mjs","sources":["../../src/token-supplier/contentgridTokenExchange.ts"],"sourcesContent":["import { FetchHooksError } from \"@contentgrid/fetch-hooks\";\nimport { AuthenticationToken, AuthenticationTokenSupplier } from \"./types\";\nimport MimeType from \"whatwg-mimetype\";\nimport { ValueProvider, ValueProviderResolver } from \"@contentgrid/fetch-hooks/value-provider\";\n\n\ninterface TokenExchangeConfiguration {\n exchangeUrl: ValueProvider<string, [{ fetch: typeof fetch }]>;\n}\n\nfunction createTokenRequestBody(resource: string): URLSearchParams {\n const formData = new URLSearchParams();\n formData.append(\"grant_type\", \"https://contentgrid.cloud/oauth2/grant/extension-token\");\n formData.append(\"resource\", resource);\n return formData;\n}\n\n\nfunction createAuthenticationToken(responseBody: any): AuthenticationToken {\n // Verify response validity: https://datatracker.ietf.org/doc/html/rfc6749#section-5.1\n if(!(\"token_type\" in responseBody)) {\n throw new TokenExchangeProtocolViolationError(`Missing 'token_type' in response`);\n }\n if(!(\"access_token\" in responseBody)) {\n throw new TokenExchangeProtocolViolationError(`Missing 'access_token' in response`);\n }\n\n if(String(responseBody[\"token_type\"]).toLowerCase() !== \"bearer\") {\n throw new TokenExchangeProtocolViolationError(`Unsupported token type ${responseBody[\"token_type\"]}`);\n }\n\n const expiry = \"expires_in\" in responseBody ? new Date(Date.now() + responseBody[\"expires_in\"] * 1000) : null;\n\n return {\n token: responseBody[\"access_token\"],\n expiresAt: expiry\n };\n}\n\nfunction isJsonContentType(contentType: string | null): boolean {\n if(!contentType) {\n return false;\n }\n const mimetype = new MimeType(contentType);\n\n // https://mimesniff.spec.whatwg.org/#json-mime-type\n return ((mimetype.type === \"application\" || mimetype.type === \"text\") && mimetype.subtype === \"json\") || mimetype.subtype.endsWith(\"+json\");\n\n}\n\nfunction createOAuth2Error(responseBody: any): OAuth2AuthenticationError | null {\n if(!(\"error\" in responseBody)) {\n return null; // 'error' field is required in OAuth error responses: https://datatracker.ietf.org/doc/html/rfc6749#section-5.2\n }\n return new OAuth2AuthenticationError(\n responseBody[\"error\"],\n responseBody[\"error_description\"]\n );\n}\n\nexport default function createContentgridTokenExchangeTokenSupplier(config: TokenExchangeConfiguration): AuthenticationTokenSupplier {\n const exchangeUrlResolver = ValueProviderResolver.fromValueProvider(config.exchangeUrl);\n return async (uri, opts) => {\n const exchangeUrl = await exchangeUrlResolver.resolve(opts);\n const response = await opts.fetch(exchangeUrl, {\n signal: opts?.signal ?? null,\n method: \"POST\",\n body: createTokenRequestBody(uri)\n })\n\n if(response.ok) {\n if(isJsonContentType(response.headers.get(\"content-type\"))) {\n return createAuthenticationToken(await response.json());\n } else {\n throw new TokenExchangeProtocolViolationError(`Content type ${response.headers.get('content-type')} is not JSON`);\n }\n } else {\n if(isJsonContentType(response.headers.get(\"content-type\"))) {\n const oauthError = createOAuth2Error(await response.json());\n if(oauthError) {\n throw oauthError;\n }\n }\n throw new TokenExchangeProtocolViolationError(`Non-OAuth response error: ${response.status} ${response.statusText}`);\n }\n }\n\n}\n\n/**\n * Base class for token exchange errors\n */\nexport class TokenExchangeError extends FetchHooksError {\n public constructor(message: string) {\n super(`Token exchange failed: ${message}`)\n }\n}\n\n/**\n * Unexpected deviation from the expected token exchange flow\n */\nexport class TokenExchangeProtocolViolationError extends TokenExchangeError {\n public constructor(message: string) {\n super(`Protocol violation: ${message}`)\n }\n}\n\n/**\n * A potentially-expected OAuth error response\n */\nexport class OAuth2AuthenticationError extends TokenExchangeError {\n public constructor(\n public readonly code: string,\n public readonly description: string,\n ) {\n super(`OAuth2 error ${code}: ${description}`)\n }\n\n}\n"],"names":["createTokenRequestBody","resource","formData","URLSearchParams","append","createAuthenticationToken","responseBody","TokenExchangeProtocolViolationError","String","toLowerCase","expiry","Date","now","token","expiresAt","isJsonContentType","contentType","mimetype","MimeType","type","subtype","endsWith","createOAuth2Error","OAuth2AuthenticationError","createContentgridTokenExchangeTokenSupplier","config","exchangeUrlResolver","ValueProviderResolver","fromValueProvider","exchangeUrl","uri","opts","resolve","response","fetch","signal","_a","method","body","ok","headers","get","json","oauthError","status","statusText","TokenExchangeError","FetchHooksError","constructor","message","code","description"],"mappings":"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"}