Skip to content

Conversation

@pesickaa
Copy link
Contributor

@pesickaa pesickaa commented Nov 25, 2025

update base64UrlEncode and generatePKCEPair functions to work with state having specific characters like =.

The base64UrlEncode method was clearly updated to handle specific use cases which were based off the generatePKCEPair function, where we strip out specific characters for the PKCE Pair. This was fine until we realized that when a user provides state
like in the React auth issue 203, it causes the call on lines 379 of the react KindeProvider.tsx to fail.

VERIFY ISSUE SETUP:

  1. Have your React Auth SDK setup
  2. Set your state in your playground/LoggedOut.tsx to have somethinglike the following:
  • {"user_type":"client","redirect_uri":"http://localhost:7001/?user_type=client","utm":"{}"}
  1. Attempt to login. It should take you through selecting your email, your org, whatever, and then on the final step it will fail and the url on redirect will have all the code and state information, but it won't properly set your tokens.

FIX SETUP

  1. Have your React Auth SDK setup
  2. Update version of js-utils to the version in this PR (I used Verdaccio to make a local package).
  3. Set your state in your playground/LoggedOut.tsx to have somethinglike the following:
  • {"user_type":"client","redirect_uri":"http://localhost:7001/?user_type=client","utm":"{}"}
  1. Attempt login again and it should work properly.

CHANGES:

  • Update the base64UrlEncode to not strip out the characters it was previously stripping out.
  • Update the GeneratePKCEPair to strip those characters itself.
  • Update affected tests
  • Add new tests to verify how the GeneratePKCEPair functions

Explain your changes

Suppose there is a related issue with enough detail for a reviewer to understand your changes fully. In that case, you can omit an explanation and instead include either “Fixes #XX” or “Updates #XX” where “XX” is the issue number.

Checklist

🛟 If you need help, consider asking for advice over in the Kinde community.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 25, 2025

Walkthrough

Changes update base64 encoding to produce standard base64 with padding, expose generatePKCEPair() as public API, and add comprehensive PKCE tests for both crypto-available and crypto-unavailable environments.

Changes

Cohort / File(s) Summary
Base64 Encoding Implementation
lib/utils/base64UrlEncode.ts
Modifies encoding logic to produce standard base64 with padding instead of URL-safe base64; removes character replacements (+/-, /_) and padding removal from the encoding function
Base64 Encoding Tests
lib/utils/base64UrlEncode.test.ts, lib/tests/expoLazyLoading.test.ts
Updates test assertions to expect base64 strings with padding (e.g., "dGVzdA==" instead of "dGVzdA") across multiple test cases
PKCE Implementation
lib/utils/generateAuthUrl.ts
Modifies code challenge computation in non-crypto environments to normalize codeChallenge to URL-safe base64 (replacing +/- and /_, removing padding) within the function; adds generatePKCEPair() export
PKCE Tests
lib/utils/generateAuthUrl.test.ts, lib/utils/generateAuthUrl-nocrypto.test.ts
Adds new test suites for generatePKCEPair() validating codeVerifier length, URL-safe codeChallenge format, randomization, character sets, and behavior in crypto-available and crypto-unavailable environments; imports base64UrlEncode and generatePKCEPair as public exports

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • base64UrlEncode behavior shift: Verify that changing from URL-safe to standard base64 with padding doesn't break downstream consumers relying on the previous encoding format
  • PKCE normalization logic: Confirm that URL-safe normalization applied within generateAuthUrl.ts correctly handles code challenge in both crypto and no-crypto paths
  • Test coverage alignment: Ensure test expectations in expoLazyLoading.test.ts align with actual encoding behavior across all PKCE code paths
  • Export surface area: Review new public exports (generatePKCEPair, base64UrlEncode) for API stability and documentation

Possibly related issues

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main fix: base64UrlEncode handling specific characters like '=' that were causing issues.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the issue, root cause, fix approach, and verification steps.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/update-base64UrlEncode-and-generatePKCEPair-functions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Nov 25, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pesickaa pesickaa changed the title feat: update base64UrlEncode and generatePKCEPair functions to work w… fix: base64UrlEncode not working properly with specific characters Dec 2, 2025
@pesickaa pesickaa marked this pull request as ready for review December 2, 2025 11:09
@pesickaa pesickaa requested a review from a team as a code owner December 2, 2025 11:09
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/utils/generateAuthUrl.ts (1)

158-177: Align crypto detection in generatePKCEPair with test robustness checks

The production code at line 165 uses a bare if (!crypto) check, but the test at line 497–502 demonstrates a much more thorough capability check: typeof crypto !== "undefined" && crypto && crypto.subtle && typeof crypto.subtle.digest === "function".

If crypto exists but crypto.subtle is undefined or digest is not a function, line 168's call to crypto.subtle.digest("SHA-256", data) will throw a runtime error instead of falling back to the non-crypto path. The test suite even includes a try-catch around crypto.subtle.digest() (lines 509–514) to verify the capability actually works.

To make the production code match the availability checks demonstrated in the tests, consider using a safety check before calling crypto.subtle.digest:

 export async function generatePKCEPair(): Promise<{
   codeVerifier: string;
   codeChallenge: string;
 }> {
   const codeVerifier = generateRandomString(52);
   const data = new TextEncoder().encode(codeVerifier);
   let codeChallenge = "";
-  if (!crypto) {
+  const hasWebCrypto =
+    typeof crypto !== "undefined" &&
+    crypto &&
+    crypto.subtle &&
+    typeof crypto.subtle.digest === "function";
+
+  if (!hasWebCrypto) {
     codeChallenge = base64UrlEncode(codeVerifier);
   } else {
     const hashed = await crypto.subtle.digest("SHA-256", data);
     codeChallenge = base64UrlEncode(hashed);
   }

This brings the production code in line with the robustness your tests expect.

🧹 Nitpick comments (3)
lib/utils/base64UrlEncode.ts (1)

1-23: Behavior change to standard base64 is consistent but naming is now misleading

The implementation now cleanly returns standard padded base64 for both string and ArrayBuffer inputs and does so in a robust way (improved ArrayBuffer detection, explicit TextEncoder path). This matches the updated tests and the new PKCE flow, where URL‑safety and padding stripping are handled by the caller.

The only minor concern is that the function name base64UrlEncode no longer reflects its behavior (it no longer produces URL‑safe base64). That’s fine for this PR but worth calling out in release notes and/or external docs so consumers aren’t surprised by the change in semantics.

lib/utils/generateAuthUrl-nocrypto.test.ts (1)

1-12: No‑crypto PKCE tests accurately capture the intended fallback behavior

The new generatePKCEPair - no crypto suite does a good job locking in the non‑crypto behavior:

  • Verifies verifier length and URL‑safe challenge (no +, /, or trailing =).
  • Confirms the challenge matches base64UrlEncode(codeVerifier) with the same normalization you use in production.
  • Checks shape, character set, and randomness across calls.

The global crypto stubbing (both vi.stubGlobal("crypto", undefined) and the Object.defineProperty) is slightly redundant but functionally fine given this is a dedicated “no crypto” test file.

Also applies to: 52-105

lib/utils/generateAuthUrl.test.ts (1)

3-7: PKCE tests are thorough and correctly express expected behavior

The new generatePKCEPair tests are comprehensive:

  • They validate verifier length, URL‑safe challenge constraints, randomness, and result shape.
  • The “crypto availability” test sensibly distinguishes between “Web Crypto present and working” vs. fallback, using a robust capability check and cross‑checking against a direct base64UrlEncode(codeVerifier) path.

These tests nicely document the intended contract for generatePKCEPair and will help guard future changes. Note that the implementation’s current if (!crypto) check is less strict than the hasWebCrypto logic you use here; aligning the implementation with this capability check (as suggested in the implementation comment) would make behavior and tests fully consistent.

Also applies to: 459-554

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 193a8c7 and dd39e8c.

📒 Files selected for processing (6)
  • lib/tests/expoLazyLoading.test.ts (2 hunks)
  • lib/utils/base64UrlEncode.test.ts (3 hunks)
  • lib/utils/base64UrlEncode.ts (1 hunks)
  • lib/utils/generateAuthUrl-nocrypto.test.ts (2 hunks)
  • lib/utils/generateAuthUrl.test.ts (2 hunks)
  • lib/utils/generateAuthUrl.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 128
File: lib/utils/generateProfileUrl.ts:30-35
Timestamp: 2025-05-28T10:56:50.579Z
Learning: In the Kinde js-utils codebase, if the storage system returns non-string values for access tokens, it indicates wider systemic issues. The team prefers to keep simple type casting in generateProfileUrl rather than adding defensive type checking, as the root cause would need to be addressed elsewhere.
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.test.ts:104-104
Timestamp: 2024-10-25T23:53:26.124Z
Learning: In `lib/utils/generateAuthUrl.test.ts`, the code is test code and may not require strict adherence to PKCE specifications.
📚 Learning: 2024-10-25T23:53:26.124Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.test.ts:104-104
Timestamp: 2024-10-25T23:53:26.124Z
Learning: In `lib/utils/generateAuthUrl.test.ts`, the code is test code and may not require strict adherence to PKCE specifications.

Applied to files:

  • lib/utils/base64UrlEncode.test.ts
  • lib/tests/expoLazyLoading.test.ts
  • lib/utils/generateAuthUrl.ts
  • lib/utils/generateAuthUrl.test.ts
  • lib/utils/generateAuthUrl-nocrypto.test.ts
📚 Learning: 2024-11-19T20:31:59.197Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/index.test.ts:59-62
Timestamp: 2024-11-19T20:31:59.197Z
Learning: In `lib/utils/token/index.test.ts`, the test "getInsecureStorage returns active storage when no insecure storage is set" is intentional. It verifies that when insecure storage is not set, `getInsecureStorage()` returns the active storage as a fallback, preferring secure storage but allowing for insecure storage when needed by consumers of the library.

Applied to files:

  • lib/tests/expoLazyLoading.test.ts
  • lib/utils/generateAuthUrl-nocrypto.test.ts
📚 Learning: 2024-10-08T23:57:58.113Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 12
File: lib/main.ts:0-0
Timestamp: 2024-10-08T23:57:58.113Z
Learning: When exporting modules in `lib/main.ts`, ensure that paths to modules like `./utils/token` are explicitly set to include `index.ts` (e.g., `./utils/token/index.ts`) to prevent missing export issues.

Applied to files:

  • lib/tests/expoLazyLoading.test.ts
  • lib/utils/generateAuthUrl.test.ts
📚 Learning: 2025-01-16T21:47:40.307Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.

Applied to files:

  • lib/utils/generateAuthUrl.ts
  • lib/utils/generateAuthUrl-nocrypto.test.ts
📚 Learning: 2024-10-25T23:50:56.599Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.ts:27-30
Timestamp: 2024-10-25T23:50:56.599Z
Learning: In `lib/utils/generateAuthUrl.ts`, `StorageKeys` is imported from `../main` and includes the `state` key.

Applied to files:

  • lib/utils/generateAuthUrl.ts
  • lib/utils/generateAuthUrl.test.ts
  • lib/utils/generateAuthUrl-nocrypto.test.ts
📚 Learning: 2024-10-08T23:57:58.113Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 8
File: lib/utils/token/testUtils/index.ts:3-39
Timestamp: 2024-10-08T23:57:58.113Z
Learning: The file `lib/utils/token/testUtils/index.ts` is a test utility, not production code.

Applied to files:

  • lib/utils/generateAuthUrl.test.ts
  • lib/utils/generateAuthUrl-nocrypto.test.ts
📚 Learning: 2025-05-28T10:56:50.579Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 128
File: lib/utils/generateProfileUrl.ts:30-35
Timestamp: 2025-05-28T10:56:50.579Z
Learning: In the Kinde js-utils codebase, if the storage system returns non-string values for access tokens, it indicates wider systemic issues. The team prefers to keep simple type casting in generateProfileUrl rather than adding defensive type checking, as the root cause would need to be addressed elsewhere.

Applied to files:

  • lib/utils/generateAuthUrl.test.ts
  • lib/utils/generateAuthUrl-nocrypto.test.ts
📚 Learning: 2024-11-10T23:29:36.293Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/exchangeAuthCode.ts:51-51
Timestamp: 2024-11-10T23:29:36.293Z
Learning: In `lib/utils/exchangeAuthCode.ts`, the `exchangeAuthCode` function intentionally uses `getInsecureStorage()` to store temporary authentication flow values locally between sessions. This is necessary for storing data needed for the return trip. The `getInsecureStorage()` function returns the secure storage if no active insecure storage is defined.

Applied to files:

  • lib/utils/generateAuthUrl-nocrypto.test.ts
🧬 Code graph analysis (3)
lib/utils/generateAuthUrl.ts (3)
lib/utils/base64UrlEncode.ts (1)
  • base64UrlEncode (6-24)
lib/main.ts (1)
  • base64UrlEncode (6-6)
lib/utils/index.ts (1)
  • base64UrlEncode (1-1)
lib/utils/generateAuthUrl.test.ts (2)
lib/utils/generateAuthUrl.ts (1)
  • generatePKCEPair (158-178)
lib/utils/base64UrlEncode.ts (1)
  • base64UrlEncode (6-24)
lib/utils/generateAuthUrl-nocrypto.test.ts (2)
lib/utils/generateAuthUrl.ts (1)
  • generatePKCEPair (158-178)
lib/utils/base64UrlEncode.ts (1)
  • base64UrlEncode (6-24)
🔇 Additional comments (2)
lib/tests/expoLazyLoading.test.ts (1)

190-211: Updated expectations correctly match new padded base64 behavior

The new expectations for base64UrlEncode("test")"dGVzdA==" align with the updated implementation and still validate the tree‑shaking behavior as intended.

lib/utils/base64UrlEncode.test.ts (1)

5-8: Tests correctly reflect standard padded base64 output

The updated expectations for padded base64 (including =) are correct for the provided inputs and match the new base64UrlEncode semantics for both strings and ArrayBuffers.

Also applies to: 26-29, 33-36, 40-50

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.

2 participants