Skip to main content

AuthX-Identity

Python PyPI Downloads Build Coverage License GitHub Release GitHub Stars

A standalone OpenID Connect (OIDC) identity microservice, built with FastAPI, plus a small Django client for services that need to talk to it.

Maintained by DjangoPlay.


Contents

What is AuthX

AuthX is a standards-compliant OIDC identity provider. It:

  • Issues signed JWT access tokens and refresh tokens
  • Exposes public OIDC endpoints (/token, /userinfo, /jwks, /.well-known/openid-configuration)
  • Exposes an internal API (/internal/identities) for trusted services to create and look up identities
  • Supports email/password and SSO (Google, Apple) identity providers
  • Is stateless and horizontally scalable — any instance can validate any token, no shared session state

What's in this package

pip install authx-identity gives you two things bundled into one distribution:

Package Purpose You need it if...
authx The FastAPI microservice itself — DB models, Alembic migrations, API routes You're running AuthX as its own deployed service
authx_client A small Django client: create/look up identities over the internal API, verify AuthX JWTs locally You have a Django app that consumes a running AuthX instance

These ship together so a single pip install covers both sides, but each has its own dependencies:

pip install authx-identity            # microservice only
pip install "authx-identity[django]"  # adds Django, for the client

If you only need the client, you don't need to run the microservice's stack (Postgres, Alembic, etc.) yourself — just point it at wherever AuthX is already deployed.

Architecture

┌───────────────────────────────────┐
│  Client (browser, mobile, CLI)    │
│  → POST /token       (login)      │
│  → GET  /userinfo    (who am I?)  │
└────────────────┬──────────────────┘
                 │ JWT
     ┌───────────▼──────────────────┐
     │            AuthX              │
     │   FastAPI + PostgreSQL        │
     │   Issues & validates JWTs     │
     └───────────┬──────────────────┘
                 │ Internal API (X-Service-Token)
     ┌───────────▼──────────────────┐
     │         DjangoPlay             │
     │   Trusts AuthX JWTs            │
     │   Calls authx_client for       │
     │   identity create/lookup       │
     └────────────────────────────────┘

AuthX owns identity (email, password, SSO links). The consuming app (e.g. DjangoPlay) owns its own domain data and links to an identity by ID.

Quickstart: running the microservice

  1. Clone this repo and copy the environment template:

    cp env.example .env
    
  2. Generate an RSA keypair for signing JWTs — do not reuse any keypair that has ever been committed to source control:

    openssl genrsa -out private.pem 2048
    openssl rsa -in private.pem -pubout -out public.pem
    
  3. Inline both keys into .env as JWT_PRIVATE_KEY / JWT_PUBLIC_KEY (single line, literal \n between lines — see the comment in env.example for the exact awk command).

  4. Configure all required JWT settings:

    JWT_ISSUER=https://auth.example.com
    JWT_AUDIENCE=your-application
    

    JWT_ISSUER must identify the actual AuthX deployment. JWT_AUDIENCE must identify the application or API for which the token is intended. Neither value has a DjangoPlay-specific default.

  5. Fill in the remaining .env values: database credentials, INTERNAL_SERVICE_TOKEN, and CORS_ORIGINS.

  6. Start everything:

    docker compose up
    

    Migrations run automatically on startup. The service listens on http://localhost:8100 by default.

  7. Confirm it's up:

    curl http://localhost:8100/.well-known/openid-configuration
    

Quickstart: using the Django client

Install with the django extra so Django itself comes along:

pip install "authx-identity[django]"

Configure the required AuthX settings in your Django project's settings.py (see Configuration below), then:

from authx_client import AuthXClient, AuthXJWT, AuthXConflictError

# Server-to-server: create or look up identities
client = AuthXClient()

try:
    identity = client.create_identity(
        email="user@example.com",
        username="user",
        password="...",
    )
except AuthXConflictError:
    identity = client.get_by_email("user@example.com")

# Verify a JWT locally — no network call needed per request
payload = AuthXJWT.decode(token)
identity_id = AuthXJWT.get_identity_id(token)

AuthXClient is synchronous, since Django views and services typically are. It talks to AuthX's /internal/* endpoints using a shared service token — never expose that token to end users or client-side code.

API reference

Public OIDC endpoints

Method Path Description
GET /.well-known/openid-configuration OIDC discovery document
GET /jwks Public keys for JWT verification
POST /token Issue access + refresh token
POST /token/refresh Refresh access token
GET /userinfo Get identity info from a token

Internal endpoints (require X-Service-Token)

Method Path Description
POST /internal/identities Create identity
GET /internal/identities/{id} Get identity by ID
GET /internal/identities/by-email/{email} Look up by email
GET /internal/identities/by-sso/lookup Look up by SSO provider + ID
PATCH /internal/identities/{id} Update identity fields
DELETE /internal/identities/{id} Soft delete identity

Internal endpoints are meant for trusted backend services only — never expose them publicly without the service token check in front.

Configuration

Microservice (.env)

All variables the FastAPI service reads are listed in env.example, grouped by purpose:

  • ApplicationAPP_ENV, APP_HOST, APP_PORT, APP_BASE_URL
  • DatabaseDATABASE_URL (async, for the app), DATABASE_URL_SYNC (for Alembic)
  • JWT signingJWT_PRIVATE_KEY, JWT_PUBLIC_KEY, JWT_ALGORITHM, JWT_ACCESS_TOKEN_EXPIRE_MINUTES, JWT_REFRESH_TOKEN_EXPIRE_DAYS, JWT_ISSUER, JWT_AUDIENCE
  • Internal authINTERNAL_SERVICE_TOKEN, shared with consumers that call /internal/*
  • CORSCORS_ORIGINS, comma-separated

JWT_ISSUER and JWT_AUDIENCE are required settings. There are no DjangoPlay-specific defaults for either value.

JWT_ISSUER must be an HTTP(S) URL without a query string or fragment. HTTPS is required when APP_ENV=production.

JWT_AUDIENCE is an application/API identifier and does not need to be a URL.

Copy env.example to .env and fill in real values; never commit .env or any key material.

Django client settings

Set these in the consuming Django project's settings.py:

AUTHX_BASE_URL = "http://authx:8100"
AUTHX_SERVICE_TOKEN = "..."        # must match the microservice's INTERNAL_SERVICE_TOKEN
AUTHX_PUBLIC_KEY = "..."           # optional — omit to auto-fetch from /jwks on first use
AUTHX_JWT_ALGORITHM = "RS256"
AUTHX_JWT_AUDIENCE = "your-application"
AUTHX_JWT_ISSUER = "https://auth.example.com"

AUTHX_JWT_AUDIENCE and AUTHX_JWT_ISSUER must exactly match the corresponding JWT_AUDIENCE and JWT_ISSUER configured in the AuthX service.

There is no DjangoPlay-specific fallback for either value. If either setting is missing from the consuming Django application, JWT verification will fail instead of silently using an incorrect issuer or audience.

AUTHX_BASE_URL and AUTHX_SERVICE_TOKEN remain required for the internal API client. AUTHX_PUBLIC_KEY and AUTHX_JWT_ALGORITHM retain their existing optional/default behavior.

JWT verification

Consumers should:

  1. Fetch public keys from /jwks once and cache them (or set AUTHX_PUBLIC_KEY directly to skip the fetch).
  2. Verify JWT signatures locally — no call to AuthX needed per request.
  3. Validate both the iss and aud claims against the explicitly configured AUTHX_JWT_ISSUER and AUTHX_JWT_AUDIENCE.
  4. Only call /userinfo for server-to-server lookups when you don't already have a JWT in hand.

The issuer identifies the AuthX deployment that issued the token. The audience identifies the application or API for which the token is intended.

Running in production

docker compose -f docker-compose.yml -f docker-compose.fullstack.yml up -d

Make sure .env has production-grade secrets (fresh JWT keypair, strong INTERNAL_SERVICE_TOKEN) and that /internal/* is not reachable from outside your private network.

In production, JWT_ISSUER must use HTTPS and must identify the actual public issuer URL for the AuthX deployment.

Development

pip install -e ".[dev]"
pytest
ruff check .

See CHANGELOG.md for release history.

License

MIT — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

authx_identity-1.0.1.tar.gz (23.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

authx_identity-1.0.1-py3-none-any.whl (24.9 kB view details)

Uploaded Python 3

File details

Details for the file authx_identity-1.0.1.tar.gz.

File metadata

  • Download URL: authx_identity-1.0.1.tar.gz
  • Upload date:
  • Size: 23.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for authx_identity-1.0.1.tar.gz
Algorithm Hash digest
SHA256 68f0f49e3a69ec67eaaf3c9526726f7280e49186ae8c81ddfe7e18c629a04639
MD5 8194104b0dee7ad6181232b57ce4e8a5
BLAKE2b-256 97a11965ddb521a2e754ed63deb66342562a5e058c256fbf181465f0ea00f07f

See more details on using hashes here.

File details

Details for the file authx_identity-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: authx_identity-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 24.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for authx_identity-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d70a15c9c7c22e48cc9a5118b658e45f40e85b31d7a88b09f324e867816f4dc3
MD5 246e22a2d5178a75b1c8620e29d668b7
BLAKE2b-256 18e99bb0794223451a4ac0b2b57d7e6b337423c69a5839c6cbee54ff4d58b4ba

See more details on using hashes here.

Release history Release notifications | RSS feed

1.1.1

2 files

1.1.0

2 files

This release

1.0.1 This release

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page