Testing authentication flows
Testing
With Kinde, you can test backend APIs using refresh tokens for maintaining authenticated sessions in automated tests, including token rotation.
For automated backend tests, you can establish a long-running auth session using refresh tokens. This allows your test infrastructure to maintain authentication without manual sign-ins.
The access token obtained this way is identical to what your production users receive.
You can add your API to Kinde. This will scope your token to be used only for your testing setup. This is optional, but it is a good practice to do so. Learn more about registering and managing APIs in Kinde.
In Kinde, go to Settings > APIs.
Select Add API.
Enter an API name and Audience (e.g., https://api.mysite.com). The audience (aud) is a unique identifier for this API. Often, a short code or the URL of the API is used.
Select Save. The details window for the API opens. You’ll notice that an ID has been created, but it is not editable, and neither is the audience. However, you can copy these details.
To authorize this API for your apps, select Applications in the left menu.
Select the three dots menu next to the relevant application (your test application), then choose Authorize application.
To include the audience claim in your token, add the audience value in your SDK.
For example, in your Next.js test application, you can add the audience value in your .env file:
KINDE_AUDIENCE=<your-api-audience>Run your test application locally
Sign in with your test user in a browser
Right-click on the page and select Inspect to open the browser developer tools
Navigate to the Application tab and select Cookies > http://localhost:3000
Select the refresh_token cookie and copy its value. You will need this refresh token value when configuring your test setup.
You can validate the test API request with the Kinde JWT validator and JWT decoder packages.
Install the required dependencies:
npm install @kinde/jwt-validator @kinde/jwt-decoderHere is sample code showing how to validate your JWT token:
import { validateToken } from "@kinde/jwt-validator";import { jwtDecoder } from "@kinde/jwt-decoder";
// ... get the token from the request headers
try { // Validate the token const result = await validateToken({ token, domain, // KINDE_ISSUER_URL });
if (!result.valid) { console.log("Token validation failed:", result.message); return null; }
// Decode after validation const decoded = jwtDecoder(token); return decoded;
} catch (error) { // The validator throws for JWKS or validation errors console.error("Token is invalid:", error); return null; }If you are protecting your API with Kinde, you should also check for the audience claim to ensure the token is valid for your API. This way, only authorized apps can access your API. Here is sample code:
// ... validate token using previous code ...const expectedAudience = process.env.KINDE_AUDIENCE; // or hardcoded value
if (expectedAudience) { const audience = decoded.aud; // Handle both string and array audience values const audiences = Array.isArray(audience) ? audience : [audience];
if (!audiences.includes(expectedAudience)) { console.log( "Token audience validation failed. Expected:", expectedAudience, "Got:", audience ); return null; } return decoded;}After exchange, the previous refresh token remains valid for approximately 30 seconds (grace period), then becomes invalid. Always use the most recently issued refresh token.
Never commit tokens to source control. Make sure to add .env to your .gitignore file. For CI/CD environments, use secret managers like GitHub Secrets, AWS Secrets Manager, or similar to inject environment variables securely.
Refresh tokens at the start of each test run to ensure fresh access tokens.
The following limitations apply to backend API testing with refresh tokens:
To see complete backend API testing examples, see the following guides: