Skip to content

CP endpoints for iOS fleet flow #266

@posix4e

Description

@posix4e

The iOS app on devopsdefender/dd-client#1 (commits 6bf998b, f4f6dab) lands a new GitHub-auth fleet flow, but it depends on CP-side endpoints that don't exist yet — https://app.devopsdefender.com/oauth/ios/start currently 404s and the new LaunchView's "Sign in with GitHub" tap opens an empty ASWebAuthenticationSession against that 404.

This issue is the CP-side contract the iOS client expects.

Required endpoints

GET /oauth/ios/start?pubkey=<hex>&label=<label>

  • Begins GitHub OAuth.
  • After GitHub redirects back, the CP records the (authenticated GitHub user) ↔ pubkeylabel mapping and issues a bearer token (JWT or opaque, server's choice).
  • CP returns a 302 to: devopsdefender://oauth/callback?token=<token> — the iOS app catches this via the existing devopsdefender:// custom-scheme registration (apps/ios/DevOpsDefender/Info.plist in dd-client).
  • pubkey is hex-encoded X25519 (64 chars); label is URL-encoded free text, defaults to UIDevice.current.name on the iOS side.
  • This is also where enrollment happens — first call with a new pubkey associates it with the GitHub identity. Subsequent calls re-issue a token for the existing pubkey.

GET /api/v1/agents

  • Auth: Authorization: Bearer <token> from the OAuth flow above.
  • Returns JSON array of agents the authenticated user has access to:
    [
      {
        "id": "agent-stable-id",
        "label": "Human-readable name, e.g. 'laptop'",
        "agent_url": "https://agent-host.example.com",
        "last_seen_at": "2026-05-11T14:48:00Z"
      }
    ]
  • 401/403 on missing/invalid token (iOS treats both as "re-auth needed" — wipes the Keychain token and returns to the launch chooser).
  • Per-agent session listing does NOT need a CP endpoint — the iOS client uses the existing Noise shell.list_sessions RPC on the agent directly once it has the agent URL. New FFI helper dd_client_list_sessions already wraps that.

Rebuild of /admin/enroll?pubkey=&label=

  • Currently this is the URL the CLI's dd-client keygen --cp-url … prints to enroll a desktop pubkey. Today it's a "useless webpage" per the iOS user.
  • Rebuild it as the fleet dashboard — same destination iOS lands on after /oauth/ios/start. When the URL carries pubkey/label query params (i.e. the user clicked the CLI's printed link), show a sticky banner at top: "Confirm enrollment of pubkey `abc…` as 'laptop'", with a confirm button.
  • CLI output is unchanged (enrollment_url in dd-client-core/src/lib.rs stays as-is) so existing scripts/docs keep working.

Agent-side authorization

  • iOS does NOT carry a JWT through the Noise handshake. The CP is the source of truth for "which pubkeys can attach where."
  • Agents are expected to poll the CP (or subscribe) for the list of authorized pubkeys at periodic intervals. When iOS attaches with its pubkey, the agent recognizes it from the freshest poll.
  • Propagation window of a few seconds to a minute is fine for the iOS UX.

Token shape (open question)

iOS doesn't care whether the token is a JWT or opaque — it just needs:

  • It's a single string returned as the `token=` query param in the 302 to `devopsdefender://oauth/callback`.
  • It's accepted as `Authorization: Bearer ` on subsequent CP API calls.
  • Expiry is up to the CP. iOS handles 401 by re-running the OAuth flow.

If you want it to be a JWT (e.g. so agents can verify it without a CP round-trip later), include the GitHub `sub`, the iOS pubkey hex, and an `exp`. iOS won't introspect it.

Why this matters now

Until these endpoints exist, the iOS fleet flow lands users on Cloudflare's 404 page inside the OAuth sheet — which they reasonably mistook for a crash today. The iOS side ships behind a `DEBUG_FAKE_FLEET` compile flag for now so we can iterate on the post-auth UI with stub agents, but real end-to-end requires CP work.

References

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions