JAVA Contents

authn/authz, JWT basics

Implement authentication and authorization basics for Java web services: JWT validation, claim hygiene, roles vs permissions and common production pitfalls.

On this page

Authn vs Authz: Stop Mixing Them

Authentication (authn) answers: Who are you? Authorization (authz) answers: What are you allowed to do? Production teams routinely mix these and ship security bugs. A valid identity does not automatically mean permission.

Incident Scenario: Privilege Escalation via Missing Authorization

A service validated JWT properly. Then it assumed: If token is valid, user can access any resource. Endpoint: GET /accounts/{id} Attacker used a valid token for their own account and changed the id to someone else. Service returned data because it never checked ownership. Root cause: Authentication implemented, authorization missing. This is one of the most common production authorization failures.

JWT Basics That Matter

A JWT is: - header - payload (claims) - signature It is not encrypted by default. Anyone can read the payload. Never put secrets in JWT claims. JWT gives you: - integrity (if properly signed and verified) - portability JWT does not automatically give: - revocation - session control - authorization correctness

Anti-Pattern: Trusting Unverified Tokens

If you decode without verifying signature, you are trusting attacker input. Also dangerous: - accepting tokens with alg=none - algorithm confusion issues - accepting wrong issuer or audience - skipping exp validation Production rule: Validate token signature and critical claims every time.

Correct JWT Validation Requirements

On every request, verify: - signature with correct key - algorithm allowlist (only what you support) - issuer (iss) - audience (aud) - expiration (exp) - not before (nbf) if used - clock skew handling - subject (sub) presence and format JWT validation is not just signature validation.

Key Management and Rotation

If you use symmetric keys (HMAC): - key compromise breaks everything - rotation is harder across services If you use asymmetric keys (RSA/ECDSA): - private key signs, public key verifies - easier to distribute verification keys Use a JWKS endpoint for key distribution when appropriate. Support key rotation by key id (kid), but do not trust kid blindly without controlling source of keys.

Token Transport

Best practice: Authorization: Bearer <token> Avoid putting tokens in: - query parameters (leak in logs and caches) - local storage in browsers (XSS risk) depending on app context For browser apps, consider secure HTTP-only cookies and CSRF protections. Do not cargo-cult JWT without understanding tradeoffs.

Roles vs Permissions

Roles: Coarse-grained groupings, often organizational. Permissions: Fine-grained actions (order.read, order.refund). Production reality: Roles alone are too blunt for complex systems. Permissions are easier to audit and reason about. Avoid encoding complex authorization logic in controller annotations only. Centralize authorization decisions where possible.

Authorization Patterns

Common patterns: - Ownership checks (resource belongs to user) - RBAC (role-based access control) - ABAC (attribute-based access control) - Policy-based checks (permissions evaluated by policy engine) Ownership check example logic: - token sub must match resource owner - admin role may bypass with explicit policy Never rely on client-provided userId fields for authorization.

Service-to-Service Authentication

Do not reuse end-user JWTs for internal service calls without care. Service-to-service auth should use: - mTLS - service identity tokens - short-lived credentials This reduces blast radius if a token is leaked.

Expiration, Revocation, and Logout Reality

JWT is stateless. That means: - revocation is hard - logout is not automatic Mitigations: - short-lived access tokens - refresh tokens stored securely - server-side revocation list for critical cases - rotate signing keys when compromise occurs If you need strict session control, consider stateful sessions.

Logging and Observability

Log: - auth failures (rate-limited) - invalid issuer/audience attempts - expired token counts Never log: - full tokens - raw Authorization header Log token identifiers only if needed and safe.

Checklist

- Separate authentication from authorization explicitly - Validate JWT signature and critical claims (iss, aud, exp) - Use algorithm allowlist, reject alg=none - Do not store secrets in JWT payload - Use Authorization header, avoid query tokens - Implement ownership checks for resources - Prefer permissions over roles for fine-grained control - Plan key rotation and token lifetime strategy - Do not log tokens or sensitive auth headers - Design service-to-service auth separately from user auth If your system only authenticates but does not authorize, you did not build security. You built a login page.