Skip to content

Proposal: Move KernelCI API user onboarding to invite-only “single link” activation (deprecate legacy verification-token flow) #639

@nuclearcat

Description

@nuclearcat

Today user onboarding is split across multiple steps (create user, request verification token, verify, then login), and verification/reset emails contain raw tokens requiring copy/paste into CLI/API calls. This is functional not great UX and adds support friction. I recently implemented an invite-only flow in kernelci-api where a single invite link allows a user to set their password and become verified in one step.

Proposal
Adopt invite-only onboarding as the recommended/primary workflow:

  1. Admin invites a user
  • API: POST /user/invite (admin-only) creates the user (if missing) and generates an invite token + link.
  • Web UI: GET /user/invite provides a minimal invite form and shows the computed “public” URL base before sending.
  1. User accepts invite (one step)
  • API: POST /user/accept-invite with {token, password} sets password + marks user verified.
  • Web UI: GET /user/accept-invite?token=... provides a minimal password-set page.
  1. Login continues to require verified users
  • Existing /user/login behavior remains: requires verification (now satisfied via invite acceptance).

Motivation / Why change

  • UX: one link to activate + set password is the common expectation for invite-only systems.
  • Operational simplicity: removes the “request verification token” step and token copy/paste.
  • Consistency: aligns with staging workflow (accounts created by admins/sysadmins).
  • Security: keeps admin-only creation; invite token is signed JWT with expiry.
  • Works with and without SMTP: admins can request return_token=true and send_email=false to distribute link manually.

URL generation / reverse proxy support
Invite links use the following resolution order:

  1. PUBLIC_BASE_URL env var (recommended)
  2. X-Forwarded-Host header
  3. request.base_url fallback

Admin can preview resolved URL via GET /user/invite/url before sending invites.

Compatibility / Impact

  • Existing user records remain valid.
  • Existing auth tokens continue to work unchanged.
  • Password reset flow remains unchanged (/user/forgot-password, /user/reset-password).
  • Legacy email verification-token endpoints have been removed in favor of invite acceptance.

Testing

  • Added e2e coverage for invite flow without SMTP: tests/e2e_tests/test_user_invite.py uses send_email=false and validates invite -> accept -> login.
  • CI helper script ci-checks.sh mirrors GitHub workflows (pycodestyle + docker-compose + pylint + pytest).

Follow-ups / TODO

  • Add e2e coverage for durable pubsub (subscriber_id) reconnect/catch-up semantics and ownership enforcement (tracked in TODO.md).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions