A7C

JWT, OAuth2, Entra ID, CORS/CSRF, and Kubernetes RBAC configured for production setups

We configured production Django APIs with OAuth2, JWT, and CORS/CSRF enforcement to match client requirements instead of the shipped defaults. SSO runs through Azure Entra ID via Django Allauth. Kubernetes clusters use RBAC and namespace isolation.

JWT, OAuth2, Entra ID, CORS/CSRF, and Kubernetes RBAC configured for production setups

Problem

Production systems across several projects needed proper authentication and access control. The defaults that ship with Django and Kubernetes stay permissive enough to be dangerous once a system handles real users and real data.

Approach

JWT token management with correct expiry, rotation, and revocation patterns. OAuth2 flows configured per use case: client credentials for service-to-service calls, authorization code for user-facing apps. CORS and CSRF policies tightened to the origins each app needs. Azure Entra ID SSO integrated via Django Allauth. Kubernetes clusters configured with RBAC policies and namespace isolation per environment.

Architecture

Django APIs with JWT auth via djangorestframework-simplejwt, OAuth2 via Django OAuth Toolkit. Azure Entra ID as identity provider, integrated through Django Allauth social login. CORS configured with explicit allowed origins and methods. Kubernetes RBAC with role bindings per service account and namespace-scoped policies.

Outcome

Production APIs and clusters now run defence-in-depth authentication: no wildcard CORS origins, no default service account permissions, no unsigned tokens. Entra ID SSO cut credential management overhead and centralised identity under the client's existing Azure tenant.

Why defaults are not enough

Django ships permissive defaults on purpose: they speed up development and assume no specific deployment model. Kubernetes does the same, and a freshly provisioned cluster lets service accounts do more than they should. In production, against real users and real data, these defaults are unacceptable exposure. This work closes the gap between "it works" and "it's configured correctly."

JWT and OAuth2

JWT configuration covered token expiry windows, refresh token rotation, and revocation on logout, the parts that are easy to get wrong and rarely tested. We configured OAuth2 flows per use case: client credentials for internal service-to-service calls (no user context, short-lived tokens, scoped to specific endpoints), and authorization code with PKCE for user-facing web clients. We defined scopes explicitly instead of leaning on broad defaults.

CORS and CSRF

Cross-origin policies default to either blocking everything (development pain) or allowing everything (production risk). The correct configuration sets explicit allowed origins matching the frontend deployment URLs, combined with CSRF enforcement on all state-mutating endpoints. Cookie-based session auth and token-based auth carry different CSRF exposure profiles, so we configured each project to its own auth mechanism instead of applying one policy across all of them.

Azure Entra ID SSO

We integrated Azure Entra ID (formerly Azure AD) as the identity provider for client projects running within Microsoft-managed tenants. The Django Allauth integration covered the OAuth2 / OIDC flow, group-based permission mapping, and token validation against the tenant's JWKS endpoint. This puts identity management on the client's existing Azure infrastructure and removes the need for a separate user database.

Kubernetes RBAC

We configured the Kubernetes clusters with role-based access control at the service account level: each deployment runs under a dedicated service account with only the permissions it needs. Namespace isolation separates environments (staging, production) and blocks lateral movement between workloads. We reviewed the cluster roles and removed default bindings that grant broader access than any workload in the cluster needs.

© 2017 - 2026 · A7C