@authlink/client
Version:
Official client SDK for integrating with the Authlink Identity Provider
128 lines (127 loc) • 4.23 kB
JavaScript
/**
* Creates a code verifier.
* @returns The code verifier string.
* */
export function createCodeVerifier() {
return generateRandomString(64);
}
/**
* Creates a code challenge from the given code verifier.
* */
export async function createCodeChallenge(codeVerifier, method) {
if (method == "plain")
return codeVerifier;
let hashed = await sha256(codeVerifier);
return base64UrlEncode(hashed);
}
/**
* Computes the SHA-256 hash of the given string.
* @param plain The string to hash.
* @returns A promise that resolves to the hash.
*/
async function sha256(plain) {
const encoder = new TextEncoder();
const data = encoder.encode(plain);
return await crypto.subtle.digest("SHA-256", data);
}
/**
* Encodes an ArrayBuffer to a base64 URL encoded string.
* @param arrayBuffer The ArrayBuffer to encode.
* @returns The base64 URL encoded string.
*/
function base64UrlEncode(arrayBuffer) {
const bytes = new Uint8Array(arrayBuffer);
let str = String.fromCharCode(...bytes);
return btoa(str)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
/**
* Generate a random string of the specified length using the Web Crypto API.
* @param length The length of the string to generate.
* @returns A random string in hexadecimal format.
* */
export function generateRandomString(length) {
const array = new Uint8Array(length);
window.crypto.getRandomValues(array);
return Array
.from(array, byte => ('0' + byte.toString(16)).slice(-2))
.join('');
}
/**
* Creates a silent iframe to load a URL without user interaction.
* @param url The URL to load in the iframe.
* @return The created iframe element.
* */
export function createSilentIframe(url) {
const iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.src = url;
document.body.appendChild(iframe);
return iframe;
}
/**
* Listens for a web message with the specified state and origin.
* @param state The expected state of the authorization response.
* @param expectedOrigin The expected origin of the message.
* @returns A promise that resolves with the authorization response data.
*/
export function listenForWebMessage(state, expectedOrigin) {
return new Promise((resolve, _) => {
function handler(event) {
if (event.origin !== expectedOrigin)
return;
const { data } = event;
if (data.type !== "authorization_response" || data.state !== state)
return;
window.removeEventListener("message", handler);
resolve(event.data);
}
window.addEventListener("message", handler);
});
}
/**
* Maps the JSON response from the token endpoint to a TokenResponse object.
* @param json The JSON response from the token endpoint.
* @return A TokenResponse object containing the token information.
* */
export function mapTokenResponse(json) {
return {
tokenType: json.token_type,
accessToken: json.access_token,
expiresIn: json.expires_in,
refreshToken: json.refresh_token,
idToken: json.id_token,
scope: json.scope,
issuedTokenType: json.issued_token_type
};
}
/**
* Maps the JSON response from the authorization endpoint to an AuthorizeResponse object.
* @param json The JSON response from the authorization endpoint.
* @return An AuthorizeResponse object containing the authorization information.
* */
export function mapAuthorizeResponse(json) {
return {
type: json.type,
state: json.state,
code: json.code,
idToken: json.id_token,
accessToken: json.access_token,
expiresIn: json.expires_in,
error: json.error,
errorDescription: json.error_description
};
}
/**
* Maps the JSON response from the OpenID configuration endpoint to an OpenIdConfiguration object.
* @param json The JSON response from the OpenID configuration endpoint.
* @return An OpenIdConfiguration object containing the issuer and JWKS URI.
* */
export function mapOpenIdConfiguration(json) {
return {
issuer: json.issuer,
jwksUri: json.jwks_uri
};
}