Tokens
What is inside the access token, how a backend verifies it, and what the refresh token is.
Access token
A JWT signed with HS256 using JWT_ACCESS_SECRET, the same secret and the same { name, email, _id } payload every Corpland backend already checks. Tokens from the redirect flow add a few claims.
| Claim | Example | Meaning |
|---|---|---|
_id | 6aca9bf9b50f1fec97df56c0 | The Corpland ID user id. Use it as your user key. |
name | Ama Mensah | Display name at the time of sign in. |
email | ama@acme.com | Verified email. |
sid | 3f1c... | The session family. Every refresh in one sign in shares it. |
cid | corpland-content | The client that asked for the token. |
aud | corpland-content | Same as cid, as a standard audience. |
vid | 6aca9bfeb50f1fec97df56d6 | The venture picked at sign in. Missing when none was picked. |
iss | https://... | The ID API base address. |
iat, exp | Issued and expiry times. exp is 15 minutes after iat. |
Verifying on your backend
Existing backends need no change: jwt.verify(token, JWT_ACCESS_SECRET) still works. To reject tokens minted for another Corpland app, check the audience too.
const jwt = require("jsonwebtoken");
const verifyCorplandToken = (token) =>
jwt.verify(token, process.env.JWT_ACCESS_SECRET, {
audience: "corpland-content",
clockTolerance: 60,
});Allow 60 seconds of clock leeway. Never trust vid alone for access to venture data: confirm the membership with the internal API, which is cached and fast.
The move to RS256 with a public JWKS is planned. When it lands, only the verify call changes.
Refresh token
An opaque random string, not a JWT. Corpland ID stores only its hash. Keep it where only your app can read it, and send it only to POST /oauth/token and POST /oauth/revoke.
| Rule | Value |
|---|---|
| Rotation | Every use returns a new refresh token |
| Grace for parallel tabs | 10 seconds after rotation |
| Reuse after the grace | The whole family is revoked, error token_reused |
| Idle lifetime | 30 days |
| Absolute lifetime | 90 days from the first sign in |
| Bound to | One client. Another client id gets invalid_grant. |
People can end any app's sessions from Connected apps in their account portal. Your next refresh then fails with invalid_grant, and you send them to sign in again.