Skip to content

Tech Story: Station-Bot administration authentication, downstream OAuth identity, and session handling #241

@GitAddRemote

Description

@GitAddRemote

User Story

As a Station platform engineer, I need a dedicated authentication model for Station-Bot administration so that only signed-in Station users can reach the admin surface, Station can call Station-Bot over a secure machine-to-machine identity boundary, and the Station super admin retains a break-glass login path if Discord authentication is unavailable.

Definition of Done

  • Station-Bot administration requests from the browser require an authenticated Station user session; anonymous users cannot bootstrap or mutate any Station-Bot admin route
  • Discord OAuth2 is the primary interactive login path for all normal Station users, including guild owners and guild admins
  • Local username/password login is restricted to the station_super_admin break-glass account and is intended only for cases where Discord is down or the Discord login flow is broken
  • Station-to-Station-Bot calls use a dedicated OAuth 2.0 Client Credentials identity rather than forwarding the end-user browser token downstream
  • A minimum downstream scope model is defined and enforced for the Station admin client, with separate scopes for read, write, and privileged action paths
  • Station stores any Station-Bot admin client credentials securely, never returns them to the frontend, and masks/reveals/rotates them using the same write-only secret discipline already expected for operator config
  • The frontend has clear auth-state handling for this area: no anonymous access, predictable 401/403 behavior, session-expiry handling, and degraded-state rendering when downstream client auth fails
  • Tests cover unauthenticated browser requests, Discord-authenticated access, blocked local login for non-super-admin users, allowed break-glass local login for the super admin, expired/revoked Station sessions, missing/invalid downstream client credentials, and downstream scope mismatch failures
  • pnpm typecheck passes

Acceptance Criteria

  • A user who is not logged in to Station cannot access /admin/station-bot, cannot call Station-Bot admin API routes, and does not receive any Station-Bot bootstrap payload
  • Guild owners and guild admins authenticate through Discord OAuth2 rather than local username/password login
  • Local login is unavailable to normal customer users and is only supported for the station_super_admin break-glass account
  • A signed-in Station user never sends Station-Bot client credentials to the browser; the browser only talks to Station, and Station talks to Station-Bot using the dedicated client identity
  • If the Station-Bot admin client is missing, revoked, or has insufficient scopes, the Station UI shows a degraded integration/authentication state instead of exposing a generic 500 or blank screen
  • Session expiry during Station-Bot admin use results in the same re-authentication behavior as the rest of Station, without leaving the admin area in a misleading partially-authenticated state
  • The downstream client scope contract is explicit and versioned. Minimum expected scopes should be:
    • station-bot:admin:read
    • station-bot:admin:write
    • station-bot:admin:action

Technical Elaboration

Station already has two relevant authentication primitives in code today:

  1. End-user authentication via JWT-backed Station sessions, refresh rotation, session IDs, blacklist support, and both local and Discord auth support in backend/src/modules/auth
  2. Machine-to-machine authentication via OAuth client credentials, ClientAuthGuard, and ScopesGuard

This story should formalize how those pieces are used for Station-Bot administration:

  • Browser → Station: authenticated Station user session only
  • Station interactive login policy:
    • station_super_admin may use local login as a break-glass path
    • all other customer-facing/admin users should authenticate with Discord OAuth2
  • Station → Station-Bot: dedicated OAuth client credentials token issued for the Station admin integration
  • Never: browser directly calling Station-Bot admin APIs with bot credentials or with a forwarded end-user JWT

Recommended implementation shape:

  • Station frontend admin route still relies on the existing Station user auth flow
  • Station backend explicitly distinguishes break-glass local login policy for the super admin from normal Discord-based auth for customer accounts
  • Station backend station-bot-admin module acquires and caches a downstream client token for the configured Station-Bot admin client
  • Downstream Station-Bot admin endpoints enforce scopes such as:
    • station-bot:admin:read for config/bootstrap/status fetches
    • station-bot:admin:write for standard config mutation
    • station-bot:admin:action for resync/manual action operations such as exec-hangar controls
  • Station stores the client ID and secret in secure operator config, with masked-read behavior after save
  • Station surfaces distinct integration-auth states:
    • user not signed in
    • user signed in but Station lacks downstream client config
    • downstream client configured but token request failed
    • downstream token valid but missing scopes
    • downstream auth healthy

This ticket is intentionally about authentication and service identity, not end-user permissions. Whether a signed-in user is allowed to see or mutate a specific bot domain is handled by the authorization story.

Design Elaboration

From the user’s perspective, Station-Bot administration should feel like a normal authenticated Station area, not a second login wall. Guild owners and guild admins sign in through Discord; the Station super admin retains a clearly designated break-glass local login only for platform support continuity.

The important UX requirement is clarity when auth breaks. If the user session expired, say so. If Discord auth is degraded, the super admin still has a recovery path. If the downstream bot client is misconfigured, say so. If Station can render the shell but cannot authenticate to Station-Bot, that degraded state should be obvious before the user edits anything.


Parent Epic: #231
Depends on: None. This is an authentication foundation story for the Station Bot Administration epic.
Blocks: #232, #233, #243, #244

Metadata

Metadata

Assignees

Labels

apiPublic/internal API endpointsbackendBackend services and logicconfigConfiguration and feature flagssecuritySecurity, auth, and permissionstech-storyTechnical implementation story

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions