Identity and Registry

World discovery, player authentication, JWT tokens, RBAC permissions, OAuth2 login, and profile management in Aether.

The identity and registry system is the central authority for player authentication, profile management, permissions, and world discovery in Aether. It provides JWT-based authentication with Ed25519 signing, OAuth2 social login, RBAC/ABAC authorization, and token validation for federated world servers.

Key Concepts

  • JWT authentication -- Short-lived access tokens (15 min) and long-lived refresh tokens (30 days) signed with Ed25519.
  • OAuth2 social login -- Google, Apple, Discord, and Steam as identity providers.
  • RBAC/ABAC permissions -- Hierarchical roles with inherited permissions.
  • Token validation -- JWKS endpoint for federated world servers to verify tokens locally.
  • Profile management -- CRUD operations for player profiles with search capability.
  • Audit logging -- Every authentication event is recorded for security and compliance.

Architecture

The identity service is a Go-based microservice backed by PostgreSQL, Redis, and NATS:

Client -> API Gateway -> Identity Service
                              |
              +---------------+---------------+
              |               |               |
          PostgreSQL       Redis           NATS
          (users,        (sessions,      (auth events)
           roles,         token cache)
           audit)
ComponentTechnologyPurpose
HTTP Frameworknet/http + chiLightweight, stdlib-compatible routing
DatabasePostgreSQL 16User records, roles, audit logs
CacheRedis 7Session storage, token blacklist
Message BusNATS JetStreamAuth event publishing
JWT Signinggo-jose/v4Ed25519 token signatures
WebAuthngo-webauthnFIDO2/passkey support

Authentication Flow

Player login follows a secure multi-step flow:

  1. Client sends credentials to the API gateway.
  2. Gateway forwards to the identity service.
  3. Service queries the user by email from PostgreSQL.
  4. Password is verified using Argon2id.
  5. A new session is created in the database and cached in Redis.
  6. A login event is published to NATS for audit subscribers.
  7. Access token and refresh token are returned to the client.

Token refresh rotates both tokens:

POST /api/v1/auth/refresh { refresh_token }
  -> Validate refresh token against session
  -> Generate new access + refresh token pair
  -> Rotate refresh token hash in database
  -> Update Redis cache
  -> Return new token pair

The old refresh token is invalidated on each rotation, preventing replay attacks.

JWT Token Design

Access token (short-lived, 15 minutes):

{
  "sub": "user-uuid",
  "iss": "aether-identity",
  "aud": ["aether-api", "aether-world"],
  "exp": 1709890800,
  "iat": 1709889900,
  "jti": "unique-token-id",
  "role": "creator",
  "permissions": ["world:create", "avatar:upload"]
}

Refresh token (long-lived, 30 days):

  • Stored as SHA-256 hash in the sessions table (never stored in plaintext).
  • Rotated on each refresh; the old token is invalidated.
  • Bound to IP address and user-agent for anomaly detection.

Signing: Ed25519 is used for fast signature generation with small token sizes. Ed25519 keys are provided via the IDENTITY_JWT_PRIVATE_KEY environment variable.

World Server Token Validation

Federated world servers validate player tokens without per-request calls to the identity service:

Option 1 -- JWKS (preferred): World servers fetch the JWKS endpoint periodically (every 5 minutes) and validate tokens locally using the cached Ed25519 public keys.

GET /api/v1/auth/.well-known/jwks.json
-> Returns Ed25519 public keys for local JWT validation

Option 2 -- Validation endpoint: For cases requiring extra claims or revocation checking:

POST /api/v1/auth/validate { token }
-> Returns { valid: true, claims: { ... } }

RBAC/ABAC Permission Model

Roles are hierarchical -- higher-level roles inherit all permissions from lower levels:

RoleLevelPermissions
Player0profile:read, profile:write, world:join, avatar:equip
Creator10world:create, world:edit, avatar:upload, asset:upload
Moderator50user:warn, user:mute, user:kick, report:review
Admin100user:ban, role:assign, role:revoke, system:configure

Permission checks evaluate the role hierarchy:

Admin inherits -> Moderator inherits -> Creator inherits -> Player

A Creator can do everything a Player can, plus creator-specific actions. A Moderator inherits both Creator and Player permissions.

OAuth2 Social Login

The identity service supports four OAuth2 providers:

ProviderFlowNotes
GoogleAuthorization CodeStandard OIDC flow
AppleAuthorization CodeSign in with Apple
DiscordAuthorization CodeDiscord OAuth2
SteamOpenID 2.0Steam Web API

OAuth2 endpoints:

GET  /api/v1/auth/oauth/{provider}          -- Initiate OAuth2 redirect
GET  /api/v1/auth/oauth/{provider}/callback  -- Handle OAuth2 callback

On first OAuth login, a new user account is created and linked to the provider. Subsequent logins match the provider user ID to the existing account.

WebAuthn / Passkey Support

The identity service supports FIDO2/WebAuthn for passwordless authentication:

POST /api/v1/auth/webauthn/register/begin   -- Begin passkey registration
POST /api/v1/auth/webauthn/register/finish  -- Complete registration
POST /api/v1/auth/webauthn/login/begin      -- Begin passkey login
POST /api/v1/auth/webauthn/login/finish     -- Complete login

WebAuthn credentials are stored in the webauthn_credentials table with the credential ID, public key, AAGUID, and sign count for replay detection.

Profile Management

Player profiles support CRUD operations with search:

GET  /api/v1/profiles/me        -- Get current user's profile
PUT  /api/v1/profiles/me        -- Update current user's profile
GET  /api/v1/profiles/{id}      -- Get profile by ID
GET  /api/v1/profiles           -- Search profiles

Profile fields include display name, bio, avatar URL, and user-defined settings stored as JSONB.

Audit Logging

Every authentication event is recorded in the audit_logs table:

Event TypeTrigger
loginSuccessful login
logoutSession revocation
token_refreshRefresh token rotation
permission_changeRole assignment or revocation
profile_updateProfile field modification

Each audit record captures the user ID, IP address, user-agent, timestamp, and event-specific metadata as JSONB.

Configuration

All settings are driven by environment variables:

VariableDefaultDescription
IDENTITY_PORT8080HTTP listen port
IDENTITY_DB_URLrequiredPostgreSQL connection string
IDENTITY_REDIS_URLrequiredRedis connection string
IDENTITY_NATS_URLrequiredNATS connection string
IDENTITY_JWT_PRIVATE_KEYrequiredEd25519 private key (PEM)
IDENTITY_JWT_ACCESS_TTL15mAccess token TTL
IDENTITY_JWT_REFRESH_TTL720hRefresh token TTL
IDENTITY_RATE_LIMIT_LOGIN10Login attempts per minute
IDENTITY_RATE_LIMIT_REGISTER5Registration attempts per minute
IDENTITY_ARGON2_MEMORY65536Argon2id memory in KB
IDENTITY_ARGON2_ITERATIONS3Argon2id iterations

OAuth provider credentials are optional and enable social login when configured:

VariableDescription
IDENTITY_OAUTH_GOOGLE_IDGoogle OAuth client ID
IDENTITY_OAUTH_GOOGLE_SECRETGoogle OAuth client secret
IDENTITY_OAUTH_APPLE_IDApple OAuth client ID
IDENTITY_OAUTH_DISCORD_IDDiscord OAuth client ID
IDENTITY_OAUTH_STEAM_KEYSteam API key