Auth
auth is Skippr Cloud identity: humans, application users, API keys, and workload principals — with a single ABAC model for authorizing Cloud APIs.
Status: Preview — OTP sign-in, JWT sessions, API keys, workspace run locks, and JWKS at auth.cloud.skippr.io. Cloud directory SSO and app user pools are planned.
Directories
| Directory | Who | Typical use |
|---|---|---|
| Cloud directory | Operators of a Cloud account | Console, CLI, CDK/TF, SigV4 keys |
| App user pool | End users of your product | OTP / SSO into your app |
| Workload | Automation | Functions, fleets, CI (sk_live_… keys) |
Hostnames
| Role | Hostname |
|---|---|
| Auth API | https://auth.cloud.skippr.io |
| Edge (multi-service) | https://api.cloud.skippr.io |
All calls use HTTPS. Auth routes are native JSON (not Cognito/IAM wire format).
Quickstart — OTP sign-in
# 1. Request a one-time code
curl -sS -X POST https://auth.cloud.skippr.io/auth/sign-in \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com"}'
# 2. Confirm with the code from email (dev stacks accept 000000)
curl -sS -X POST https://auth.cloud.skippr.io/auth/confirm \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","code":"123456"}'Response includes token (access JWT, ~15 min) and refresh_token (~365 days).
Use the access token on other Cloud APIs via the gateway:
curl -sS https://tables.eu-central-1.cloud.skippr.io/ \
-H 'Authorization: Bearer <access_token>' \
-H 'x-amz-target: DynamoDB_20120810.ListTables' \
-H 'Content-Type: application/x-amz-json-1.0' \
-d '{}'Fetch JWKS for local verification:
curl -sS https://auth.cloud.skippr.io/.well-known/jwks.jsonAPI keys (skipprd / CI)
Create a key while authenticated, then exchange it for JWTs:
# Create (Bearer access token required)
curl -sS -X POST https://auth.cloud.skippr.io/auth/api-keys \
-H 'Authorization: Bearer <access_token>' \
-H 'Content-Type: application/json' \
-d '{"name":"ci"}'
# Exchange sk_live_… for JWT pair
curl -sS -X POST https://auth.cloud.skippr.io/auth/api-key-exchange \
-H 'Authorization: Bearer sk_live_<secret>' \
-H 'Content-Type: application/json' \
-d '{}'Session lifecycle
| Operation | Route | Auth |
|---|---|---|
| Current session | GET /auth/session | Bearer access JWT |
| Refresh | POST /auth/refresh | {"refresh_token":"…"} body |
| Logout | POST /auth/logout | Bearer access JWT |
| Delete account | DELETE /auth/delete | Bearer access JWT |
Logout bumps token_version server-side; previously issued access tokens stop working after refresh window.
Workspace run locks
skipprd uses workspace run locks to serialize heavy commands (sync, discover, etc.):
POST /auth/workspaces/{workspace}/runs/lock/acquire
POST /auth/workspaces/{workspace}/runs/lock/heartbeat
POST /auth/workspaces/{workspace}/runs/lock/complete
GET /auth/workspaces/{workspace}/runs/lockAll require a valid Bearer JWT for the tenant that owns the workspace.
Limits
| Limit | Value |
|---|---|
| OTP attempts per code | 5 |
| Access token TTL | 15 minutes |
| Refresh token TTL | 365 days |
| API keys per user | 25 (soft) |
| Run lock lease | 120 seconds (heartbeat extends) |
Errors
Auth returns JSON with error or message fields. Common HTTP statuses:
| Status | Meaning |
|---|---|
| 400 | Invalid email or request body |
| 401 | Missing or expired token |
| 403 | Forbidden (tenant isolation / ABAC deny) |
| 429 | Too many OTP attempts |
| 503 | Upstream tables unavailable |
