first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,106 @@
# schemas/routes/oauth
## Purpose
Schemas for the OAuth pair `GET /auth/oauth/:provider/start` and
`GET /auth/oauth/:provider/callback`. The start endpoint initiates an
OAuth flow (typically redirecting to the provider's authorization
endpoint); the callback receives the provider's `code` + `state` and
finishes the flow.
## Features
- `OAuthStartParamsSchema` — `{ provider: string (min 1) }` for the
path parameter.
- `OAuthStartQuerySchema` — `{ redirectTo?: string (url) }` so callers
can request a specific post-login redirect.
- `OAuthStartResponseSchema` — `{ redirectTo: string (url) }`; the
body shape used when the response is a 200 + JSON pointer rather than
a direct 302.
- `OAuthCallbackParamsSchema` + `OAuthCallbackQuerySchema` — `{ code,
state }` from the provider.
- `OAuthCallbackResponseSchema` — `{ redirectTo: string (url) }` for
the same 200 + JSON pointer variant.
## Usage: Basic
```ts
import { OAuthStartQuerySchema, OAuthCallbackQuerySchema } from "@suaveplan/api-plugin-auth/schemas/routes";
const startQuery = OAuthStartQuerySchema.parse({ redirectTo: "https://example.test/" });
const callbackQuery = OAuthCallbackQuerySchema.parse({ code: "abc", state: "xyz" });
```
## Usage: Advanced
Use the params + query + response shapes inside a `RouteBuilder` chain
so the OpenAPI doc advertises a fully-typed OAuth flow including the
required `state` field on the callback:
```ts
import { GET, successResponse } from "@suaveplan/api-openapi";
import {
OAuthCallbackParamsSchema,
OAuthCallbackQuerySchema,
OAuthCallbackResponseSchema,
OAuthStartParamsSchema,
OAuthStartQuerySchema,
OAuthStartResponseSchema,
} from "@suaveplan/api-plugin-auth/schemas/routes";
const startRoute = GET("/auth/oauth/{provider}/start")
.tags("auth", "oauth")
.summary("Begin OAuth flow with the named provider")
.params(OAuthStartParamsSchema)
.query(OAuthStartQuerySchema)
.response(successResponse(OAuthStartResponseSchema))
.build();
const callbackRoute = GET("/auth/oauth/{provider}/callback")
.tags("auth", "oauth")
.summary("OAuth callback — exchange code for session")
.params(OAuthCallbackParamsSchema)
.query(OAuthCallbackQuerySchema)
.response(successResponse(OAuthCallbackResponseSchema))
.build();
```
## API Reference
### `OAuthStartParamsSchema`
`{ provider: string (min 1) }`. Inferred type `OAuthStartParams`.
### `OAuthStartQuerySchema`
`{ redirectTo?: string (url) }`. Inferred type `OAuthStartQuery`.
### `OAuthStartResponseSchema`
`{ redirectTo: string (url) }`.
### `OAuthCallbackParamsSchema`
`{ provider: string (min 1) }`. Inferred type `OAuthCallbackParams`.
### `OAuthCallbackQuerySchema`
`{ code: string (min 1); state: string (min 1) }`. Inferred type
`OAuthCallbackQuery`.
### `OAuthCallbackResponseSchema`
`{ redirectTo: string (url) }`.
## Implementation Notes
- The OAuth pair is documented as 200-with-JSON-redirect in OpenAPI for
ergonomics — Better-Auth's runtime handler may return a 302 directly,
which is compatible with the OpenAPI doc because consumers reading
the spec see the "redirectTo" pointer either way.
- The callback's `state` field is required (Better-Auth always emits
it) so CSRF protection is enforced at the schema layer; callers that
drop `state` fail Zod validation before Better-Auth ever runs.
- Provider validation is structural — the route accepts any provider
string; Better-Auth's configured providers map decides whether the
call succeeds at runtime.