Initial Commit
This commit is contained in:
67
packages/api-stack/api/api-schemas/src/auth/refresh.md
Normal file
67
packages/api-stack/api/api-schemas/src/auth/refresh.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# refresh
|
||||
|
||||
## Purpose
|
||||
|
||||
Defines Zod schemas for the token-refresh request and response shapes used by Suaveplan's `POST /auth/refresh` endpoint. The refresh flow implements token rotation — each use of a refresh token returns both a new access token and a new refresh token, invalidating the consumed one. These schemas are shared between the server route handler, the React auth hook that silently re-authenticates expiring sessions, and the OpenAPI generator.
|
||||
|
||||
## Features
|
||||
|
||||
- `RefreshInput` schema — accepts a single `refreshToken` string (non-empty)
|
||||
- `RefreshOutput` schema — returns a new `token` (access) and new `refreshToken` (rotation pattern)
|
||||
- Non-empty validation on both token fields to prevent silent empty-string bypasses
|
||||
- Full TypeScript inference via `z.infer<>` — no manual interface duplication
|
||||
- Zod v4 compatible
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { RefreshInput, RefreshOutput } from "@suaveplan/api-schemas/auth";
|
||||
|
||||
// Validate the request body
|
||||
const input = RefreshInput.parse(req.body);
|
||||
// → { refreshToken: "rt_abc123..." }
|
||||
|
||||
// Validate the response
|
||||
const output = RefreshOutput.parse({ token: "new-access-token", refreshToken: "new-rt_xyz" });
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { RefreshInput, RefreshOutput } from "@suaveplan/api-schemas/auth";
|
||||
|
||||
async function handleRefresh(rawBody: unknown): Promise<RefreshOutput> {
|
||||
const { refreshToken } = RefreshInput.parse(rawBody);
|
||||
const session = await sessionStore.consume(refreshToken); // invalidates old token
|
||||
const newAccess = await tokenService.issueAccessToken(session.userId);
|
||||
const newRefresh = await sessionStore.issue(session.userId);
|
||||
return RefreshOutput.parse({ token: newAccess, refreshToken: newRefresh });
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `RefreshInput`
|
||||
|
||||
Zod object schema — token refresh request body.
|
||||
|
||||
| Field | Type | Description |
|
||||
|----------------|------------------|---------------------------------------------------|
|
||||
| `refreshToken` | `string` (min 1) | Long-lived refresh token from a prior login/refresh|
|
||||
|
||||
**Type export:** `type RefreshInput = z.infer<typeof RefreshInput>`
|
||||
|
||||
### `RefreshOutput`
|
||||
|
||||
Zod object schema — token refresh success response.
|
||||
|
||||
| Field | Type | Description |
|
||||
|----------------|------------------|------------------------------------------------|
|
||||
| `token` | `string` (min 1) | New short-lived access token |
|
||||
| `refreshToken` | `string` (min 1) | New long-lived refresh token (rotation) |
|
||||
|
||||
**Type export:** `type RefreshOutput = z.infer<typeof RefreshOutput>`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The output deliberately echoes the same shape as `LoginOutput`'s token fields, allowing React hooks to handle both login and refresh responses through a shared token-update function. Token rotation (issuing a new refresh token each time) is recommended by OAuth 2.0 Security Best Practices to limit the damage from a stolen refresh token. The server should record and compare the previous refresh token before issuing the new pair, rejecting any reuse attempts.
|
||||
Reference in New Issue
Block a user