Authentication: prediction-assistant

arch-auth Architecture

architecture

Authentication Architecture

Two-layer authentication: Keycloak SSO for app access, Kalshi API keys for trading. Answers: how are users authenticated and authorized?

Diagram




          
  

Components

Component Purpose Notes
Keycloak SSO App-level authentication and user management Direct grant flow (no browser redirect). Realm: kalshi-assistant
JWT Tokens Stateless auth between iOS app and Rails API Access token + refresh token. Validated via JWKS endpoint.
Kalshi API Key ID Identifies the user's Kalshi account for API access Public identifier, stored per-user in DB
RSA Private Key Signs Kalshi API requests on behalf of the user PEM format. Encrypted at rest. Never transmitted after initial setup.
Credential Store Per-user encrypted storage of Kalshi API credentials Rails encrypted credentials or DB-level encryption

Key Decisions

  • Two auth layers, not one — Keycloak handles "who is this user of our app?" Kalshi API keys handle "can this user trade?" Separating these means users can log in and browse without having Kalshi credentials set up yet.
  • Direct grant over redirect flow — Mobile apps use Keycloak's direct grant (Resource Owner Password Credentials). No browser redirect needed. Cleaner native UX.
  • Per-user Kalshi credential storage — Each user brings their own Kalshi API key and RSA private key. Keys are encrypted at rest. The app signs requests on behalf of users but never holds their funds.
  • User can revoke access anytime — Users can delete their API key from Kalshi's settings at any time, immediately revoking our trading access. No lock-in.
  • RSA private key never leaves the server — After initial submission, the private key is encrypted and stored server-side. It is used only for signing Kalshi API requests. Never returned to the client.