One project. Two ways in.
Create a project, publish your pages, add your exact callback URL, then create an API key with the Authentication permission. Use hosted sign-in for the quickest integration, or build your own interface against the server API.
Base URL: https://auth.saidworth.com/api/v1. All timestamps use UTC.
Hosted sign-in
- Your server generates a cryptographically random
stateand a PKCE verifier (43–128 characters). Store both in your own session. - Redirect the browser to the URL below. The callback must match a URL in Project settings exactly.
- At your callback, compare the returned state with your session using a constant-time comparison. Consume the state once.
- Exchange the returned code from your server within 60 seconds, using the same callback URL and original verifier.
- Keep the resulting access and refresh tokens in your application’s server session.
GET /authorize
?project=swp_YOUR_PROJECT_ID
&redirect_uri=https%3A%2F%2Fyour-app.com%2Fcallback
&state=YOUR_RANDOM_STATE
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&code_challenge_method=S256The included resources/integration-example.php implements the complete server-side flow with state checking, PKCE and session storage.
POST /api/v1/token
X-API-Key: swsk_YOUR_SECRET_KEY
Content-Type: application/json
{
"code": "swc_RETURNED_CODE",
"redirect_uri": "https://your-app.com/callback",
"code_verifier": "YOUR_ORIGINAL_VERIFIER"
}The standalone login URL is useful for viewing your page. To connect a login to your application, always start at /authorize.
Bring your own interface
Call these endpoints from your application’s server. User accounts are isolated by project.
POST /api/v1/register
X-API-Key: swsk_YOUR_SECRET_KEY
Content-Type: application/json
{"name":"Alex","email":"alex@example.com","password":"a-long-unique-password"}
POST /api/v1/login
X-API-Key: swsk_YOUR_SECRET_KEY
Content-Type: application/json
{"email":"alex@example.com","password":"a-long-unique-password"}Both return this shape. Registration returns HTTP 201.
{
"token_type": "Bearer",
"access_token": "swa_...",
"refresh_token": "swr_...",
"expires_in": 900,
"user": {
"id": 1,
"name": "Alex",
"email": "alex@example.com",
"email_verified": false,
"created_at": "2026-10-16 08:00:00"
}
}If verified email is required, registration creates the account and sends a verification link instead of issuing tokens. The response is HTTP 403. After verification, sign in normally.
Short access. Explicit control.
Access tokens last 15 minutes. Refresh tokens last 30 days and rotate on use. A refresh invalidates both old tokens; replace both atomically in your application. Revoking an API key blocks new server requests with that key. To end existing user access too, revoke their sessions or suspend the project.
GET /api/v1/me
Authorization: Bearer swa_ACCESS_TOKEN
POST /api/v1/refresh
X-API-Key: swsk_YOUR_SECRET_KEY
Content-Type: application/json
{"refresh_token":"swr_REFRESH_TOKEN"}
POST /api/v1/logout
Authorization: Bearer swa_ACCESS_TOKENFor browser calls (including published configuration), add ?project=swp_YOUR_PROJECT_ID and allow the exact browser origin in project settings. Authentication, token exchange, refresh and user management remain server-only.
API reference
| Method | Endpoint | Permission |
|---|---|---|
| GET | /health | Public |
| GET | /config/{project_id} | Public · published design |
| POST | /register | auth |
| POST | /login | auth |
| POST | /token | auth |
| POST | /refresh | auth |
| POST | /password/reset | auth |
| GET | /me | Bearer access token |
| POST | /logout | Bearer access token |
| GET | /users?page=1 | users:read |
| PATCH | /users/{id} | users:write |
| DELETE | /users/{id} | users:write |
PATCH /users/{id} accepts {"name":"Alex","status":"suspended"}. Allowed statuses: active, suspended. The users list returns 50 users per page. Deletion is permanent. Password reset accepts {"email":"alex@example.com"} and returns a generic message.
Predictable errors
{"error":"A human-readable message."}400 invalid flow or JSON · 401 invalid credentials/token · 403 permissions, suspended access or email verification · 404 missing resource · 405 wrong method · 409 conflict · 422 validation · 429 rate limited · 503 email unavailable.
Authentication attempts are limited per project and IP. Server keys allow up to 240 requests per minute per IP; access tokens allow 180. Honor the Retry-After header on 429 responses.