authx-identity / Architecture / AuthX — Security Architecture
DocsAuthx-IdentityArchitectureAuthX — Security Architecture

AuthX — Security Architecture

AuthX is the identity authority for DjangoPlay authentication.

10 min readApplies to v1.1.1
On this page ▾
  1. 1. Security Architecture Overview
  2. AuthX
  3. DjangoPlay

The security model is based on:

  • Password hashing
  • RSA-signed JWTs
  • Issuer and audience validation
  • Stateful refresh-token control
  • Backend service authentication
  • Restricted CORS origins
  • Strict separation of AuthX and DjangoPlay credentials
  • Protection of private signing keys

1. Security Architecture Overview

The important security boundary is that AuthX owns identity credentials and JWT signing, while consuming applications only receive what they need to authenticate and verify users.


2. Password Security

AuthX does not store plaintext passwords.

The identity record stores a password hash rather than the original password.

text
User Password
      │
      ▼
Password Hashing
      │
      ▼
password_hash
      │
      ▼
AuthX PostgreSQL

The password credential therefore remains inside AuthX.

DjangoPlay does not need to reproduce AuthX's password storage or hashing logic.

AuthX is responsible for:

  • Receiving passwords during authentication workflows
  • Hashing passwords
  • Storing password hashes
  • Verifying supplied passwords against stored hashes

The application database should never contain plaintext AuthX passwords.


3. JWT Signing Architecture

AuthX is the sole JWT signing authority for AuthX identity tokens.

text
                    signs
AuthX ─────────────────────────► JWT
  │                               │
  │ JWT_PRIVATE_KEY               │
  │                               │
  │                               ▼
  │                         DjangoPlay
  │                               │
  │                               │ verifies
  │                               ▼
  └──────────────────────── AuthX Public Key

AuthX uses an RSA key pair and the configured signing algorithm:

text
JWT_ALGORITHM=RS256

The private key is configured through:

text
JWT_PRIVATE_KEY

The corresponding public key is configured through:

text
JWT_PUBLIC_KEY

The private key belongs exclusively to AuthX.

DjangoPlay and other consumers must never receive the AuthX private signing key.


4. RSA Key Protection

AuthX's RSA private key is one of the most sensitive credentials in the system.

text
JWT_PRIVATE_KEY
       │
       ▼
     AuthX
       │
       │ signs
       ▼
     JWT

The public key can safely be distributed to consumers for signature verification.

The private key must:

  • Remain server-side
  • Never be exposed to browser clients
  • Never be committed to Git
  • Never be included in frontend assets
  • Never be shared with consuming applications
  • Be replaced if it is suspected of being compromised

A fresh RSA key pair should be generated for a new deployment.

Example:

bash
openssl genrsa -out jwt_private.pem 2048

openssl rsa \
  -in jwt_private.pem \
  -pubout \
  -out jwt_public.pem

Validate the private key:

bash
openssl rsa -in jwt_private.pem -check -noout

Expected:

text
RSA key ok

Verify that the public key corresponds to the private key:

bash
openssl rsa \
  -in jwt_private.pem \
  -pubout \
  -outform PEM | diff - jwt_public.pem

No output and exit status 0 indicate that the public and private keys match.

When storing PEM values in environment configuration, preserve PEM line boundaries using literal \n sequences.

Do not introduce arbitrary backslashes into the Base64 key material.


5. JWT Claims

AuthX-issued identity JWTs contain standard identity and token metadata.

The important security claims include:

text
sub
iss
aud
iat
exp
jti
type

Identity access tokens additionally carry identity attributes such as:

text
email
username
is_verified
is_staff
is_superuser

The token type distinguishes access and refresh tokens:

text
type=access
type=refresh

The jti claim provides a unique JWT identifier and is particularly important for token tracking and refresh-token state.


6. Issuer Validation

AuthX identifies itself as the JWT issuer using:

text
JWT_ISSUER

The current DjangoPlay deployment uses:

text
JWT_ISSUER=https://auth.djangoplay.org

The issuer identifies the identity authority asserted by the token.

It is not necessarily the network address used to reach the AuthX process.

For example:

text
AuthX runtime:

APP_BASE_URL=http://127.0.0.1:8100


JWT identity authority:

JWT_ISSUER=https://auth.djangoplay.org

These are intentionally different concepts.

Consumers should validate the iss claim against their configured AuthX issuer.

This prevents a token issued by an unexpected authority from being silently accepted.


7. Audience Validation

AuthX also uses:

text
JWT_AUDIENCE

The current DjangoPlay configuration uses:

text
JWT_AUDIENCE=djangoplay

The audience identifies the application for which the JWT is intended.

The consumer should verify the aud claim as well as the signature and issuer.

Conceptually:

text
JWT
 │
 ├── Signature ──────► valid AuthX signature?
 │
 ├── iss ────────────► expected AuthX issuer?
 │
 └── aud ────────────► expected application?

A valid RSA signature alone is therefore not sufficient.


8. Access Tokens and Refresh Tokens

AuthX separates short-lived access tokens from longer-lived refresh tokens.

The configured defaults are:

text
Access token:
60 minutes

Refresh token:
30 days

These values are controlled by:

text
JWT_ACCESS_TOKEN_EXPIRE_MINUTES
JWT_REFRESH_TOKEN_EXPIRE_DAYS

Access tokens are intended for normal authenticated API access.

Refresh tokens are used to obtain new access tokens and therefore require additional server-side protection.


9. Refresh Token State

Refresh tokens are stateful.

AuthX maintains refresh-token records in PostgreSQL so that refresh tokens can be controlled after issuance.

Conceptually:

text
Refresh JWT
    │
    │ jti
    ▼
AuthX
    │
    ▼
Refresh Token Record
    │
    ├── active
    ├── revoked
    └── expired

This allows AuthX to support server-side revocation and refresh-token lifecycle management.

Access tokens, by contrast, are designed to be validated cryptographically without requiring a database lookup for every request.


10. Internal Service Authentication

AuthX exposes internal identity-management operations for trusted backend consumers.

DjangoPlay authenticates these requests using:

text
X-Service-Token

The configured credential is:

text
AUTHX_SERVICE_TOKEN

The security boundary is:

text
DjangoPlay
    │
    │ X-Service-Token
    ▼
AuthX /internal/*

The service token is a backend credential.

It must never be:

  • Embedded in frontend JavaScript
  • Sent by browser clients
  • Stored in browser storage
  • Included in public documentation with its real value
  • Committed to source control

The same service credential must be configured consistently on the DjangoPlay and AuthX sides.


11. Public vs Internal API Boundary

AuthX separates public authentication functionality from internal identity-management functionality.

text
                    AuthX
                      │
          ┌───────────┴───────────┐
          │                       │
          ▼                       ▼
   Public Authentication     Internal APIs
          │                       │
          │                       │ X-Service-Token
          ▼                       ▼
   Browser / Clients          DjangoPlay

Public clients should not receive the credentials required to access internal identity-management endpoints.

The internal service token establishes a backend-to-backend trust boundary.


12. CORS Protection

AuthX supports explicit browser-origin configuration through:

text
CORS_ORIGINS

Development may contain local DjangoPlay origins such as:

text
https://app.lvh.me:9999
http://app.lvh.me:3333

Production should contain only the browser origins that actually need to communicate with AuthX.

Example production configuration:

text
CORS_ORIGINS=https://app.djangoplay.org,https://issues.djangoplay.org

CORS configuration should not be treated as authentication.

It controls which browser origins may make cross-origin requests; it does not replace JWT validation or backend service authentication.

Do not unnecessarily add:

text
*

or unrelated production origins.


13. Credential Separation

DjangoPlay and AuthX deliberately maintain separate credentials.

text
DjangoPlay
    │
    ├── DB_PASSWORD
    ├── DATABASE_URL
    └── JWT_SIGNING_KEY

versus:

text
AuthX
    │
    ├── POSTGRES_PASSWORD
    ├── DATABASE_URL
    ├── DATABASE_URL_SYNC
    ├── JWT_PRIVATE_KEY
    ├── JWT_PUBLIC_KEY
    ├── JWT_ISSUER
    ├── JWT_AUDIENCE
    └── AUTHX_SERVICE_TOKEN

These credentials must not be confused.

In particular:

text
DB_PASSWORD          != POSTGRES_PASSWORD

JWT_SIGNING_KEY      != JWT_PRIVATE_KEY

APP_BASE_URL         != JWT_ISSUER

AUTHX_SERVICE_TOKEN  != database password

The current configuration explicitly uses POSTGRES_PASSWORD for the AuthX PostgreSQL role; there is no AUTHX_DB_PASSWORD configuration key.


14. AuthX Configuration Boundary

For a DjangoPlay deployment, AuthX configuration is maintained separately from the main DjangoPlay secrets.

text
~/.dplay/
│
├── .secrets
│      │
│      └── DjangoPlay secrets
│
└── .authx
       │
       └── AuthX configuration

The AuthX configuration contains its own:

  • Database credentials
  • JWT signing keys
  • JWT configuration
  • Service authentication credential
  • CORS configuration

This separation reduces accidental credential mixing between the two systems.


15. Database Security

AuthX stores identity data in its own PostgreSQL database.

The database contains sensitive identity information, including password hashes and refresh-token state.

The AuthX PostgreSQL credentials are:

text
POSTGRES_USER
POSTGRES_PASSWORD
POSTGRES_DB

and the corresponding connection strings:

text
DATABASE_URL
DATABASE_URL_SYNC

The AuthX database credentials are separate from DjangoPlay's database credentials.

Database access should therefore remain restricted to the AuthX runtime and trusted administrative operations.


16. Security Boundary Summary

The major trust boundaries are:

Boundary Protection
Client → AuthX Authentication protocol and token issuance
Backend → AuthX X-Service-Token
AuthX → PostgreSQL Restricted database credentials
AuthX → JWT RSA private-key signing
Consumer → JWT Public-key signature verification
JWT → Consumer Issuer and audience validation
Browser → AuthX Explicit CORS origins
AuthX configuration Separate .authx deployment configuration

17. Security Rules

The following rules should be treated as mandatory:

  1. Never store plaintext passwords.
  2. Never expose JWT_PRIVATE_KEY.
  3. Never expose AUTHX_SERVICE_TOKEN to browser clients.
  4. Never commit private keys or service credentials to Git.
  5. Use RS256 for the current AuthX JWT architecture.
  6. Validate JWT signature, issuer, audience, expiration, and token type as appropriate for the operation.
  7. Keep AuthX database credentials separate from DjangoPlay credentials.
  8. Use explicit production CORS origins.
  9. Generate a fresh RSA key pair for a new deployment.
  10. Rotate compromised private keys and service tokens.
  11. Keep AuthX identity persistence inside AuthX rather than duplicating credential-management logic in DjangoPlay.
  12. Treat AuthX as the identity and JWT-signing authority.

18. Security Responsibilities

The security responsibilities are deliberately divided between AuthX and its consumers.

AuthX

AuthX is responsible for:

  • Password credential protection
  • Identity persistence
  • Password verification
  • JWT signing
  • Refresh-token state
  • JWT issuer and audience configuration
  • Internal service authentication
  • CORS configuration
  • Protection of private signing keys

DjangoPlay

DjangoPlay is responsible for:

  • Securely storing its AuthX service credential
  • Verifying AuthX-issued JWTs
  • Configuring the expected issuer and audience
  • Protecting local application sessions and credentials
  • Enforcing application-level authorization
  • Never exposing AuthX private credentials

This separation ensures that authentication authority and application-level authorization remain distinct concerns.


19. Security Model Summary

AuthX's security model can be summarized as:

text
                AUTHX
                  │
        ┌─────────┼─────────┐
        │         │         │
        ▼         ▼         ▼
   Credentials   JWTs    Internal API
        │         │         │
        ▼         ▼         ▼
     Hashing    RS256   Service Token
                  │
          ┌───────┴───────┐
          │               │
          ▼               ▼
     Private Key     Public Key
       signing       verification
          │               │
          ▼               ▼
        AuthX         Consumers

AuthX therefore provides a dedicated identity security boundary: credentials and signing authority remain inside AuthX, while DjangoPlay and other consumers verify and consume the resulting identity assertions without receiving AuthX's most sensitive secrets.