gitlab-org--gitlab-foss/app/assets/javascripts/jira_connect/subscriptions/pkce.js

60 lines
2.1 KiB
JavaScript

import { bufferToBase64, base64ToBase64Url } from '~/authentication/webauthn/util';
import { PKCE_CODE_CHALLENGE_DIGEST_ALGORITHM } from './constants';
// PKCE codeverifier should have a maximum length of 128 characters.
// Using 96 bytes generates a string of 128 characters.
// RFC: https://datatracker.ietf.org/doc/html/rfc7636#section-4.1
export const CODE_VERIFIER_BYTES = 96;
/**
* Generate a cryptographically random string.
* @param {Number} lengthBytes
* @returns {String} a random string
*/
function getRandomString(lengthBytes) {
// generate random values and load them into byteArray.
const byteArray = new Uint8Array(lengthBytes);
window.crypto.getRandomValues(byteArray);
// Convert array to string
const randomString = bufferToBase64(byteArray);
return randomString;
}
/**
* Creates a code verifier to be used for OAuth PKCE authentication.
* The code verifier has 128 characters.
*
* RFC: https://datatracker.ietf.org/doc/html/rfc7636#section-4.1
* @returns {String} code verifier
*/
export function createCodeVerifier() {
const verifier = getRandomString(CODE_VERIFIER_BYTES);
return base64ToBase64Url(verifier);
}
/**
* Creates a code challenge for OAuth PKCE authentication.
* The code challenge is derived from the given [codeVerifier].
* [codeVerifier] is tranformed in the following way (as per the RFC):
* code_challenge = BASE64URL-ENCODE(SHA256(ASCII(codeVerifier)))
*
* RFC: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2
* @param {String} codeVerifier
* @returns {String} code challenge
*/
export async function createCodeChallenge(codeVerifier) {
// Generate SHA-256 digest of the [codeVerifier]
const buffer = new TextEncoder().encode(codeVerifier);
const digestArrayBuffer = await window.crypto.subtle.digest(
PKCE_CODE_CHALLENGE_DIGEST_ALGORITHM.long,
buffer,
);
// Convert digest to a Base64URL-encoded string
const digestHash = bufferToBase64(digestArrayBuffer);
// Escape string to remove reserved charaters
const codeChallenge = base64ToBase64Url(digestHash);
return codeChallenge;
}