Skip to content

Native API token auth and websocket routes#168

Open
stacknode-lambda wants to merge 7 commits into
mpiorowski:mainfrom
stacknode-lambda:main
Open

Native API token auth and websocket routes#168
stacknode-lambda wants to merge 7 commits into
mpiorowski:mainfrom
stacknode-lambda:main

Conversation

@stacknode-lambda
Copy link
Copy Markdown

What changed

This change adds a native-client API surface to late-ssh and a matching token model in late-core.

  • Added a native_tokens table and NativeToken model for persistent bearer tokens with expiry.
  • Added an in-memory NativeChallengeStore for short-lived nonces issued by GET /api/native/challenge.
  • Added late-ssh/src/native_api.rs and mounted its routes under /api/native/* plus /api/ws/native.
  • Wired the new module and shared state into the existing API server and application bootstrap.
  • Added deadpool-postgres where needed for the new DB-backed native endpoints.

Auth flow

The native auth flow is challenge-based:

  1. A client requests a nonce from GET /api/native/challenge.
  2. The client signs that nonce with its SSH key.
  3. POST /api/native/token verifies the SSH signature and fingerprint.
  4. If the fingerprint maps to a known user, the server issues a time-limited bearer token and stores it in native_tokens.

This keeps the native API aligned with the existing SSH identity model instead of introducing a separate password-based auth path.

API surface

The new native API exposes endpoints for:

  • current user identity
  • room listing and room history
  • online user presence
  • now playing and voting status
  • submitting votes
  • bonsai state and watering
  • websocket updates for chat, votes, and now-playing changes

Why

The repo already had the core app state and websocket/event infrastructure, but it did not expose a dedicated native-client API with a reusable bearer-token auth flow. This change fills that gap so a native app can authenticate with an SSH-backed identity and consume the same real-time app data without going through the browser-oriented routes.

Copy link
Copy Markdown
Owner

@mpiorowski mpiorowski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good, but we need a little bit of hardening ;p

  1. Fix private room/message leaks

Highest priority. Native REST history and WS events must respect room membership and target_user_ids. This is the only issue that can expose user content.

  1. Restore test compilation

Add native_challenges to test State builders. This is small, but until fixed the branch weakens CI signal.

  1. Hash stored bearer tokens

Store only a SHA-256/HMAC hash of the token in native_tokens, not the raw token. On auth, hash the presented token and compare by hash. If DB leaks, raw tokens should not be directly usable.

  1. Move websocket auth token out of query string if possible

Query params leak into logs/proxies more often. Prefer Authorization: Bearer ... if the client stack allows it, or a short-lived WS ticket minted via authenticated REST and used once.

  1. Rate-limit native auth

Add limits for:

GET /api/native/challenge
POST /api/native/token
failed token auth attempts
WS connection attempts
Start per-IP. If easy, also rate-limit by fingerprint on /token.

  1. Add token revocation/logout

Add DELETE /api/native/token or /api/native/logout for current token. Optional but useful: revoke all native tokens for the user.

  1. Track token metadata

Add last_used_at, maybe user_agent/device_name, and maybe created_ip. This helps debugging and future token management. Keep IP retention policy in mind.

  1. Purge expired tokens

Either call NativeToken::purge_expired periodically or make it part of startup/background maintenance. Not urgent for security because queries check expiry, but important for DB hygiene.

@stacknode-lambda
Copy link
Copy Markdown
Author

Copy that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants