AuthX — Internal Identity API
The Internal Identity API is the trusted backend interface used by DjangoPlay and other authorized backend consumers to manage identities in AuthX.
On this page ▾
AuthX remains the authoritative identity service. Consuming applications must not implement their own copy of AuthX credential management, password hashing, or identity persistence logic.
The internal API is intentionally separate from the public authentication endpoints.
1. Architecture
flowchart LR
APP["DjangoPlay<br/><small>Backend Application</small>"]
CLIENT["AuthXClient<br/><small>HTTP client</small>"]
AUTH["AuthX<br/><small>Identity Service</small>"]
DB[("AuthX PostgreSQL<br/><small>Identity Store</small>")]
TOKEN["AUTHX_SERVICE_TOKEN<br/><small>Backend credential</small>"]
APP --> CLIENT
CLIENT -->|"X-Service-Token"| AUTH
TOKEN -.->|"Authentication"| AUTH
AUTH --> DB
classDef app fill:#e5f6f1,stroke:#159a7a,stroke-width:2px,color:#075d4b
classDef auth fill:#fceee8,stroke:#d65a2a,stroke-width:2px,color:#7d321c
classDef db fill:#eeeeff,stroke:#5a55c9,stroke-width:2px,color:#403b91
classDef credential fill:#f5f3ed,stroke:#777,stroke-width:1px,color:#444
class APP,CLIENT app
class AUTH auth
class DB db
class TOKEN credential
`The normal communication path is:
DjangoPlay
│
│ AuthXClient
│
│ X-Service-Token
▼
AuthX Internal API
│
▼
Identity Service
│
▼
AuthX PostgreSQL2. Trust Model
The Internal Identity API is not a browser-facing API.
Only trusted backend applications should have access to the service credential.
Browser / Public Client
│
│ NO SERVICE TOKEN
▼
Public AuthX APIs
DjangoPlay Backend
│
│ X-Service-Token
▼
/internal/identities/*The credential is:
AUTHX_SERVICE_TOKENIt must remain server-side and must never be exposed to:
- Browser JavaScript
- HTML
- Mobile clients
- Public API consumers
- Frontend configuration
3. Authentication
Every internal identity request requires:
X-Service-Token: <AUTHX_SERVICE_TOKEN>AuthX validates the supplied token before processing the identity operation.
The same backend credential must be configured on both sides:
DjangoPlay
│
└── AUTHX_SERVICE_TOKEN
│
│ must match
▼
AuthX
│
└── AUTHX_SERVICE_TOKENInvalid or missing service authentication is rejected by AuthX.
The service credential is separate from:
- DjangoPlay database credentials
- AuthX database credentials
- JWT signing keys
- User passwords
4. Identity Ownership
AuthX owns the authoritative identity record.
AuthX is responsible for:
- Identity persistence
- Password credentials
- Password hashing
- SSO identity linkage
- Authentication
- Identity status
- Verification status
- Staff/superuser identity flags
DjangoPlay maintains a local identity mirror for application-level relationships and data.
SOURCE OF TRUTH
│
▼
AuthX Identity
│
│ identity response
▼
DjangoPlay UserIdentity
local mirrorThe consuming application should not directly modify AuthX's database.
5. Endpoints
The internal identity API currently exposes the following operations:
| Method | Endpoint | Purpose |
|---|---|---|
POST |
/internal/identities |
Create an identity |
GET |
/internal/identities/{id} |
Retrieve an identity by ID |
PUT |
/internal/identities/{id} |
Update an identity |
GET |
/internal/identities/by-email/{email} |
Find an identity by email |
GET |
/internal/identities/by-sso/lookup |
Find an identity by SSO provider and provider ID |
All endpoints require:
X-Service-Token: <AUTHX_SERVICE_TOKEN>6. Create Identity
Request
POST /internal/identities
X-Service-Token: <token>
Content-Type: application/jsonExample request:
{
"email": "user@example.com",
"username": "user",
"password": "strong-password",
"sso_provider": null,
"sso_id": null,
"is_active": true,
"is_verified": false,
"is_staff": false,
"is_superuser": false
}The exact fields accepted by the current AuthX schema should be treated as the authoritative contract.
Password handling
The caller supplies the plaintext password only over the protected backend request.
AuthX is responsible for hashing the password before persistence.
DjangoPlay
│
│ password
▼
AuthX
│
│ password hashing
▼
password_hash
│
▼
AuthX PostgreSQLDjangoPlay must not reproduce AuthX's password hashing implementation.
Duplicate identity
An identity conflict, such as an existing email or conflicting SSO identity, is reported as a conflict response rather than silently creating another identity.
7. Get Identity by ID
GET /internal/identities/{id}
X-Service-Token: <token>The {id} value is the AuthX identity UUID.
Example:
GET /internal/identities/550e8400-e29b-41d4-a716-446655440000The endpoint returns the corresponding identity when it exists and is eligible for normal lookup.
8. Get Identity by Email
GET /internal/identities/by-email/{email}
X-Service-Token: <token>Example:
GET /internal/identities/by-email/user@example.comThis endpoint is used when a backend consumer needs to resolve an AuthX identity from its email address.
Email lookup should be performed through AuthX rather than by querying the AuthX database directly.
9. Get Identity by SSO Identity
GET /internal/identities/by-sso/lookupQuery parameters:
provider
sso_idExample:
GET /internal/identities/by-sso/lookup?provider=GOOGLE&sso_id=<provider-id>
X-Service-Token: <token>The combination of:
sso_provider
sso_ididentifies the external SSO identity.
This allows DjangoPlay to resolve an existing AuthX identity during an SSO onboarding or login flow.
10. Update Identity
PUT /internal/identities/{id}
X-Service-Token: <token>
Content-Type: application/jsonThe update operation modifies the authoritative AuthX identity.
Example:
{
"email": "updated@example.com",
"username": "updated-user",
"is_active": true,
"is_verified": true
}Only fields supplied by the caller are intended to be changed according to the current request schema.
If a password is supplied, AuthX performs the password hashing before persisting the new credential.
DjangoPlay
│
▼
AuthXClient
│
│ PUT /internal/identities/{id}
▼
AuthX
│
├── Validate request
├── Apply identity changes
├── Hash password if supplied
└── Persist
│
▼
AuthX PostgreSQLAfter a successful update, DjangoPlay synchronizes its local identity mirror.
11. Identity Synchronization
DjangoPlay does not treat its local identity record as the authoritative identity source.
For example:
DjangoPlay
│
│ create/update identity
▼
AuthX
│
│ authoritative identity
▼
AuthX PostgreSQL
│
│ response
▼
DjangoPlay
│
▼
sync_identity()
│
▼
Local UserIdentity mirrorThe local mirror contains identity information required by DjangoPlay, including values such as:
authx_id
username
email
sso_provider
sso_id
is_active
is_verified
is_staff
is_superuserThis allows DjangoPlay to maintain:
- Application relationships
- Foreign keys
- Profiles
- Groups
- Application permissions
- Domain-specific records
- Local history
without becoming the owner of AuthX credentials.
12. Soft Delete
Identity deletion is represented as a soft-delete operation.
DELETE /internal/identities/{id}
X-Service-Token: <token>The identity record is retained rather than physically removed.
Conceptually:
deleted_at = current UTC time
is_active = falseDeleted identities are excluded from normal identity lookup.
This preserves the identity record for data integrity and historical purposes while preventing the identity from remaining active.
13. Identity Lifecycle
The complete lifecycle can be represented as:
flowchart TD
CREATE["Create Identity"]
ACTIVE["Active Identity"]
UPDATE["Update Identity"]
VERIFY["Verification / Status Changes"]
DELETE["Soft Delete"]
RETAINED["Retained Identity Record"]
CREATE --> ACTIVE
ACTIVE --> UPDATE
UPDATE --> ACTIVE
ACTIVE --> VERIFY
VERIFY --> ACTIVE
ACTIVE --> DELETE
DELETE --> RETAINED
classDef action fill:#e6f1fb,stroke:#2474b5,stroke-width:2px,color:#174d7a
classDef active fill:#e5f6f1,stroke:#159a7a,stroke-width:2px,color:#075d4b
classDef deleted fill:#fceee8,stroke:#d65a2a,stroke-width:2px,color:#7d321c
class CREATE,UPDATE,VERIFY action
class ACTIVE active
class DELETE,RETAINED deleted14. DjangoPlay Integration
DjangoPlay uses its AuthX integration layer rather than calling internal endpoints directly throughout the application.
The main components are:
users/
services/
authx_sync.py
authx_client
AuthXClientThe integration layer provides operations such as:
create_identity_and_mirror()
update_identity_and_mirror()
sync_identity()The resulting architecture is:
DjangoPlay UI / API
│
▼
Application Service
│
▼
AuthX Synchronization Service
│
▼
AuthXClient
│
│ X-Service-Token
▼
AuthX Internal Identity APIThis keeps HTTP communication and identity synchronization outside the individual Django views.
15. Error Handling
Consumers should distinguish between authentication failures, validation errors, missing identities, and identity conflicts.
Typical categories include:
| Response | Meaning |
|---|---|
401 |
Authentication/authorization mechanism requires attention |
403 |
Invalid or missing internal service credential |
404 |
Requested identity does not exist |
409 |
Identity conflict, such as duplicate identity data |
422 |
Request validation failure |
For example, an invalid UUID supplied to an identity endpoint can result in a validation response before identity lookup occurs.
This is useful when diagnosing connectivity because a validation response demonstrates that the request reached the AuthX endpoint and passed the service-authentication boundary.
16. Security Requirements
The following rules are mandatory for consumers:
- Keep
AUTHX_SERVICE_TOKENserver-side. - Never expose the service token to frontend code.
- Never commit the service token to source control.
- Never query the AuthX database directly from DjangoPlay.
- Never duplicate AuthX password hashing logic.
- Never store AuthX passwords in DjangoPlay.
- Use
AuthXClientfor internal identity operations. - Treat AuthX as the identity source of truth.
- Keep AuthX JWT private keys exclusively inside AuthX.
- Maintain a local identity mirror only for application-level requirements.
17. Credential Separation
DjangoPlay and AuthX intentionally have separate database credentials.
DjangoPlay
│
└── DB_PASSWORD
│
└── DjangoPlay PostgreSQL
AuthX
│
├── POSTGRES_USER
├── POSTGRES_PASSWORD
├── POSTGRES_DB
├── DATABASE_URL
└── DATABASE_URL_SYNC
│
└── AuthX PostgreSQLThe DjangoPlay → AuthX service credential is separate:
AUTHX_SERVICE_TOKENAuthX JWT signing material is also separate:
JWT_PRIVATE_KEY
JWT_PUBLIC_KEYThe private signing key must remain exclusively within AuthX.
18. Operational Boundary
In the current DjangoPlay deployment, AuthX runs as a separate identity service.
The production runtime intentionally keeps AuthX locally bound on the application host:
127.0.0.1:8100DjangoPlay communicates with it over the local service boundary.
The public JWT issuer is a separate concept:
https://auth.djangoplay.orgTherefore:
APP_BASE_URL
=
where AuthX is reachable
JWT_ISSUER
=
identity authority asserted by AuthX JWTsThese values do not need to be identical.
19. Example Backend Call
A backend consumer should conceptually perform:
AuthXClient
│
├── resolve AuthX base URL
├── attach X-Service-Token
├── send internal request
├── validate HTTP response
└── return identity dataThe consumer should not construct raw database operations or reproduce AuthX's internal identity logic.
20. Summary
The AuthX Internal Identity API provides a controlled backend interface for identity lifecycle management.
Its primary characteristics are:
| Area | Design |
|---|---|
| Consumer | Trusted backend applications |
| Authentication | X-Service-Token |
| Credential | AUTHX_SERVICE_TOKEN |
| Identity authority | AuthX |
| Persistence | AuthX PostgreSQL |
| Password hashing | AuthX |
| Identity lookup | ID, email, SSO |
| Updates | PUT |
| Deletion | Soft delete |
| Django integration | AuthXClient + synchronization service |
| Local application identity | DjangoPlay mirror |
| JWT authority | AuthX |
| JWT signing key | AuthX only |
The fundamental architectural rule is:
AuthX owns identity; DjangoPlay consumes and mirrors identity.