Skip to content

Conversation

@tamalchowdhury
Copy link
Collaborator

@tamalchowdhury tamalchowdhury commented Dec 8, 2025

Description (required)

This PR creates a new e2e testing section with Kinde

A total of 6 docs make up this new section with option to expand based on testing tools (Cypress, Playwright)

  • Overview
  • Test user and env creation
  • Backend API testing with Jest
  • Testing auth flows
  • Testing passwordless auth flows
  • Testing auth features with playwright

Sits under SDK and APIs

image

Related issues & labels (optional)

  • Closes #
  • Suggested label:

Summary by CodeRabbit

  • Documentation
    • Added a new Testing section with comprehensive guides: backend API testing using long-running refresh tokens, Playwright and browser-based auth flow testing, authenticated feature testing, and passwordless (email OTP) testing. Includes setup for test users/environments, example test workflows, CI guidance, troubleshooting, security and credential-rotation best practices, and reliability recommendations.
  • Navigation
    • Updated site navigation to surface the new Testing section.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Adds a new "Testing" docs section with six guides covering backend API testing with refresh tokens, test user/environment setup, Playwright authenticated feature testing, authentication flow automation, and passwordless OTP strategies; and updates the sidebar to include the new testing docs.

Changes

Cohort / File(s) Summary
Testing documentation
src/content/docs/developer-tools/testing/index.mdx, src/content/docs/developer-tools/testing/backend-api-testing.mdx, src/content/docs/developer-tools/testing/setup-test-user-environment.mdx, src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx, src/content/docs/developer-tools/testing/testing-authentication-flows.mdx, src/content/docs/developer-tools/testing/testing-passwordless-flows.mdx
Added six MDX pages with front matter and comprehensive tutorials: backend API testing using refresh tokens and Jest global-setup, Playwright authenticated-state and API strategies, passwordless OTP testing approaches (Mailosaur, mail pipelines, IMAP), test user/environment setup, CI examples, code snippets, and best practices. Review code samples, environment variable usage, token/OTP handling, and security notes.
Navigation configuration
src/data/sidebarData.ts
Added a "Testing" entry under the "SDKs and APIs" sidebar group with autogenerate: "developer-tools/testing" to surface the new docs.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through pages, soft and spry,

Tokens twirled beneath the sky,
Playwright pranced, Jest tapped the drum,
OTPs fetched—now tests will run,
A rabbit cheers: the checks — hooray!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: new section - end to end testing with Kinde' clearly and concisely summarizes the main change—adding a comprehensive new end-to-end testing documentation section. It accurately reflects the primary objective without unnecessary details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 8, 2025

Deploying kinde-docs-preview with  Cloudflare Pages  Cloudflare Pages

Latest commit: 028d84b
Status: ✅  Deploy successful!
Preview URL: https://b06baa92.kinde-docs-preview.pages.dev
Branch Preview URL: https://tamal-feat-end-to-end-testin.kinde-docs-preview.pages.dev

View logs

@tamalchowdhury tamalchowdhury changed the title WIP: end to end testing section feat: new section - end to end testing with Kinde Jan 5, 2026
@tamalchowdhury tamalchowdhury marked this pull request as ready for review January 5, 2026 10:18
@tamalchowdhury tamalchowdhury requested a review from a team as a code owner January 5, 2026 10:18
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: 4

Fix all issues with AI Agents 🤖
In @src/content/docs/developer-tools/testing/setup-test-user-environment.mdx:
- Line 93: Replace the incorrect verb form "setup" in the sentence "Verify the
email address and setup a strong password" with the two-word verb "set up" so
the line reads "Verify the email address and set up a strong password"; locate
this exact phrase in
src/content/docs/developer-tools/testing/setup-test-user-environment.mdx (look
for the sentence beginning with "Verify the email address") and update it
accordingly.
- Around line 52-53: The sentence "Sign in to your Kinde dashboard, select
**Production** arrow, a pop-up appears - Select **All environments**" contains a
comma splice; rewrite it as two or more clear clauses—for example, "Sign in to
your Kinde dashboard and click the **Production** arrow. When the pop-up
appears, select **All environments**." Update the text in
src/content/docs/developer-tools/testing/setup-test-user-environment.mdx to
replace the original line with a version that removes the comma splice and
improves flow.
- Around line 75-77: The ordered list in setup-test-user-environment.mdx has
duplicate "3." entries; update the second "3." (the line "Select **Save**") to
"4." and renumber all following steps incrementally so the sequence progresses
correctly (e.g., change the "4." that follows to "5.", etc.) to restore proper
step ordering.

In @src/content/docs/developer-tools/testing/testing-authentication-flows.mdx:
- Around line 426-537: The example uses Playwright's page.fill() which is
incompatible with AWS Synthetic Canaries' Puppeteer Page; update the handler's
flowStep usages to call Puppeteer's page.type() instead of page.fill() wherever
you populate inputs (e.g., the fields in exports.handler:
'input[name="p_first_name"]', 'input[name="p_last_name"]',
'input[name="p_email"]' in the sign-up flow, the commented OTP step
'input[name="p_confirmation_code"]', the password creation fields
'input[name="p_first_password"]' and 'input[name="p_second_password"]', and the
sign-in fields 'input[name="p_email"]' and 'input[name="p_password"]'). Ensure
all page.fill(...) calls in the handler are replaced with page.type(...) so the
script uses Puppeteer-compatible APIs.
🧹 Nitpick comments (2)
src/content/docs/developer-tools/testing/index.mdx (1)

54-54: Consider clarifying MFA testing capabilities.

The statement "may require manual intervention" is somewhat vague. Consider specifying what MFA testing is possible (e.g., testing with backup codes, testing the MFA setup flow) versus what requires manual intervention (e.g., actual authenticator app interaction).

src/content/docs/developer-tools/testing/setup-test-user-environment.mdx (1)

56-56: Provide example for both environment name and code.

The instruction mentions entering both "environment name and code" but only provides an example for the name. Consider adding an example code value (e.g., "TEST" or "test") to help users understand the expected format for both fields.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 445ab36 and f125c7d.

📒 Files selected for processing (7)
  • src/content/docs/developer-tools/testing/backend-api-testing.mdx
  • src/content/docs/developer-tools/testing/index.mdx
  • src/content/docs/developer-tools/testing/setup-test-user-environment.mdx
  • src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx
  • src/content/docs/developer-tools/testing/testing-authentication-flows.mdx
  • src/content/docs/developer-tools/testing/testing-passwordless-flows.mdx
  • src/data/sidebarData.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-27T18:42:29.479Z
Learnt from: victoreronmosele
Repo: kinde-oss/documentation PR: 647
File: src/content/docs/developer-tools/sdks/native/ios-sdk.mdx:278-297
Timestamp: 2025-12-27T18:42:29.479Z
Learning: In MDX documentation files (e.g., any API reference docs), when documenting parameters (like loginHint, connectionId), prefer listing them in the API reference Arguments section and link to detailed documentation pages instead of duplicating descriptions, format specs, or validation rules inline. This follows the 'document once, reference anywhere' principle.

Applied to files:

  • src/content/docs/developer-tools/testing/backend-api-testing.mdx
  • src/content/docs/developer-tools/testing/testing-passwordless-flows.mdx
  • src/content/docs/developer-tools/testing/testing-authentication-flows.mdx
  • src/content/docs/developer-tools/testing/index.mdx
  • src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx
  • src/content/docs/developer-tools/testing/setup-test-user-environment.mdx
🪛 LanguageTool
src/content/docs/developer-tools/testing/backend-api-testing.mdx

[grammar] ~88-~88: Ensure spelling is correct
Context: ...the placeholder values with your actual Kinde credentials from Step 1. <Aside ty...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

src/content/docs/developer-tools/testing/testing-passwordless-flows.mdx

[grammar] ~380-~380: Use a hyphen to join words.
Context: ...n-in flow To test the passwordless sign in flow: 1. Enable the Email + code...

(QB_NEW_EN_HYPHEN)

src/content/docs/developer-tools/testing/testing-authentication-flows.mdx

[grammar] ~60-~60: Ensure spelling is correct
Context: ...management | ## Testing sign-up flows Kinde requires OTP email verification when si...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~66-~66: Use a hyphen to join words.
Context: ... email testing service to test user sign up 3. Verify redirect: Check that us...

(QB_NEW_EN_HYPHEN)


[grammar] ~228-~228: Use a hyphen to join words.
Context: ...-a8b7236e3300/public) ### Example: Sign up flow with Playwright Check out the f...

(QB_NEW_EN_HYPHEN)


[grammar] ~385-~385: Use a hyphen to join words.
Context: ...-16576792a600/public) ### Example: Sign up flow with Cypress ```ts // spec.cy.t...

(QB_NEW_EN_HYPHEN)

src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx

[style] ~37-~37: Try moving the adverb to make the sentence clearer.
Context: ...ling passwordless flows. --- Learn how to efficiently test authenticated features in applications using Kinde authenticat...

(SPLIT_INFINITIVE)


[grammar] ~438-~438: Ensure spelling is correct
Context: ...ecrets with the new refresh token. ### Kinde form selectors changed Kinde may updat...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (13)
src/content/docs/developer-tools/testing/backend-api-testing.mdx (2)

104-142: LGTM! Token refresh implementation is well-structured.

The token refresh logic properly handles errors and falls back to existing tokens if refresh fails, which ensures tests can still run with cached credentials. Good use of environment variables and clear error messages.


223-249: LGTM! Excellent security guidance and limitations.

The documentation properly covers token rotation behavior, secure storage requirements, and testing limitations. The best practices section provides actionable security recommendations.

src/content/docs/developer-tools/testing/testing-authentication-flows.mdx (3)

48-58: LGTM! Helpful tool comparison.

The comparison table provides clear pros/cons for different browser automation tools, helping developers choose the right approach for their needs.


174-218: LGTM! Playwright test examples are correct.

The test examples properly use Playwright's API, handle redirects with URL expectations, and verify authentication state. Good use of test-id attributes for reliable selectors.


330-375: LGTM! Cypress examples properly handle cross-origin flows.

The test examples correctly use cy.origin() to handle Kinde's authentication on a different domain, which is essential for Cypress testing. Good use of environment variables for configuration.

src/content/docs/developer-tools/testing/testing-passwordless-flows.mdx (2)

49-263: LGTM! Comprehensive OTP testing approaches.

The documentation covers multiple practical approaches for capturing OTP codes (Mailosaur, Mailtrap, AWS S3, database, IMAP), with correct API usage and proper error handling. The regex pattern for extracting 6-digit codes is reliable.


317-519: LGTM! Well-structured Playwright + Mailosaur integration.

The test examples demonstrate proper integration between Playwright and Mailosaur for OTP extraction. Good practices include unique email generation, cleanup steps, and storage state persistence.

src/data/sidebarData.ts (1)

70-74: LGTM! Sidebar entry correctly configured.

The new Testing section is properly added under "SDKs and APIs" with the correct directory path and sensible defaults. The collapsed: false setting ensures the new documentation is immediately visible to users.

src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx (4)

83-180: LGTM! Excellent authentication state reuse pattern.

The implementation correctly uses Playwright's storage state feature to authenticate once and reuse across tests. The setup/dependency pattern is properly configured, and the auth verification step ensures state is saved only after successful login.


206-298: LGTM! Solid API testing implementation with token refresh.

The token refresh setup properly persists tokens to a file and the API tests correctly read and use them. Good use of Playwright's request fixture for API testing, and the console log reminder about updating the refresh token is helpful.


365-408: LGTM! Well-structured CI/CD integration.

The GitHub Actions workflow properly installs dependencies, Playwright browsers, and runs tests with secrets injected from repository settings. Good inclusion of artifact upload for test reports.


410-454: LGTM! Comprehensive troubleshooting guidance.

The troubleshooting section addresses common issues (navigation timeouts, auth state persistence, token expiry, form selector changes) with practical solutions. Best practices emphasize security and reliability.

src/content/docs/developer-tools/testing/setup-test-user-environment.mdx (1)

85-87: Consider moving the example repository to the official Kinde organization for consistency.

The Kinde Next.js test application is currently hosted under a personal account rather than the kinde-oss organization. While the repository is accessible and functional, consolidating examples under the official organization would improve discoverability and clarify official support status. For reference, most other examples and starter kits in this documentation are hosted under kinde-oss or kinde-starter-kits.

⛔ Skipped due to learnings
Learnt from: clairekinde11
Repo: kinde-oss/documentation PR: 545
File: src/content/docs/design/customize-with-code/custom-styling-per-application.mdx:59-70
Timestamp: 2025-09-04T02:15:38.458Z
Learning: In Kinde custom pages repository structure, layout.tsx should be placed as a sibling to the (kinde) directory at pages/layout.tsx level, not inside the (kinde) directory. The import path "../../layout" from pages/(kinde)/(default)/page.tsx works correctly with this structure in Kinde's system.
Learnt from: DaveOrDead
Repo: kinde-oss/documentation PR: 402
File: src/content/docs/workflows/bindings/fetch-binding.mdx:42-47
Timestamp: 2025-04-24T03:46:44.953Z
Learning: The correct import path for the Kinde infrastructure library is `kinde/infrastructure`, not `kinde-oss/infrastructure`, despite the GitHub repository being at kinde-oss/infrastructure.
Learnt from: marcosmartini
Repo: kinde-oss/documentation PR: 226
File: src/content/docs/developer-tools/sdks/backend/nextjs-sdk.mdx:0-0
Timestamp: 2024-10-22T06:12:51.559Z
Learning: The Kinde documentation's base URL is not `kinde.com`, so links to the documentation should use the correct base URL.

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: 2

Fix all issues with AI Agents 🤖
In @src/content/docs/developer-tools/testing/testing-authentication-flows.mdx:
- Line 364: The click call using cy.get('button[type="submit"]').click({
multiple: true }) will click all matching submit buttons; remove the unnecessary
{ multiple: true } option and use cy.get('button[type="submit"]').click() (or
explicitly target a single element with .first()/.eq(n) before .click() if a
specific button is intended) to ensure only one submit button is clicked.
- Line 347: The Cypress click call is using an unnecessary { multiple: true }
option which will click all matched submit buttons; update the
cy.get('button[type="submit"]').click call in the testing-authentication-flows
content to remove the multiple option so it clicks a single submit button (i.e.,
change the click invocation on the selector cy.get('button[type="submit"]') to
call .click() with no options).
🧹 Nitpick comments (1)
src/content/docs/developer-tools/testing/testing-authentication-flows.mdx (1)

550-550: Consider adding explicit setup guidance for test IDs.

The examples throughout this guide rely on data-testid attributes (e.g., [data-testid="sign-in-button"]), but there's no explicit mention that users need to add these attributes to their application code before running the tests. Consider adding a brief setup note in the prerequisites section or early in the guide.

Example addition for the "What you need" section:

- Test IDs added to your application's UI elements:
  - `[data-testid="sign-in-button"]` on your sign-in button
  - `[data-testid="sign-up-button"]` on your sign-up button
  - `[data-testid="sign-out-button"]` on your sign-out button
  - `[data-testid="user-profile"]` on an element visible when authenticated
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f125c7d and 7fa9ff2.

📒 Files selected for processing (2)
  • src/content/docs/developer-tools/testing/setup-test-user-environment.mdx
  • src/content/docs/developer-tools/testing/testing-authentication-flows.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/content/docs/developer-tools/testing/setup-test-user-environment.mdx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-27T18:42:29.479Z
Learnt from: victoreronmosele
Repo: kinde-oss/documentation PR: 647
File: src/content/docs/developer-tools/sdks/native/ios-sdk.mdx:278-297
Timestamp: 2025-12-27T18:42:29.479Z
Learning: In MDX documentation files (e.g., any API reference docs), when documenting parameters (like loginHint, connectionId), prefer listing them in the API reference Arguments section and link to detailed documentation pages instead of duplicating descriptions, format specs, or validation rules inline. This follows the 'document once, reference anywhere' principle.

Applied to files:

  • src/content/docs/developer-tools/testing/testing-authentication-flows.mdx
🪛 LanguageTool
src/content/docs/developer-tools/testing/testing-authentication-flows.mdx

[grammar] ~60-~60: Ensure spelling is correct
Context: ...management | ## Testing sign-up flows Kinde requires OTP email verification when si...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~66-~66: Use a hyphen to join words.
Context: ... email testing service to test user sign up 3. Verify redirect: Check that us...

(QB_NEW_EN_HYPHEN)


[grammar] ~228-~228: Use a hyphen to join words.
Context: ...-a8b7236e3300/public) ### Example: Sign up flow with Playwright Check out the f...

(QB_NEW_EN_HYPHEN)


[grammar] ~385-~385: Use a hyphen to join words.
Context: ...-16576792a600/public) ### Example: Sign up flow with Cypress ```ts // spec.cy.t...

(QB_NEW_EN_HYPHEN)

@onderay onderay requested a review from a team January 7, 2026 02:36
@Arobce
Copy link
Contributor

Arobce commented Jan 7, 2026

Hi @tamalchowdhury ,

I was reviewing the "Backend API testing with Jest" guide.

From the example, it appears that the guide is currently demonstrating how to call Kinde Account APIs (for example, /oauth2/v2/user_profile) using a refreshed access token. This is useful for validating authentication and token rotation.

If this was the intended goal of the guide, then the current approach makes sense. However, if the intent was to demonstrate how customers can test their own backend APIs protected by Kinde, then the example may need to be adjusted, as it does not currently show calling or validating a customer-managed backend API.

If the goal is to test client-managed backend APIs secured by Kinde, I think we need to adjust the guide and add a few missing pieces:

1. Prerequisite: Register the backend API in Kinde

The backend API must first be registered and managed in Kinde.
https://docs.kinde.com/developer-tools/your-apis/register-manage-apis/

2. Audience must be included when issuing tokens

When obtaining access and refresh tokens, the audience parameter should be included:

  • During the initial authentication
  • In the refresh token exchange

This ensures the access token is scoped for the customer’s backend API, not just Kinde’s Account APIs.

3. Calling the customer’s backend API (not Kinde’s)

The refreshed access token should then be used to call a protected customer API endpoint, rather than a Kinde endpoint like /user_profile.

4. Backend token validation using a Kinde SDK

If the API is protected, the backend should validate the token using the appropriate SDK, for example:

  • @kinde-oss/kinde-node for Node/Express backends

The guide should show how the backend validates the token and enforces scopes or permissions.

5. End-to-end test example

A complete example test would ideally show:

  • Token refresh with audience
  • Calling a protected backend endpoint
  • Backend verifying the token
  • Test asserting a successful response

Another small improvement suggestion: could you hide your name in the demo screenshot? Adding a simple white box over it would be enough, mainly to protect your own identity.

Relevant references

Custom API scopes
https://docs.kinde.com/developer-tools/your-apis/custom-api-scopes

Register and manage APIs
https://docs.kinde.com/developer-tools/your-apis/register-manage-apis/

Backend SDKs (Node / Express / GraphQL)
https://docs.kinde.com/developer-tools/sdks/backend/node-express-graphql/

If you decide to implement this yourself, the steps should be fairly clear. This guide is intended as a high-level outline, and more detailed implementation guidance can be found in the Kinde documentation or by using Kinde AI.

Please let me know if anything is unclear or if there’s any area where I can help further. I’m also reviewing other guides and will share feedback as I come across additional opportunities for improvement.

test('should get user profile', async () => {
const response = await fetch(
`${KINDE_ISSUER_URL}/oauth2/v2/user_profile`,
{

Choose a reason for hiding this comment

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

This example is calling Kinde’s Account API (/oauth2/v2/user_profile) rather than demonstrating “test your backend API with Jest” (matches @Arobce’s concern). I suggest either (a) reframe this page explicitly as “Testing Kinde Account APIs + token rotation”, or (b) update the example to call a customer backend endpoint (e.g. https://api.yourapp.com/...) and include the missing pieces: audience/resource API, and guidance that the backend must validate the JWT (iss/aud/exp + signature) before trusting it.

4. Navigate to the **Application** tab and select **Cookies** > `http://localhost:3000`
5. Select the `refresh_token` and `access_token` cookies and copy their values, you will need these in the next step

![Screenshot of browser developer tools showing the refresh_token and access_token cookies](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/8f5e05a6-2671-4688-06de-bbc328b4d700/public)

Choose a reason for hiding this comment

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

Screenshot hygiene: this is externally hosted and may contain PII/org identifiers (and could change/expire). Recommend redacting any identifying info and hosting the image in-repo under src/assets/images (or another stable docs asset path) so we control permanence and future diffs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hi @dtoxvanilla1991, I am totally fine with sharing my PII, since I want to associate my name with my work.

Regarding the externally hosted images: this way, the source repo stays lean, but still, I will ask Andre about the screenshot policies.


1. Sign in to your Kinde dashboard and select the **Production** arrow. A pop-up appears.
- Select **All environments**
![setup test environment in kinde](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/2220b137-f7fa-4b3e-95e5-9b1ad7676d00/public)

Choose a reason for hiding this comment

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

Same screenshot concern here: please ensure screenshots are redacted (no real emails/org names) and consider moving from external image hosting to repo-managed assets for long-term stability.


Optional: Go to **Tokens** where you can configure a custom token expiration time.

You can use the [Kinde Next.js test application](https://github.com/tamalchowdhury/kinde-test-application) to run your tests locally.

Choose a reason for hiding this comment

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

Governance/support clarity: this links to an example repo under a personal account. Can we pick an example repo under kinde-oss/kinde-starter-kits?

@tamalchowdhury
Copy link
Collaborator Author

@Arobce Hi, in the Test Authentication Features with Playwright doc, there is a section on backend API testing. I have used my sample test application and tested two endpoints. Do you think it's the right way to do it? If yes, we can use that to model for the Jest testing doc.

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: 2

🤖 Fix all issues with AI agents
In
@src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx:
- Around line 148-149: The current use of new RegExp(`^${baseURL}/.*`) in the
page.waitForURL call can misbehave if baseURL contains regex metacharacters;
change the wait to use a string-based predicate instead (replace the RegExp
usage with page.waitForURL(url => url.startsWith(baseURL))) or, if you truly
need pattern matching, escape baseURL before constructing the RegExp; update the
site where page.waitForURL is called to use the startsWith predicate or a
properly escaped RegExp of baseURL to avoid unintended regex interpretation.
- Around line 396-400: CI workflow env block is missing the required variables
KINDE_ISSUER_URL and TEST_APP_URL referenced by the tests; update the env
section that currently sets TEST_USER_EMAIL, TEST_USER_PASSWORD,
KINDE_CLIENT_ID, and KINDE_REFRESH_TOKEN to also export KINDE_ISSUER_URL and
TEST_APP_URL (e.g., KINDE_ISSUER_URL: ${{ secrets.KINDE_ISSUER_URL }},
TEST_APP_URL: ${{ secrets.TEST_APP_URL }}) so the test configuration can read
them at runtime.
🧹 Nitpick comments (4)
src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx (4)

214-224: Consider adding audience parameter for API-scoped tokens.

When testing customer-protected backend APIs, the access token typically needs to be scoped to the specific API. The token refresh request should include the audience parameter to ensure the returned access token is valid for your backend API.

Suggested enhancement
      const response = await request.post(
        `${process.env.KINDE_ISSUER_URL}/oauth2/token`,
        {
          form: {
            client_id: process.env.KINDE_CLIENT_ID!,
            grant_type: 'refresh_token',
            refresh_token: process.env.KINDE_REFRESH_TOKEN!,
+           audience: process.env.KINDE_API_AUDIENCE!, // Your registered API identifier
          },
        }
      )

Add to .env section:

KINDE_API_AUDIENCE=https://your-api.example.com

This aligns with the PR feedback about ensuring tokens are properly scoped for customer backend APIs.


248-251: Document refresh token rotation strategy.

The commented code hints at an important concern: refresh tokens may rotate on each use. In CI/CD environments, this can cause test failures if the stored refresh token becomes invalid.

Consider adding guidance on:

  1. How to detect and persist new refresh tokens
  2. Using a secrets manager that supports programmatic updates
  3. Alternative approaches like using M2M (machine-to-machine) tokens for CI

347-363: Project structure missing api-token.json.

The api.setup.ts writes tokens to playwright/.auth/api-token.json, but this file isn't shown in the project structure. Consider adding it for completeness.

 ├── playwright/
 │   └── .auth/
 │       └── user.json            # Saved auth state (gitignored)
+│       └── api-token.json       # API tokens (gitignored)

426-428: Use template variable instead of hardcoded URL in example.

For consistency with the rest of the guide, consider using a template placeholder or referencing baseURL:

-await page.waitForURL('https://your-app.com/**', { timeout: 30000 });
+await page.waitForURL(`${baseURL}/**`, { timeout: 30000 });
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fa9ff2 and a07cb47.

📒 Files selected for processing (1)
  • src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-27T18:42:29.479Z
Learnt from: victoreronmosele
Repo: kinde-oss/documentation PR: 647
File: src/content/docs/developer-tools/sdks/native/ios-sdk.mdx:278-297
Timestamp: 2025-12-27T18:42:29.479Z
Learning: In MDX documentation files (e.g., any API reference docs), when documenting parameters (like loginHint, connectionId), prefer listing them in the API reference Arguments section and link to detailed documentation pages instead of duplicating descriptions, format specs, or validation rules inline. This follows the 'document once, reference anywhere' principle.

Applied to files:

  • src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx
🪛 LanguageTool
src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx

[style] ~37-~37: Try moving the adverb to make the sentence clearer.
Context: ...ling passwordless flows. --- Learn how to efficiently test authenticated features in applications using Kinde authenticat...

(SPLIT_INFINITIVE)


[grammar] ~438-~438: Ensure spelling is correct
Context: ...ecrets with the new refresh token. ### Kinde form selectors changed Kinde may updat...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (4)
src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx (4)

46-75: Prerequisites and setup look complete.

Clear prerequisites, proper environment variable setup guidance, and appropriate security warning about .gitignore. The setup instructions follow standard Playwright project initialization patterns.


410-418: Best practices section is comprehensive.

Good coverage of essential testing practices including security (test-specific users, secure credentials), reliability (handling flakiness, data-testid), and maintenance (cleanup, storage state).


448-454: Limitations section appropriately sets expectations.

Clear documentation of testing limitations (social providers, enterprise SSO, MFA) helps users understand the boundaries of automated testing with Kinde.


8-10: [No action required] All three relatedArticles UUIDs are valid page IDs that exist in the documentation:

  • 4882de7b-07f3-4cc8-ac01-b096e17dcc35backend-api-testing.mdx
  • c1b1ea81-35f9-467e-8079-042d6a786e55testing-authentication-flows.mdx
  • a1b2c3d4-e5f6-7890-abcd-ef1234567890testing-passwordless-flows.mdx

Likely an incorrect or invalid review comment.

Comment on lines 148 to 149
// Wait for redirect back to your app
await page.waitForURL(new RegExp(`^${baseURL}/.*`));
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Potential regex issue with unescaped baseURL.

If baseURL contains regex special characters (e.g., ?, ., +), the RegExp constructor will interpret them as regex metacharacters, potentially causing unexpected behavior or test failures.

Suggested fix
-      await page.waitForURL(new RegExp(`^${baseURL}/.*`));
+      // Escape special regex characters in baseURL
+      const escapedBaseURL = baseURL!.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+      await page.waitForURL(new RegExp(`^${escapedBaseURL}/.*`));

Alternatively, use a simpler string-based check if exact matching suffices:

await page.waitForURL(url => url.startsWith(baseURL!));
🤖 Prompt for AI Agents
In
@src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx
around lines 148 - 149, The current use of new RegExp(`^${baseURL}/.*`) in the
page.waitForURL call can misbehave if baseURL contains regex metacharacters;
change the wait to use a string-based predicate instead (replace the RegExp
usage with page.waitForURL(url => url.startsWith(baseURL))) or, if you truly
need pattern matching, escape baseURL before constructing the RegExp; update the
site where page.waitForURL is called to use the startsWith predicate or a
properly escaped RegExp of baseURL to avoid unintended regex interpretation.

Comment on lines 396 to 400
env:
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
KINDE_CLIENT_ID: ${{ secrets.KINDE_CLIENT_ID }}
KINDE_REFRESH_TOKEN: ${{ secrets.KINDE_REFRESH_TOKEN }}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

CI workflow missing required environment variables.

The workflow is missing KINDE_ISSUER_URL and TEST_APP_URL which are required by the test configurations shown earlier in the document.

Suggested fix
        env:
+         TEST_APP_URL: ${{ secrets.TEST_APP_URL }}
          TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
          TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
          KINDE_CLIENT_ID: ${{ secrets.KINDE_CLIENT_ID }}
+         KINDE_ISSUER_URL: ${{ secrets.KINDE_ISSUER_URL }}
          KINDE_REFRESH_TOKEN: ${{ secrets.KINDE_REFRESH_TOKEN }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
env:
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
KINDE_CLIENT_ID: ${{ secrets.KINDE_CLIENT_ID }}
KINDE_REFRESH_TOKEN: ${{ secrets.KINDE_REFRESH_TOKEN }}
env:
TEST_APP_URL: ${{ secrets.TEST_APP_URL }}
TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
KINDE_CLIENT_ID: ${{ secrets.KINDE_CLIENT_ID }}
KINDE_ISSUER_URL: ${{ secrets.KINDE_ISSUER_URL }}
KINDE_REFRESH_TOKEN: ${{ secrets.KINDE_REFRESH_TOKEN }}
🤖 Prompt for AI Agents
In
@src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx
around lines 396 - 400, CI workflow env block is missing the required variables
KINDE_ISSUER_URL and TEST_APP_URL referenced by the tests; update the env
section that currently sets TEST_USER_EMAIL, TEST_USER_PASSWORD,
KINDE_CLIENT_ID, and KINDE_REFRESH_TOKEN to also export KINDE_ISSUER_URL and
TEST_APP_URL (e.g., KINDE_ISSUER_URL: ${{ secrets.KINDE_ISSUER_URL }},
TEST_APP_URL: ${{ secrets.TEST_APP_URL }}) so the test configuration can read
them at runtime.

@Arobce
Copy link
Contributor

Arobce commented Jan 12, 2026

@Arobce Hi, in the Test Authentication Features with Playwright doc, there is a section on backend API testing. I have used my sample test application and tested two endpoints. Do you think it's the right way to do it? If yes, we can use that to model for the Jest testing doc.

@tamalchowdhury, that is a step in the right direction. We need to make a few changes: the access token is generated directly by the API (it is not stored anywhere); aud, which is essentially the Kinde Managed API URL, should be set to the API endpoint to obtain the correct access token and then perform the test runs. My above longer comment should also be helpful. Please let me know if you are unsure of anything.

@Arobce
Copy link
Contributor

Arobce commented Jan 12, 2026

@tamalchowdhury

For example (and this also needs to be changed), in testing authenticated features with Playwright.

Here:

 const response = await request.post(
    `${process.env.KINDE_ISSUER_URL}/oauth2/token`,
    {
      form: {
        client_id: process.env.KINDE_CLIENT_ID!,
        grant_type: 'refresh_token',
        refresh_token: process.env.KINDE_REFRESH_TOKEN!,
      },
    }
  )

You have then used the /api/profile and /api/settings.

However, the correct steps here are to:

  1. First add the /api URL to Kinde Managed APIs
image
  1. Request the token with an audience parameter:
const response = await fetch(
    `${process.env.KINDE_ISSUER_URL}/oauth2/token`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        "Accept": "application/json",
      },
      body: new URLSearchParams({
        grant_type: "refresh_token",
        client_id: process.env.KINDE_CLIENT_ID!,
        client_secret: process.env.KINDE_CLIENT_SECRET!,
        refresh_token: process.env.KINDE_REFRESH_TOKEN!,
        audience: "/api",
      }).toString(),
    }
  )
  1. Use the API as you have with the new token

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: 2

🤖 Fix all issues with AI agents
In `@src/content/docs/developer-tools/testing/backend-api-testing.mdx`:
- Around line 127-132: The token refresh request built in the requestBody
URLSearchParams is missing the audience parameter; update the URLSearchParams
(the requestBody variable) to include audience: process.env.KINDE_AUDIENCE so
the refreshed access token is scoped to the customer's backend API, and also add
KINDE_AUDIENCE to the .env example in Step 3 (the environment variable sample
near the existing KINDE_CLIENT_ID/KINDE_CLIENT_SECRET/KINDE_REFRESH_TOKEN
entries) so users know to set it.

In `@src/content/docs/developer-tools/testing/setup-test-user-environment.mdx`:
- Line 56: Sentence "Select **Add environment**, a pop-up appears" contains a
comma splice; change it to match line 52's style by replacing the comma with a
period or semicolon so it reads "Select **Add environment**. A pop-up appears"
(update the string in the markdown file
src/content/docs/developer-tools/testing/setup-test-user-environment.mdx where
that sentence appears).
♻️ Duplicate comments (1)
src/content/docs/developer-tools/testing/setup-test-user-environment.mdx (1)

88-88: Consider using a kinde-oss repository for the test application.

This links to a personal GitHub account repository. For official documentation, consider hosting the example under kinde-oss or kinde-starter-kits for governance, long-term maintenance, and discoverability.

Comment on lines 127 to 132
const requestBody = new URLSearchParams({
grant_type: 'refresh_token',
client_id: process.env.KINDE_CLIENT_ID,
client_secret: process.env.KINDE_CLIENT_SECRET,
refresh_token: process.env.KINDE_REFRESH_TOKEN,
}).toString()
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Include audience parameter in the token refresh request.

Per the PR discussion, the token refresh request should include the audience parameter so that the access token is scoped to the customer's backend API rather than Kinde Account APIs. Without this, the refreshed token won't have the correct aud claim for validating against the registered API.

Proposed fix
       const requestBody = new URLSearchParams({
         grant_type: 'refresh_token',
         client_id: process.env.KINDE_CLIENT_ID,
         client_secret: process.env.KINDE_CLIENT_SECRET,
         refresh_token: process.env.KINDE_REFRESH_TOKEN,
+        audience: process.env.KINDE_AUDIENCE,
       }).toString()

Also add KINDE_AUDIENCE to the .env example in Step 3 (lines 93-101):

 # .env
 KINDE_ISSUER_URL=https://your_kinde_domain.kinde.com
 KINDE_CLIENT_ID=your_client_id
 KINDE_CLIENT_SECRET=your_client_secret
+KINDE_AUDIENCE=https://api.mysite.com
 KINDE_TEST_APP_URL=http://localhost:3000
 TEST_USER_EMAIL=your_test_user_email
 KINDE_REFRESH_TOKEN=your_refresh_token_from_step_2
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const requestBody = new URLSearchParams({
grant_type: 'refresh_token',
client_id: process.env.KINDE_CLIENT_ID,
client_secret: process.env.KINDE_CLIENT_SECRET,
refresh_token: process.env.KINDE_REFRESH_TOKEN,
}).toString()
const requestBody = new URLSearchParams({
grant_type: 'refresh_token',
client_id: process.env.KINDE_CLIENT_ID,
client_secret: process.env.KINDE_CLIENT_SECRET,
refresh_token: process.env.KINDE_REFRESH_TOKEN,
audience: process.env.KINDE_AUDIENCE,
}).toString()
🤖 Prompt for AI Agents
In `@src/content/docs/developer-tools/testing/backend-api-testing.mdx` around
lines 127 - 132, The token refresh request built in the requestBody
URLSearchParams is missing the audience parameter; update the URLSearchParams
(the requestBody variable) to include audience: process.env.KINDE_AUDIENCE so
the refreshed access token is scoped to the customer's backend API, and also add
KINDE_AUDIENCE to the .env example in Step 3 (the environment variable sample
near the existing KINDE_CLIENT_ID/KINDE_CLIENT_SECRET/KINDE_REFRESH_TOKEN
entries) so users know to set it.

- Select **All environments**

![setup test environment in kinde](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/2220b137-f7fa-4b3e-95e5-9b1ad7676d00/socialsharingimage)
2. Select **Add environment**, a pop-up appears
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix comma splice for consistency with line 52.

Line 56 has the same comma splice pattern that was corrected on line 52.

Proposed fix
-2. Select **Add environment**, a pop-up appears
+2. Select **Add environment**. A pop-up appears.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
2. Select **Add environment**, a pop-up appears
2. Select **Add environment**. A pop-up appears.
🤖 Prompt for AI Agents
In `@src/content/docs/developer-tools/testing/setup-test-user-environment.mdx` at
line 56, Sentence "Select **Add environment**, a pop-up appears" contains a
comma splice; change it to match line 52's style by replacing the comma with a
period or semicolon so it reads "Select **Add environment**. A pop-up appears"
(update the string in the markdown file
src/content/docs/developer-tools/testing/setup-test-user-environment.mdx where
that sentence appears).

@tamalchowdhury
Copy link
Collaborator Author

@Arobce Kindly have a look at the updated Jest backend testing doc. I have included the Register API step, and it now tests the backend API.

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: 2

🤖 Fix all issues with AI agents
In `@src/content/docs/developer-tools/testing/backend-api-testing.mdx`:
- Around line 118-165: The refreshTokens function in jest.global-setup.js must
persist refreshed tokens to a shared file so test workers can read them; update
refreshTokens to write tokens.access_token and tokens.refresh_token to a JSON
file (e.g., .kinde-tokens.json) after successful refresh and keep the existing
console/log behavior on failure, then update test setup (or individual tests) to
read and load environment values from that JSON file before tests run; also add
.kinde-tokens.json to .gitignore to avoid committing tokens.

In
`@src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx`:
- Around line 276-303: The refresh token request in tests/api/api.setup.ts
(inside setup('refresh API tokens', async ({ request }) => { ... })) is missing
the audience parameter, causing refreshed tokens to lack the correct API
audience; update the .env example to include an audience variable (e.g.,
KINDE_AUDIENCE or TEST_API_AUDIENCE) and modify the form sent in the POST to
include audience: process.env.KINDE_AUDIENCE (or the chosen name), so the
request includes client_id, grant_type, refresh_token, and audience ensuring the
token is scoped for your backend.
♻️ Duplicate comments (4)
src/content/docs/developer-tools/testing/testing-authentication-flows.mdx (1)

341-365: Avoid Cypress clicking multiple submit buttons

{ multiple: true } will click all matched submit buttons and can cause double submits or unpredictable behavior. Prefer a single click or narrow the selector.

🔧 Suggested fix
-          cy.get('button[type="submit"]').click({ multiple: true })
+          cy.get('button[type="submit"]').click()
...
-          cy.get('button[type="submit"]').click({ multiple: true })
+          cy.get('button[type="submit"]').click()
src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx (2)

148-149: Escape baseURL before building a RegExp

Unescaped baseURL can introduce regex metacharacters and cause false matches or failures. Prefer a predicate or escape the string.

✅ Safer option
-      await page.waitForURL(new RegExp(`^${baseURL}/.*`));
+      await page.waitForURL(url => url.startsWith(baseURL!));

476-480: CI env block missing required variables

The workflow examples reference TEST_APP_URL and KINDE_ISSUER_URL earlier, but they’re not exported here.

🔧 Suggested fix
       - name: Run Playwright tests
         run: npx playwright test
         env:
+          TEST_APP_URL: ${{ secrets.TEST_APP_URL }}
           TEST_USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
           TEST_USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
           KINDE_CLIENT_ID: ${{ secrets.KINDE_CLIENT_ID }}
+          KINDE_ISSUER_URL: ${{ secrets.KINDE_ISSUER_URL }}
           KINDE_REFRESH_TOKEN: ${{ secrets.KINDE_REFRESH_TOKEN }}
src/content/docs/developer-tools/testing/backend-api-testing.mdx (1)

94-101: Add audience to refresh request and .env sample

Without audience, refreshed tokens won’t be scoped to the registered API, which undermines backend JWT validation.

🔧 Suggested fix
 # .env
 KINDE_ISSUER_URL=https://your_kinde_domain.kinde.com
 KINDE_CLIENT_ID=your_client_id
 KINDE_CLIENT_SECRET=your_client_secret
+KINDE_AUDIENCE=https://api.mysite.com
 KINDE_TEST_APP_URL=http://localhost:3000
 TEST_USER_EMAIL=your_test_user_email
 KINDE_REFRESH_TOKEN=your_refresh_token_from_step_2
       const requestBody = new URLSearchParams({
         grant_type: 'refresh_token',
         client_id: process.env.KINDE_CLIENT_ID,
         client_secret: process.env.KINDE_CLIENT_SECRET,
         refresh_token: process.env.KINDE_REFRESH_TOKEN,
+        audience: process.env.KINDE_AUDIENCE,
       }).toString()

Also applies to: 128-133

Comment on lines 118 to 165
5. Open `jest.global-setup.js` and add the following code that refreshes tokens before tests run:

```javascript
// jest.global-setup.js
require('dotenv').config()

async function refreshTokens() {
const tokenUrl = `${process.env.KINDE_ISSUER_URL}/oauth2/token`

try {
const requestBody = new URLSearchParams({
grant_type: 'refresh_token',
client_id: process.env.KINDE_CLIENT_ID,
client_secret: process.env.KINDE_CLIENT_SECRET,
refresh_token: process.env.KINDE_REFRESH_TOKEN,
}).toString()

const response = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: requestBody,
})

if (!response.ok) {
const errorText = await response.text()
throw new Error(
`Token refresh failed: ${response.status} ${response.statusText} - ${errorText}`
)
}

const tokens = await response.json()

// Update environment variables for current test run
process.env.KINDE_ACCESS_TOKEN = tokens.access_token
process.env.KINDE_REFRESH_TOKEN = tokens.refresh_token

console.log('✓ Tokens refreshed successfully')
} catch (error) {
console.warn('⚠ Failed to refresh tokens:', error.message)
console.warn('⚠ Continuing with existing tokens from .env file')
// Don't throw - allow tests to run with existing tokens
}
}

module.exports = refreshTokens
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Jest globalSetup separate process environment variables

💡 Result:

Short answer: globalSetup runs outside the test worker processes and cannot directly share in-memory globals with your tests. Use environment variables, files, or a custom testEnvironment/setupFiles to pass data.

Details and options

  • Jest docs: globals set in globalSetup are only readable by globalTeardown, not test suites. globalSetup is run once before suites. [1].
  • Community/issue threads confirm globalSetup/globalTeardown run in different processes from per-test workers, so in-memory values won't be visible to tests; common workarounds are writing data to a file, starting a service and exposing a connection endpoint, or setting env vars that test workers can read. [2][3].

Practical approaches

  • Write the value (e.g. a port, WSEndpoint, token) to a temp file in globalSetup and read that file from tests or from a custom testEnvironment. [2][3].
  • Export needed values via environment variables if you run Jest single-process (runInBand) or ensure the worker processes inherit them (CI/launcher-level env), but note setting process.env inside globalSetup will not propagate to already-spawned worker processes. [2].
  • Use setupFiles or a custom TestEnvironment (setup/teardown) to initialize per-worker globals that tests can access as this.global. [1][3].

If you want, tell me which value you need shared (WSEndpoint, DB URI, auth token, etc.) and your Jest config (maxWorkers, runInBand, node/jsdom) and I’ll give a concrete snippet.

Sources: [1] Jest config/docs, [2] Jest GitHub issue / StackOverflow thread, [3] blogs/docs describing file/env workarounds.


🏁 Script executed:

# First, let's examine the file mentioned in the review
find . -type f -name "backend-api-testing.mdx" | head -5

Repository: kinde-oss/documentation

Length of output: 133


🏁 Script executed:

# Read the file to see the context around lines 118-165 and 258-264
cat -n ./src/content/docs/developer-tools/testing/backend-api-testing.mdx | sed -n '100,180p'

Repository: kinde-oss/documentation

Length of output: 3009


🏁 Script executed:

# Also check lines 250-270 for the second reference
cat -n ./src/content/docs/developer-tools/testing/backend-api-testing.mdx | sed -n '250,270p'

Repository: kinde-oss/documentation

Length of output: 784


🏁 Script executed:

# Check if there's any additional Jest config in the repo
find . -type f -name "jest.config.*" -o -name "jest.json" | head -10

Repository: kinde-oss/documentation

Length of output: 49


🏁 Script executed:

# Check the full context of the documentation to see if there are any warnings or additional config mentioned
cat -n ./src/content/docs/developer-tools/testing/backend-api-testing.mdx | sed -n '1,50p'

Repository: kinde-oss/documentation

Length of output: 2163


🏁 Script executed:

# Also check if there's any mention of how tokens are actually used or if there's alternative guidance
cat -n ./src/content/docs/developer-tools/testing/backend-api-testing.mdx | sed -n '167,250p'

Repository: kinde-oss/documentation

Length of output: 2838


🏁 Script executed:

# Check if there's a .gitignore in the repo and what it excludes
if [ -f .gitignore ]; then cat .gitignore | head -20; fi

Repository: kinde-oss/documentation

Length of output: 285


🏁 Script executed:

# Let me also verify the exact Jest documentation reference for this pattern
# by checking if there are any other Jest config examples in the docs
grep -r "globalSetup\|setupFiles\|testEnvironment" ./src --include="*.mdx" | grep -v node_modules | head -20

Repository: kinde-oss/documentation

Length of output: 291


Persist refreshed tokens to a file—globalSetup runs in isolation from test workers

globalSetup runs in its own process, so process.env updates there won't reach test workers. They will only see values from the original .env file. Persist tokens to a file in globalSetup and read them in tests instead.

🔧 Suggested fix (file-based token handoff)
-    // Update environment variables for current test run
-    process.env.KINDE_ACCESS_TOKEN = tokens.access_token
-    process.env.KINDE_REFRESH_TOKEN = tokens.refresh_token
+    const { writeFileSync } = require('fs')
+    const { join } = require('path')
+    const tokenPath = join(process.cwd(), '.kinde-tokens.json')
+    writeFileSync(
+      tokenPath,
+      JSON.stringify(
+        {
+          access_token: tokens.access_token,
+          refresh_token: tokens.refresh_token,
+          expires_at: Date.now() + tokens.expires_in * 1000,
+        },
+        null,
+        2
+      )
+    )
-    const accessToken = process.env.KINDE_ACCESS_TOKEN
+    const { readFileSync } = require('fs')
+    const { join } = require('path')
+    const tokenData = JSON.parse(
+      readFileSync(join(process.cwd(), '.kinde-tokens.json'), 'utf-8')
+    )
+    const accessToken = tokenData.access_token

Also add .kinde-tokens.json to .gitignore to prevent token files from being committed.

🤖 Prompt for AI Agents
In `@src/content/docs/developer-tools/testing/backend-api-testing.mdx` around
lines 118 - 165, The refreshTokens function in jest.global-setup.js must persist
refreshed tokens to a shared file so test workers can read them; update
refreshTokens to write tokens.access_token and tokens.refresh_token to a JSON
file (e.g., .kinde-tokens.json) after successful refresh and keep the existing
console/log behavior on failure, then update test setup (or individual tests) to
read and load environment values from that JSON file before tests run; also add
.kinde-tokens.json to .gitignore to avoid committing tokens.

Comment on lines 276 to 303
2. Update the `.env` file with the following values:

```env
# .env
TEST_APP_URL=http://your-app-url.com
TEST_USER_EMAIL=test@example.com
KINDE_CLIENT_ID=your-kinde-client-id
KINDE_ISSUER_URL=https://your-subdomain.kinde.com
KINDE_REFRESH_TOKEN=your-refresh-token
```
3. Create and update a new `api.setup.ts` file with the following content:

```tsx
// tests/api/api.setup.ts
import { test as setup, expect } from '@playwright/test'
import { writeFileSync, mkdirSync } from 'fs'
import { join, dirname } from 'path'

setup('refresh API tokens', async ({ request }) => {
const response = await request.post(
`${process.env.KINDE_ISSUER_URL}/oauth2/token`,
{
form: {
client_id: process.env.KINDE_CLIENT_ID!,
grant_type: 'refresh_token',
refresh_token: process.env.KINDE_REFRESH_TOKEN!,
},
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Kinde OAuth2 token refresh audience parameter

💡 Result:

Short answer: Yes — Kinde’s SDKs let you pass an audience when refreshing, but the token service will only issue an access token for an audience the refresh token (and client) are allowed to use; it will commonly return the existing (same‑aud) access token unless a new one is required. See the Ruby SDK refresh_token call which accepts an optional audience parameter, Kinde’s note that refreshed tokens may be the existing access token, and the client_credentials flow requirement that audience be authorized for the app. [1][2][3]

Sources:

  • Kinde Ruby SDK (refresh_token / audience options). [1]
  • Kinde — Behaviour of Access Tokens on refresh (may return existing access token). [2]
  • Kinde M2M (client_credentials) — audience parameter and app authorization for an API. [3]

🌐 Web query:

Kinde refresh token endpoint audience scope

💡 Result:

Short answer: You can include audience (and scope) when calling Kinde’s /oauth2/token with grant_type=refresh_token to request an access token for a specific audience — Kinde’s SDKs and docs show audience as a supported parameter for token/refresh operations. See Kinde refresh token docs and SDK pages. [1][2][3]

Sources

  • Refresh tokens overview (token endpoint / refresh flow). [1]
  • JS SDK — audience and overriding scope. [2]
  • Ruby SDK — refresh_token helper and audience parameter. [3]

🌐 Web query:

OAuth2 refresh token audience parameter standard

💡 Result:

Short answer: There is no standardized "audience" parameter defined for the OAuth 2.0 refresh_token grant in RFC 6749. Use the Resource Indicators extension (resource) or the Token Exchange spec (audience) when you need to request/audience-restrict tokens.

  • RFC 6749 (refresh_token request parameters): no audience parameter is defined. [1]
  • RFC 8707 (Resource Indicators): defines the resource parameter for token endpoint requests (applicable to all grant types, including refresh_token) to indicate target audiences/resources. [2]
  • RFC 8693 (Token Exchange): defines an audience parameter for exchanging tokens when you need to request tokens targeted at other audiences/services. [3]

If you need provider-specific behavior many implementations also support custom "audience" query/body parameters (check your authorization server docs).


Include audience in refresh token request and add to environment config

Kinde's token refresh endpoint supports an audience parameter. Without it, the refreshed token may not be scoped to your API, causing audience validation failures in your backend.

🔧 Suggested fix
     # .env
     TEST_APP_URL=http://your-app-url.com
     TEST_USER_EMAIL=test@example.com
     KINDE_CLIENT_ID=your-kinde-client-id
     KINDE_ISSUER_URL=https://your-subdomain.kinde.com
     KINDE_REFRESH_TOKEN=your-refresh-token
+    KINDE_AUDIENCE=your-api-audience
           form: {
             client_id: process.env.KINDE_CLIENT_ID!,
             grant_type: 'refresh_token',
             refresh_token: process.env.KINDE_REFRESH_TOKEN!,
+            audience: process.env.KINDE_AUDIENCE!,
           },
🤖 Prompt for AI Agents
In
`@src/content/docs/developer-tools/testing/testing-authenticated-features-playwright.mdx`
around lines 276 - 303, The refresh token request in tests/api/api.setup.ts
(inside setup('refresh API tokens', async ({ request }) => { ... })) is missing
the audience parameter, causing refreshed tokens to lack the correct API
audience; update the .env example to include an audience variable (e.g.,
KINDE_AUDIENCE or TEST_API_AUDIENCE) and modify the form sent in the POST to
include audience: process.env.KINDE_AUDIENCE (or the chosen name), so the
request includes client_id, grant_type, refresh_token, and audience ensuring the
token is scoped for your backend.

@tamalchowdhury tamalchowdhury marked this pull request as draft January 19, 2026 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants