Authentication and Authorisation: Tokens, OIDC and RBAC

Separate identity, session renewal and resource access, including organisation-scoped authorization.

What problem does this solve?

A valid login does not entitle a user to every record. Multi-tenant APIs need both a trustworthy identity and an authorization decision tied to the requested organisation and action.

What is it?

Authentication establishes identity. Authorization decides permitted actions. A JWT is a token format, OAuth is an authorization framework and OIDC adds an identity layer. RBAC maps roles to capabilities, but roles still need resource and tenant context.

Mental model

Identity is the name on a badge; authorization is whether that badge opens this particular door now. An ID token tells a client about authentication. An access token is intended for a resource server; they are not interchangeable.

How it works internally

Verify access-token signatures using an allowed algorithm and trusted keys, plus issuer, audience and expiry. Refresh rotation replaces a presented renewal token and invalidates its prior use according to the session policy. HttpOnly restricts JavaScript access to a cookie but does not itself prevent CSRF. OAuth/OIDC browser flows need state, PKCE and appropriate nonce handling rather than a hand-built login shortcut.

Production example

For /organisations/:id/products, derive the user from a verified credential, load current membership and check the product belongs to that organisation. Never trust a role or tenant header supplied directly by the browser.

Node.js / TypeScript implementation

A pure policy function after identity and membership verification. It illustrates scoped permissions; it is not a JWT verifier or a substitute for scoped SQL queries.

type Role = "ORG_ADMIN" | "OPERATOR" | "VIEWER";
type Membership = { userId: string; orgId: string; role: Role };
function canEditProduct(userId: string, orgId: string, m: Membership) {
  return m.userId === userId && m.orgId === orgId
    && m.role === "ORG_ADMIN";
}
console.log(canEditProduct("u1", "org-a", {
  userId: "u1", orgId: "org-b", role: "ORG_ADMIN"
})); // false

Common mistakes

Decoding a JWT is not verification. Frontend role checks do not secure an API. Long-lived access tokens complicate revocation. Logging refresh tokens or storing them in broadly accessible browser storage expands exposure.

Performance / reliability considerations

Define key rotation, membership changes and session revocation behavior. Keep password hashing work bounded and rate-limit authentication. Decide what reuse of a rotated refresh token does to the token family; implement rotation atomically and test concurrent refreshes.

Interview questions

How do OAuth and OIDC differ? Why is an ID token unsuitable as a general API credential? How does refresh rotation detect replay? Why is a role alone insufficient in a multi-tenant API?

Quick Revision

Authenticate identity, authorize each resource action. Verify JWT signature and claims. Keep access and ID token audiences distinct. Rotate refresh sessions atomically. HttpOnly is not CSRF protection. Enforce tenant scope in policies and queries. Treat role changes, key rotation and revocation as explicit lifecycle concerns.

Further reading

OpenID Connect Core ↗

NestJS: authorization ↗