Skip to content

Add a refresh-token flow so merchants are not hard-logged-out every hour #456

Description

@Cedarich
  • Complexity: Medium
  • Labels: Backend, auth, api, security, Medium
  • Overview: The backend issues a single short-lived access token and provides no way to renew it. AuthController exposes only POST /auth/nonce, POST /auth/verify, GET /auth/me, and POST /auth/logout — there is no refresh endpoint. JwtModule signs with JWT_EXPIRES_IN defaulting to 3600, so every merchant is hard-logged-out once an hour and must reconnect their wallet and sign a fresh nonce to continue. For a merchant running a POS or working through an invoice batch, that is a wallet prompt in the middle of real work.
  • Details:
    • AuthService.verify() returns { accessToken } and nothing else. There is no refresh token, no session record, and no renewal path.
    • The mobile client already types VerifyResponse.refreshToken? in mobile/lib/auth-service.ts, and use-auth-store.ts decodes the token expiry and wipes the session when it lapses. The client is written as if a refresh flow exists; the backend never provides one.
    • Re-authentication is not a cheap redirect here — it requires a wallet signature, so an expiry mid-session interrupts the merchant with a Freighter or mobile wallet prompt.
    • Raising JWT_EXPIRES_IN is not an acceptable workaround: tokenVersion-based revocation only takes effect when a token expires or the user logs out, so a longer access token directly widens the window in which a revoked session stays usable.
    • Session lifetime, idle timeout, and absolute timeout are currently undefined behaviour rather than a deliberate policy.
  • Scope:
    • Add a refresh flow that issues a longer-lived refresh credential alongside the access token at verify time.
    • Persist refresh sessions so they can be individually revoked, and make logout revoke the refresh credential as well as bump tokenVersion.
    • Rotate the refresh credential on each use and detect reuse of a rotated credential as a compromise signal.
    • Define and document explicit idle and absolute session timeouts, after which a fresh wallet signature is genuinely required.
    • Keep the access token short-lived so tokenVersion revocation stays effective.
    • Update the web and mobile clients to renew transparently instead of dropping the session.
  • Technical scope:
    • backend/src/auth/auth.controller.ts
    • backend/src/auth/auth.service.ts
    • backend/src/auth/auth.module.ts
    • backend/src/auth/strategy/jwt.strategy.ts
    • backend/prisma/schema.prisma
    • web/hooks/use-wallet-auth.tsx
    • mobile/lib/auth-service.ts
  • Acceptance criteria:
    • A merchant stays signed in across the access-token lifetime without a new wallet signature.
    • Refresh credentials are persisted, individually revocable, and rotated on every use.
    • Reuse of an already-rotated refresh credential invalidates the session family.
    • logout ends the session immediately for both the access and refresh credentials.
    • Idle and absolute session timeouts are enforced and documented.
    • Tests cover renewal, rotation, reuse detection, logout revocation, and both timeout paths.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    BackendGrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardMediumMedium-complexity taskThird CampaignCampaign: Third CampaignapiAPI design or implementationauthAuthentication and session worksecuritySecurity-related work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions