K
KindeMasini

Express Protected Routes: How to pass JWT from client?

Hi, I have an express API which is using the protectRoute and getUser middlewares in each route. From the client-side, I am using Expo and getting a JWT once successfully logging in, but I'm not sure how I should pass this as a parameter when invoking one of my API endpoints. How can I do this?
Oli - Kinde
Oli - Kinde18d ago
Hey @Masini, To pass the JWT from your Expo client-side application to your Express API using the protectRoute and getUser middlewares, you need to include the JWT in the Authorization header of your HTTP requests. Here's a step-by-step guide on how to do this: 1. Store the JWT: After logging in on your Expo app and receiving the JWT, store it in a secure place within your application, such as secure storage. 2. Set up the HTTP request: When making a request to your Express API, include the JWT in the Authorization header. The common practice is to use the 'Bearer' schema. Here’s an example of how you can set up the request:
const jwt = 'your_jwt_token_here'; // Assume you have fetched this from secure storage

fetch('https://yourapi.com/protected-route', {
method: 'GET', // or 'POST', 'PUT', etc.
headers: {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
const jwt = 'your_jwt_token_here'; // Assume you have fetched this from secure storage

fetch('https://yourapi.com/protected-route', {
method: 'GET', // or 'POST', 'PUT', etc.
headers: {
'Authorization': `Bearer ${jwt}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
3. Handle the JWT in Express: On your server-side, the protectRoute middleware will automatically extract the JWT from the Authorization header, validate it, and if valid, the getUser middleware will populate the request object with the user's data. Ensure your server is set up to handle and authenticate the token correctly. By following these steps, your Expo application will be able to securely communicate with your Express API, passing the JWT for authentication and user identification on protected routes. Please let me know if you have any further questions.
Masini
Masini8d ago
I can confirm that my JWT is valid and I implemented it the same way. However it's still not working. From my API, the only thing being logged is "undefined". Below are the code snippets: Expo:
const jwt = await Storage.getAccessToken();
if (!jwt) {
throw new Error("No JWT available!");
}

console.log(jwt);

const response = await fetch(
`${process.env.EXPO_PUBLIC_CLOUDFLARE_API_URL}/test`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${jwt}`,
},
}
);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = (await response.json());
const jwt = await Storage.getAccessToken();
if (!jwt) {
throw new Error("No JWT available!");
}

console.log(jwt);

const response = await fetch(
`${process.env.EXPO_PUBLIC_CLOUDFLARE_API_URL}/test`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${jwt}`,
},
}
);

if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}

const data = (await response.json());
Express API:
router.get("/test", protectRoute, getUser, (req, res) => {
const user = (req as any).user as UserType;

if(!user) throw new Error("User is undefined");

console.log("USER: ", user);

res.status(200).json("success");
})
router.get("/test", protectRoute, getUser, (req, res) => {
const user = (req as any).user as UserType;

if(!user) throw new Error("User is undefined");

console.log("USER: ", user);

res.status(200).json("success");
})
Oli - Kinde
Oli - Kinde8d ago
Hi @Masini,
the only thing being logged is "undefined"
Is this the case in your Express API or Expo app? Or Both? It seems like the issue might be related to how the JWT is being handled on the server side, particularly within the protectRoute and getUser middlewares. Here are a few steps you can take to troubleshoot and resolve the issue: 1. Verify JWT Extraction: Ensure that the protectRoute middleware is correctly extracting the JWT from the Authorization header. You can add a console log in this middleware to check if the JWT is being correctly parsed. 2. Check JWT Validation: Confirm that the JWT is being validated correctly in the protectRoute middleware. If there's an issue with the validation (e.g., wrong secret key, expired token), it might not pass the user info to the getUser middleware. 3. Middleware Configuration: Make sure that the middlewares are correctly set up to pass the user information from protectRoute to getUser. There might be an issue in the middleware chain that prevents the user data from being attached to the request object. 4. Logging and Error Handling: Enhance logging in both middlewares to capture more detailed information about the flow and any potential errors. This can help identify where the process breaks. 5. Environment Variables: Double-check your environment variables on both the client and server sides. Ensure that all necessary variables are correctly configured and accessible where needed. 6. Request Headers: On the client side, ensure that the headers are set correctly in the fetch request. It looks correct in your snippet, but it's worth double-checking for any typos or issues. 7. Test with Static Token: Temporarily replace the dynamic token retrieval with a static valid token in your client-side code to rule out any issues with how the token is being fetched or stored. Here's an example of how you might add logging to your protectRoute middleware:
const protectRoute = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'No token provided' });
}

const token = authHeader.split(' ')[1];
console.log('Extracted Token:', token);

// Add your JWT validation logic here
// Log the result of the validation
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log('Decoded JWT:', decoded);
req.user = decoded;
next();
} catch (error) {
console.error('JWT Validation Error:', error);
return res.status(401).json({ error: 'Invalid token' });
}
};
const protectRoute = (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return res.status(401).json({ error: 'No token provided' });
}

const token = authHeader.split(' ')[1];
console.log('Extracted Token:', token);

// Add your JWT validation logic here
// Log the result of the validation
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log('Decoded JWT:', decoded);
req.user = decoded;
next();
} catch (error) {
console.error('JWT Validation Error:', error);
return res.status(401).json({ error: 'Invalid token' });
}
};
By following these steps, you should be able to pinpoint the issue and get your authentication flow working correctly. If the problem persists, you may need to review the configuration of your JWT library or the specifics of how your JWTs are issued. Please let me know if you are still experiencing issues.
Want results from more Discord servers?
Add your server
More Posts
After calling createOrg({ org_name: 'name' }) a call to /token that returns 500I am manually calling createOrg as part of the onboarding flow in my react app and I have noticed thCustom properties added to the wrong tokenI added custom properties to the id token, but I see them added to the access token instead of the iExtending KindeIdToken type to include the `organizations` claimI added an `organizations` claim to the id token and would like TypeScript to know about it so I couuseKindeAuth isLoading doesn't change to falseTrying to get the org in a client component, but `isLoading` does not change to `false`. What am I Getting organization handle in id token claimsWhen user visits `myapp.com/org-handle`, I'd like to check whether the user has access to the `org-hPermission doesn't workI added an "admin" permission to a user. However, `await getPermissions()` returns no permissions: `How to sign the user out when /logout is visited?In my Next.js App Router application, I'd like to automatically sign the user out when the user visiShould I include user model in database schema? And how to handle users registering their business?Hi, how should I handle database schema while using Kinde? Should I try for creating user model in misAuthenticated === false vs user === nullIs there any difference (maybe performance?) between: ``` import { getKindeServerSession } from "@kiMulti-factor auth using SMS - Where is the user's phone number stored?I enabled "Multi-factor authentication". The first time I logged in using Google, I was asked to entProtecting routes in Next.js App Router middlewareDocs at https://kinde.com/docs/developer-tools/nextjs-sdk/#protect-routes-using-middleware mention: User's first and last names are overridden when user logs in using GoogleAfter user signs up using Google, their first and last names in KindeUser are pre-populated from the`await getUser()` doesn't return the first and last nameIn my Next.js App Router application, in a page component, I get the user: ``` const { getUser } = gDoes Kinde provide Login/SignUp components for custom Login/SignUp pages?I'd like to have a custom `myapp.com/login` page in Next.js App Router application, and render a LogSubscribe Form...React[solved] Hi, I want to include the subscribe form in a react (docusaurus) site. I want to have a buRevoke all access tokens from KindeHi, May I know how to revoke all access tokens from Kinde?