Skip to content

Conversation

@threeal
Copy link

@threeal threeal commented Sep 10, 2025

By submitting a PR to this repository, you agree to the terms within the Auth0 Code of Conduct. Please see the contributing guidelines for how to create and submit a high-quality PR for this repo.

Description

Use Uint8Array.fromBase64 if available in b64DecodeUnicode function.

References

Resolves #395.

Testing

Test not viable for now because Uint8Array.fromBase64 is not available in Node.js

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation for new/changed functionality in this PR or in auth0.com/docs
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not the default branch

@threeal threeal requested a review from a team as a code owner September 10, 2025 07:33
Copy link
Contributor

@jonkoops jonkoops left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new code path should also be covered by the existing tests, since Jest is used to fake browser testing I don't think the test suite is currently actually hitting the Uint8Array.fromBase64() in any scenario.

lib/index.ts Outdated
Comment on lines 26 to 30
if (
typeof Uint8Array !== "undefined" &&
"fromBase64" in Uint8Array &&
typeof Uint8Array.fromBase64 === "function"
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no need to feature detect Uint8Array itself, as it is widely supported. Additionally, the type of the method is already known, so there should be no need to make any assertions about its type, checking for its presence should be sufficient:

Suggested change
if (
typeof Uint8Array !== "undefined" &&
"fromBase64" in Uint8Array &&
typeof Uint8Array.fromBase64 === "function"
) {
if (Uint8Array.fromBase64) {

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type check and casting is needed because ESLint complains about it, maybe it's also because currently Uint8Array.fromBase64 is not supported yet in Node.js.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this could be fixed by updating the TypeScript version. Currently, the proposal is Stage 3, but I believe that TypeScript only adds features that are Stage 4. Still, if the error is caused by TypeScript, perhaps it would be better to cast the type of Uint8Array.fromBase64 there, rather than using runtime checks?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is still missing from the latest TypeScript, see microsoft/TypeScript#61695

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did some testing, and we could accomplish this by creating lib/types.d.ts:

declare global {
  interface FromBase64Options {
    alphabet?: "base64" | "base64url";
    lastChunkHandling?: "loose" | "strict" | "stop-before-partial";
  }

  interface Uint8ArrayConstructor {
    fromBase64?(base64: string, options?: FromBase64Options): Uint8Array;
  }
}

export {}; // Ensure this is treated as a module

This can then be included in lib/index.ts by adding the following on the top of the file:

/// <reference types="./types.d.ts" />

Which then allows the code to be simplified to:

if (Uint8Array.fromBase64) {
  const bytes = Uint8Array.fromBase64(str, { alphabet: "base64url" });
  return new TextDecoder().decode(bytes);
}

Note that I have made fromBase64() optional in the type definition, which reflects the fact that we consider it something that is not supported in all environments (yet). In order to prevent the reference comment from showing up in the compiled result, we also have to update tsconfig.build.json to strip them out:

{
  "compilerOptions": {
    "removeComments": true
  }
}

lib/index.ts Outdated
"fromBase64" in Uint8Array &&
typeof Uint8Array.fromBase64 === "function"
) {
// Use native Uint8Array.fromBase64 if available
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no comments in this entire file, and this code is pretty self-explanatory, this can likely be removed.

Suggested change
// Use native Uint8Array.fromBase64 if available

lib/index.ts Outdated
typeof Uint8Array.fromBase64 === "function"
) {
// Use native Uint8Array.fromBase64 if available
const bytes = Uint8Array.fromBase64(str) as Uint8Array;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this matches the intended behavior, or if any other options need to be passed to match the existing behavior.

Copy link
Contributor

@jonkoops jonkoops Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upon closer inspection, perhaps we can do an even earlier exit by doing the decode in base64UrlDecode()?

function base64UrlDecode(str: string) {
  const bytes = Uint8Array.fromBase64(str, { alphabet: "base64url" });
  return new TextDecoder().decode(bytes);
}

@threeal threeal force-pushed the use-native-base64-api branch from 2210fa6 to 8ce1d78 Compare September 11, 2025 03:09
@threeal
Copy link
Author

threeal commented Sep 11, 2025

@jonkoops I can't add test because Uint8Array.fromBase64 is not supported yet by Node.js (see nodejs/node#59285), unless we wanted to mock it?

@jonkoops
Copy link
Contributor

Yes, we need to find a way to run the tests in an environment where this API is supported. Perhaps it's time to reconsider Vitest (see #198), that would allow running the tests in actual browsers, all the major browsers have support for this API.

@frederikprijck WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use native Base64 APIs for decoding when available

2 participants