docs(swagger)+test(rest): document /auth/refresh + /auth/logout, add HTTP smoke tests #12

Merged
nsatoshi merged 0 commits from devin/1776541136-docs-auth-refresh-logout-followups into master 2026-04-18 12:41:50 -07:00
Owner

Summary

Follow-up to PR #8 (JWT revocation + refresh), addressing two of the three in-scope follow-ups called out on PR #11:

  1. swagger.yaml pre-dated /api/v1/auth/refresh and /api/v1/auth/logout — client generators couldn't pick them up.
  2. Those handlers were covered by unit tests on the WalletAuth layer and by the make e2e-full Playwright spec, but had no HTTP-level unit tests — regressions at the mux/handler seam (wrong method, missing walletAuth, unregistered route) were invisible to go test ./backend/api/rest.

Changes

backend/api/rest/swagger.yaml

  • New POST /api/v1/auth/refresh entry under the Auth tag. Uses bearerAuth, returns the existing WalletAuthResponse on 200, 401 via components/responses/Unauthorized, 503 when auth storage or jwt_revocations (migration 0016) is missing. Description calls out that legacy tokens without a jti cannot be refreshed.
  • New POST /api/v1/auth/logout entry. Same auth requirement; returns {status: ok} on 200; 401 via Unauthorized; 503 when migration 0016 hasn't run. Description names the jwt_revocations table so ops can correlate 503s with the migration.
  • Both slot in between /auth/wallet and /auth/register so the tag block stays ordered.

backend/api/rest/auth_refresh_internal_test.go (new — 7 tests)

  • TestHandleAuthRefreshRejectsGet — GET returns 405 method_not_allowed.
  • TestHandleAuthRefreshReturns503WhenWalletAuthUnconfiguredwalletAuth nil, POST with a Bearer header returns 503 rather than panicking.
  • TestHandleAuthLogoutRejectsGet — symmetric 405 on GET.
  • TestHandleAuthLogoutReturns503WhenWalletAuthUnconfigured — symmetric 503.
  • TestAuthRefreshRouteRegistered — exercises SetupRoutes and confirms POST /api/v1/auth/refresh and /api/v1/auth/logout are registered (not 404). Catches regressions where a future refactor drops the mux.HandleFunc entries.
  • TestAuthRefreshRequiresBearerToken + TestAuthLogoutRequiresBearerToken — a POST with no Authorization resolves to 401 or 503 (never 200 or 500).
  • decodeErrorBody helper extracts ErrorDetail from writeError's {"error":{"code":...,"message":...}} envelope so asserts match the actual wire format.
  • newServerNoWalletAuth builds a rest.Server with JWT_SECRET set to a 32-byte string so PR #3's fail-fast check is satisfied; nil db pool is fine because the tests don't touch any DB path.

Verification

  • cd backend && go vet ./... — clean.
  • cd backend && go test ./api/rest/ — pass.
  • cd backend && go test ./... — pass.

Out of scope

The live credential rotation follow-up (rotate the L@ker?s?$?2010 passwords in infra) needs database + SSH + deploy-pipeline access and belongs to the operator. docs/SECURITY.md (added in PR #3) lists every asset to rotate.

## Summary Follow-up to [PR #8](https://gitea.d-bis.org/d-bis/explorer-monorepo/pulls/8) (JWT revocation + refresh), addressing two of the three in-scope follow-ups called out on [PR #11](https://gitea.d-bis.org/d-bis/explorer-monorepo/pulls/11): 1. `swagger.yaml` pre-dated `/api/v1/auth/refresh` and `/api/v1/auth/logout` — client generators couldn't pick them up. 2. Those handlers were covered by unit tests on the `WalletAuth` layer and by the `make e2e-full` Playwright spec, but had **no HTTP-level unit tests** — regressions at the mux/handler seam (wrong method, missing `walletAuth`, unregistered route) were invisible to `go test ./backend/api/rest`. ## Changes ### `backend/api/rest/swagger.yaml` - New `POST /api/v1/auth/refresh` entry under the `Auth` tag. Uses `bearerAuth`, returns the existing `WalletAuthResponse` on 200, 401 via `components/responses/Unauthorized`, 503 when auth storage or `jwt_revocations` (migration 0016) is missing. Description calls out that legacy tokens without a `jti` cannot be refreshed. - New `POST /api/v1/auth/logout` entry. Same auth requirement; returns `{status: ok}` on 200; 401 via `Unauthorized`; 503 when migration 0016 hasn't run. Description names the `jwt_revocations` table so ops can correlate 503s with the migration. - Both slot in between `/auth/wallet` and `/auth/register` so the tag block stays ordered. ### `backend/api/rest/auth_refresh_internal_test.go` (new — 7 tests) - `TestHandleAuthRefreshRejectsGet` — GET returns 405 `method_not_allowed`. - `TestHandleAuthRefreshReturns503WhenWalletAuthUnconfigured` — `walletAuth` nil, POST with a Bearer header returns 503 rather than panicking. - `TestHandleAuthLogoutRejectsGet` — symmetric 405 on GET. - `TestHandleAuthLogoutReturns503WhenWalletAuthUnconfigured` — symmetric 503. - `TestAuthRefreshRouteRegistered` — exercises `SetupRoutes` and confirms `POST /api/v1/auth/refresh` and `/api/v1/auth/logout` are registered (not 404). Catches regressions where a future refactor drops the `mux.HandleFunc` entries. - `TestAuthRefreshRequiresBearerToken` + `TestAuthLogoutRequiresBearerToken` — a POST with no `Authorization` resolves to 401 or 503 (never 200 or 500). - `decodeErrorBody` helper extracts `ErrorDetail` from `writeError`'s `{"error":{"code":...,"message":...}}` envelope so asserts match the actual wire format. - `newServerNoWalletAuth` builds a `rest.Server` with `JWT_SECRET` set to a 32-byte string so PR #3's fail-fast check is satisfied; nil db pool is fine because the tests don't touch any DB path. ## Verification - `cd backend && go vet ./...` — clean. - `cd backend && go test ./api/rest/` — pass. - `cd backend && go test ./...` — pass. ## Out of scope The **live credential rotation** follow-up (rotate the `L@ker?s?$?2010` passwords in infra) needs database + SSH + deploy-pipeline access and belongs to the operator. `docs/SECURITY.md` (added in PR #3) lists every asset to rotate.
nsatoshi merged commit 7a684d010c into master 2026-04-18 12:41:50 -07:00
Sign in to join this conversation.