wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
 
import {
    IPerformanceClient,
    Logger,
    PkceCodes,
    invoke,
    invokeAsync,
} from "@azure/msal-common/browser";
import * as BrowserPerformanceEvents from "../telemetry/BrowserPerformanceEvents.js";
import {
    createBrowserAuthError,
    BrowserAuthErrorCodes,
} from "../error/BrowserAuthError.js";
import { urlEncodeArr } from "../encode/Base64Encode.js";
import { getRandomValues, sha256Digest } from "./BrowserCrypto.js";
 
// Constant byte array length
const RANDOM_BYTE_ARR_LENGTH = 32;
 
/**
 * This file defines APIs to generate PKCE codes and code verifiers.
 */
 
/**
 * Generates PKCE Codes. See the RFC for more information: https://tools.ietf.org/html/rfc7636
 */
export async function generatePkceCodes(
    performanceClient: IPerformanceClient,
    logger: Logger,
    correlationId: string
): Promise<PkceCodes> {
    const codeVerifier = invoke(
        generateCodeVerifier,
        BrowserPerformanceEvents.GenerateCodeVerifier,
        logger,
        performanceClient,
        correlationId
    )(performanceClient, logger, correlationId);
    const codeChallenge = await invokeAsync(
        generateCodeChallengeFromVerifier,
        BrowserPerformanceEvents.GenerateCodeChallengeFromVerifier,
        logger,
        performanceClient,
        correlationId
    )(codeVerifier, performanceClient, logger, correlationId);
    return {
        verifier: codeVerifier,
        challenge: codeChallenge,
    };
}
 
/**
 * Generates a random 32 byte buffer and returns the base64
 * encoded string to be used as a PKCE Code Verifier
 */
function generateCodeVerifier(
    performanceClient: IPerformanceClient,
    logger: Logger,
    correlationId: string
): string {
    try {
        // Generate random values as utf-8
        const buffer: Uint8Array = new Uint8Array(RANDOM_BYTE_ARR_LENGTH);
        invoke(
            getRandomValues,
            BrowserPerformanceEvents.GetRandomValues,
            logger,
            performanceClient,
            correlationId
        )(buffer);
        // encode verifier as base64
        const pkceCodeVerifierB64: string = urlEncodeArr(buffer);
        return pkceCodeVerifierB64;
    } catch (e) {
        throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);
    }
}
 
/**
 * Creates a base64 encoded PKCE Code Challenge string from the
 * hash created from the PKCE Code Verifier supplied
 */
async function generateCodeChallengeFromVerifier(
    pkceCodeVerifier: string,
    performanceClient: IPerformanceClient,
    logger: Logger,
    correlationId: string
): Promise<string> {
    try {
        // hashed verifier
        const pkceHashedCodeVerifier = await invokeAsync(
            sha256Digest,
            BrowserPerformanceEvents.Sha256Digest,
            logger,
            performanceClient,
            correlationId
        )(pkceCodeVerifier);
        // encode hash as base64
        return urlEncodeArr(new Uint8Array(pkceHashedCodeVerifier));
    } catch (e) {
        throw createBrowserAuthError(BrowserAuthErrorCodes.pkceNotCreated);
    }
}