Kinde in Cloudflare Pages Function Middleware

I'm using a Cloudflare Pages Function as a middleware to check user authentication before loading any site assets. Using Clerk as an example, it looks kinda like this: const clerkClient = createClerkClient({secretKey, publishableKey}); const {isSignedIn} = await clerkClient.authenticateRequest(context.request, {jwtKey}); if (!isSignedIn) // ...redirect to auth provider However, I'm unable to figure out how to do something similar with Kinde. The Kinde node libraries don't work because the Function environment doesn't allow the necessary libraries. I found this post which offers a solution for this, https://kinde.com/blog/engineering/verifying-jwts-in-cloudflare-workers/, but Kinde doesn't pass an authorization or cookie in the request even when I'm signed in, so there is nothing to verify. Is this just because I'm not using a custom domain in Kinde? I'm confused because the underlying React app recognizes me as being signed in, so there must be some mechanism to authenticate the user. For clarity, I also don't have a custom domain in Clerk, but maybe they set cookies by default, I'm not sure.
6 Replies
Ages - Kinde
Ages - Kinde6d ago
Hi, thanks for your detailed message — you’re exactly right to notice the difference in behavior compared to Clerk, and you’re on the right track. The key reason you’re not seeing an authorization header or cookie in the request is due to how Kinde handles token storage by default. To protect against CSRF and XSS attacks, Kinde stores tokens in memory, not in cookies or headers:
🔗 Token handling in Kinde React SDK Because of this, middleware (like your Cloudflare Pages Function) won’t see tokens by default. Here are a few ways to address this: ✅ Recommended: Use Kinde Custom Domains Setting up a custom domain allows Kinde to store a secure, httpOnly refresh token in a first-party cookie. This enables your middleware to access the token and verify it. ⚠ For Local Development Only You can use useInsecureForRefreshToken in the Kinde React SDK to store the refresh token in localStorage:
<KindeProvider
useInsecureForRefreshToken
// ...other props
/>
<KindeProvider
useInsecureForRefreshToken
// ...other props
/>
This is not recommended for production environments, but can help with local testing. 🔐 JWT Verification in Cloudflare Workers Once you’re receiving the token (e.g., via custom domain cookies or an Authorization header you manually attach), you can verify it in a Cloudflare Worker using a library like cloudflare-worker-jwt or jose:
import { verify } from 'cloudflare-worker-jwt';

const token = request.headers.get('Authorization')?.split(' ')[1];
const publicKey = 'YOUR_PUBLIC_KEY'; // From Kinde’s JWKS endpoint
const isValid = await verify(token, publicKey, { algorithm: 'RS256' });
import { verify } from 'cloudflare-worker-jwt';

const token = request.headers.get('Authorization')?.split(' ')[1];
const publicKey = 'YOUR_PUBLIC_KEY'; // From Kinde’s JWKS endpoint
const isValid = await verify(token, publicKey, { algorithm: 'RS256' });
Your Kinde JWKS endpoint is:
https://<YOUR_DOMAIN>.kinde.com/.well-known/jwks Let me know if you’d like help setting up the custom domain or verifying tokens in your worker. Happy to walk through it together!
Kinde docs
React SDK
Our developer tools provide everything you need to get started with Kinde.
Straegge
StraeggeOP6d ago
Thanks for your reply, that explains things. I'll set up a custom domain then. I don't need help with verifying the token, but I am wondering about redirecting from the CF Function if the token is not valid. With Clerk, I can simply redirect to https://<clerk-ui-domain>/sign-in. But Kinde doesn't seem to have a simple sign-in route, and since I can't use the SDK, it looks like I have to redirect to: https://<your_kinde_subdomain>.kinde.com/oauth2/auth ?response_type=code &client_id=<your_kinde_client_id> &redirect_uri=<your_app_redirect_url> &scope=openid%20profile%20email &state=abc Is my understanding correct or is there a simpler URL? Basically I just want to direct the user to the same page as when using the login method of the SDKs. Is there a way to do that within a Cloudflare Pages Function without reimplementing the login function internals?
Ages - Kinde
Ages - Kinde6d ago
Hi, Yes, you're absolutely right — since you're not using the SDK, you'll need to manually redirect users to the Kinde authorization URL from your Cloudflare Pages Function when the token is invalid. You can use a redirect like this:
// In your Cloudflare Function
async function handleRequest(request) {
return Response.redirect(
'https://<your_kinde_subdomain>.kinde.com/oauth2/auth' +
'?response_type=code' +
'&client_id=<your_kinde_client_id>' +
'&redirect_uri=<your_app_redirect_url>' +
'&scope=openid%20profile%20email' +
'&state=<your_state_value>',
302
);
}

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
// In your Cloudflare Function
async function handleRequest(request) {
return Response.redirect(
'https://<your_kinde_subdomain>.kinde.com/oauth2/auth' +
'?response_type=code' +
'&client_id=<your_kinde_client_id>' +
'&redirect_uri=<your_app_redirect_url>' +
'&scope=openid%20profile%20email' +
'&state=<your_state_value>',
302
);
}

addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
Just replace the placeholder values with your actual Kinde credentials and redirect URI. You can also optionally include the prompt parameter if you want to explicitly trigger a login or signup screen: 👉 Using Kinde without an SDK This approach effectively replicates the behaviour of the SDK’s login method — so yes, your understanding is spot on. Let me know how it goes, or if it helps or not!
Kinde docs
Using Kinde without an SDK
Our developer tools provide everything you need to get started with Kinde.
Straegge
StraeggeOP6d ago
Thanks for the confirmation. So replacing the values with my own doesn't work, that URL gives me the following error: Something went wrong when we tried to authenticate you, and we can’t offer a quick way out. Start a new session and try signing in again. Error code: 1656 But additionally adding the code_challenge and code_challenge_method parameters seems to work, at least the URL directs me to the sign-in page. I really wish there was an easier to get there, as in Clerk - like why do I need to specify the redirect_uri? It should be optional and Kinde should default to the homepage callback URL specified in the app. On that note, is there a suggested way of generating the state parameter? I don't really care about it for this middleware functionality, but the URL doesn't work without it.
Ages - Kinde
Ages - Kinde5d ago
Thanks for sharing those details — and great to hear that adding code_challenge and code_challenge_method helped move things forward. While those parameters are required by spec and important for security and proper redirection, I’ve raised your feedback internally so the team is aware of the experience from your side. Let me know if you need help with anything else in the meantime!
Straegge
StraeggeOP3d ago
Okay so I've added and verified a custom domain, and I can see the cookies set in the browser, but your suggestion still doesn't work. In the request coming to the CF Pages Function middleware, the "Authorization" header is still null. And the cookies still don't seem to be passed correctly, at least there's no token cookie present in the request. I realized you said "via custom domain cookies or Authorization header you manually attach" - I can't manually attach anything, it's a middleware managed by CF that is automatically executed for every request going to the site. Can you please verify your solution?

Did you find this page helpful?