Quick start
Machine-to-Machine (M2M)
If you’re using org-scoped machine-to-machine (M2M) apps, Kinde will automatically include a trusted org_code
claim in the token. You can then enforce access control in your own APIs using this claim.
You should validate org_code
in any API route or resource that is tenant-specific, such as:
/orgs/:org_code/users
/reports/:org_code/usage
If the token’s org doesn’t match the route or request context, you should reject the request.
When you receive a token, decode it and check:
org_code
org_code
in the token matches the organization being accessedconst jwt = require("jsonwebtoken");function verifyOrgAccess(req, res, next) { const authHeader = req.headers.authorization; const token = authHeader?.split(" ")[1]; if (!token) return res.status(401).send("Missing token"); // If Kinde is **not** validating the token for you, // verify the signature instead of a raw decode. // const PUBLIC_KEY = ... // fetch from /.well-known/openid-configuration const decoded = jwt.verify(token, PUBLIC_KEY, {algorithms: ["RS256"]}); // Check for required claims if (!decoded?.org_code) return res.status(403).send("Token not scoped to an organization"); const orgFromRoute = req.params.org_code; if (decoded.org_code !== orgFromRoute) { return res.status(403).send("Token does not match organization"); } next();}
Then apply the middleware:
app.get("/orgs/:org_code/users", verifyOrgAccess, (req, res) => { // safe to fetch users for this org});
https://<your-subdomain>.kinde.com/.well-known/openid-configuration
org_code
as a binding contract — never override it with user inputIf the token has no org_code
, treat it as not authorized to access org-specific resources unless explicitly allowed.
You may choose to: