{
"openapi": "3.0.3",
"info": {
"title": "Cedros Login API",
"description": "Authentication and authorization service supporting JWT tokens, API keys, Solana wallet auth, and organization management.",
"version": "1.0.0",
"contact": {
"name": "Cedros"
}
},
"servers": [
{
"url": "/auth",
"description": "Default mount path (adjust based on your deployment)"
}
],
"tags": [
{"name": "discovery", "description": "Service discovery and documentation"},
{"name": "auth", "description": "Authentication (login, register, tokens)"},
{"name": "solana", "description": "Solana wallet authentication (recommended for agents)"},
{"name": "api-keys", "description": "API key management"},
{"name": "user", "description": "Current user operations"},
{"name": "organizations", "description": "Organization management"},
{"name": "members", "description": "Organization member management"},
{"name": "roles", "description": "Custom role management"},
{"name": "policies", "description": "ABAC policy management"},
{"name": "invites", "description": "Organization invitations"},
{"name": "mfa", "description": "Multi-factor authentication"},
{"name": "sessions", "description": "Session management"},
{"name": "admin", "description": "System administration"}
],
"paths": {
"/discovery": {
"get": {
"tags": ["discovery"],
"summary": "Get authentication discovery info",
"description": "Returns available authentication methods and usage instructions. Designed for AI agents to discover how to authenticate.",
"operationId": "getAuthConfig",
"responses": {
"200": {
"description": "Discovery information",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/AuthConfigResponse"}
}
}
}
}
}
},
"/openapi.json": {
"get": {
"tags": ["discovery"],
"summary": "Get OpenAPI specification",
"operationId": "getOpenApiSpec",
"responses": {
"200": {
"description": "OpenAPI 3.0 specification",
"content": {"application/json": {}}
}
}
}
},
"/health": {
"get": {
"tags": ["discovery"],
"summary": "Health check",
"operationId": "healthCheck",
"responses": {
"200": {"description": "Service is healthy"}
}
}
},
"/register": {
"post": {
"tags": ["auth"],
"summary": "Register new user",
"operationId": "register",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/RegisterRequest"}
}
}
},
"responses": {
"200": {
"description": "Registration successful",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/AuthResponse"}
}
}
}
}
}
},
"/login": {
"post": {
"tags": ["auth"],
"summary": "Login with email/password",
"operationId": "login",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/LoginRequest"}
}
}
},
"responses": {
"200": {
"description": "Login successful",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/AuthResponse"}
}
}
}
}
}
},
"/refresh": {
"post": {
"tags": ["auth"],
"summary": "Refresh access token",
"operationId": "refresh",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/RefreshRequest"}
}
}
},
"responses": {
"200": {
"description": "Token refreshed",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/AuthResponse"}
}
}
}
}
}
},
"/logout": {
"post": {
"tags": ["auth"],
"summary": "Logout (revoke session)",
"operationId": "logout",
"security": [{"bearerAuth": []}],
"responses": {
"200": {"description": "Logged out successfully"}
}
}
},
"/instant-link": {
"post": {
"tags": ["auth"],
"summary": "Send instant sign-in link",
"description": "Requests a passwordless sign-in link by email. Always returns a generic success message to prevent email enumeration.",
"operationId": "sendInstantLink",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/InstantLinkRequest"}
}
}
},
"responses": {
"200": {
"description": "Request accepted",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/MessageResponse"}
}
}
}
}
}
},
"/instant-link/verify": {
"post": {
"tags": ["auth"],
"summary": "Verify instant sign-in link and login",
"description": "Verifies a one-time token from an instant sign-in email. On success returns an authenticated session (cookies) and/or tokens. If the user has MFA enabled, returns an MFA-required response.",
"operationId": "verifyInstantLink",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/VerifyInstantLinkRequest"}
}
}
},
"responses": {
"200": {
"description": "Verification result",
"content": {
"application/json": {
"schema": {
"oneOf": [
{"$ref": "#/components/schemas/AuthResponse"},
{"$ref": "#/components/schemas/MfaRequiredResponse"}
]
}
}
}
}
}
}
},
"/solana/challenge": {
"post": {
"tags": ["solana"],
"summary": "Get Solana auth challenge",
"description": "Request a challenge nonce to sign with your Solana wallet. This is the first step in Solana wallet authentication.",
"operationId": "solanaChallenge",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/SolanaChallengeRequest"}
}
}
},
"responses": {
"200": {
"description": "Challenge created",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/SolanaChallengeResponse"}
}
}
}
}
}
},
"/solana": {
"post": {
"tags": ["solana"],
"summary": "Authenticate with Solana wallet",
"description": "Complete authentication by submitting the signed challenge. Returns JWT tokens and API key for new users.",
"operationId": "solanaAuth",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/SolanaAuthRequest"}
}
}
},
"responses": {
"200": {
"description": "Authentication successful",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/AuthResponse"}
}
}
}
}
}
},
"/api-key/validate": {
"post": {
"tags": ["api-keys"],
"summary": "Validate an API key",
"operationId": "validateApiKey",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/ValidateApiKeyRequest"}
}
}
},
"responses": {
"200": {
"description": "Validation result",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/ValidateApiKeyResponse"}
}
}
}
}
}
},
"/user": {
"get": {
"tags": ["user"],
"summary": "Get current user",
"operationId": "getUser",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {
"description": "Current user info",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/UserResponse"}
}
}
}
}
}
},
"/user/api-key": {
"get": {
"tags": ["api-keys"],
"summary": "Get current API key info",
"operationId": "getApiKey",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {
"description": "API key info (masked)",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/ApiKeyResponse"}
}
}
}
}
}
},
"/user/api-key/regenerate": {
"post": {
"tags": ["api-keys"],
"summary": "Regenerate API key",
"description": "Invalidates the current API key and generates a new one. The new key is returned in full only once.",
"operationId": "regenerateApiKey",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {
"description": "New API key generated",
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/RegenerateApiKeyResponse"}
}
}
}
}
}
},
"/orgs": {
"get": {
"tags": ["organizations"],
"summary": "List user's organizations",
"operationId": "listOrgs",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [
{
"name": "limit",
"in": "query",
"schema": {"type": "integer", "minimum": 1, "maximum": 200, "default": 50}
},
{
"name": "offset",
"in": "query",
"schema": {"type": "integer", "minimum": 0, "default": 0}
}
],
"responses": {
"200": {"description": "List of organizations"}
}
},
"post": {
"tags": ["organizations"],
"summary": "Create organization",
"operationId": "createOrg",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {"$ref": "#/components/schemas/CreateOrgRequest"}
}
}
},
"responses": {
"200": {"description": "Organization created"}
}
}
},
"/orgs/{org_id}": {
"get": {
"tags": ["organizations"],
"summary": "Get organization",
"operationId": "getOrg",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Organization details"}
}
},
"patch": {
"tags": ["organizations"],
"summary": "Update organization",
"operationId": "updateOrg",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Organization updated"}
}
},
"delete": {
"tags": ["organizations"],
"summary": "Delete organization",
"operationId": "deleteOrg",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Organization deleted"}
}
}
},
"/orgs/{org_id}/switch": {
"post": {
"tags": ["organizations"],
"summary": "Switch to organization context",
"operationId": "switchOrg",
"security": [{"bearerAuth": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Context switched"}
}
}
},
"/orgs/{org_id}/members": {
"get": {
"tags": ["members"],
"summary": "List organization members",
"operationId": "listMembers",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "List of members"}
}
}
},
"/orgs/{org_id}/members/{user_id}": {
"patch": {
"tags": ["members"],
"summary": "Update member role",
"operationId": "updateMemberRole",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [
{"$ref": "#/components/parameters/orgId"},
{"$ref": "#/components/parameters/userId"}
],
"responses": {
"200": {"description": "Role updated"}
}
},
"delete": {
"tags": ["members"],
"summary": "Remove member",
"operationId": "removeMember",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [
{"$ref": "#/components/parameters/orgId"},
{"$ref": "#/components/parameters/userId"}
],
"responses": {
"200": {"description": "Member removed"}
}
}
},
"/orgs/{org_id}/roles": {
"get": {
"tags": ["roles"],
"summary": "List custom roles",
"operationId": "listCustomRoles",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "List of roles"}
}
},
"post": {
"tags": ["roles"],
"summary": "Create custom role",
"operationId": "createCustomRole",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Role created"}
}
}
},
"/orgs/{org_id}/policies": {
"get": {
"tags": ["policies"],
"summary": "List ABAC policies",
"operationId": "listPolicies",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "List of policies"}
}
},
"post": {
"tags": ["policies"],
"summary": "Create ABAC policy",
"operationId": "createPolicy",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Policy created"}
}
}
},
"/orgs/{org_id}/invites": {
"get": {
"tags": ["invites"],
"summary": "List pending invites",
"operationId": "listInvites",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "List of invites"}
}
},
"post": {
"tags": ["invites"],
"summary": "Create invite",
"operationId": "createInvite",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [{"$ref": "#/components/parameters/orgId"}],
"responses": {
"200": {"description": "Invite created"}
}
}
},
"/invites/accept": {
"post": {
"tags": ["invites"],
"summary": "Accept invite",
"operationId": "acceptInvite",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "Invite accepted"}
}
}
},
"/authorize": {
"post": {
"tags": ["user"],
"summary": "Check authorization",
"operationId": "authorize",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "Authorization result"}
}
}
},
"/permissions": {
"post": {
"tags": ["user"],
"summary": "Get user permissions",
"operationId": "getPermissions",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "User permissions"}
}
}
},
"/sessions": {
"get": {
"tags": ["sessions"],
"summary": "List active sessions",
"operationId": "listSessions",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"parameters": [
{"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 200}},
{"name": "offset", "in": "query", "schema": {"type": "integer", "minimum": 0}}
],
"responses": {
"200": {"description": "List of sessions"}
}
},
"delete": {
"tags": ["sessions"],
"summary": "Revoke all sessions",
"operationId": "revokeAllSessions",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "Sessions revoked"}
}
}
},
"/mfa/setup": {
"post": {
"tags": ["mfa"],
"summary": "Setup MFA",
"operationId": "setupMfa",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "MFA setup initiated"}
}
}
},
"/mfa/enable": {
"post": {
"tags": ["mfa"],
"summary": "Enable MFA",
"operationId": "enableMfa",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "MFA enabled"}
}
}
},
"/mfa/disable": {
"post": {
"tags": ["mfa"],
"summary": "Disable MFA",
"operationId": "disableMfa",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "MFA disabled"}
}
}
},
"/mfa/status": {
"get": {
"tags": ["mfa"],
"summary": "Get MFA status",
"operationId": "mfaStatus",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "MFA status"}
}
}
},
"/mfa/verify": {
"post": {
"tags": ["mfa"],
"summary": "Verify MFA code (authenticated step-up)",
"operationId": "verifyMfa",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "MFA verified"}
}
}
},
"/mfa/recovery": {
"post": {
"tags": ["mfa"],
"summary": "Use recovery code (authenticated step-up)",
"operationId": "useRecoveryCode",
"security": [{"bearerAuth": []}, {"apiKey": []}],
"responses": {
"200": {"description": "Recovery code accepted"}
}
}
}
},
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT",
"description": "JWT access token"
},
"apiKey": {
"type": "http",
"scheme": "bearer",
"description": "API key (prefix: ck_)"
}
},
"parameters": {
"orgId": {
"name": "org_id",
"in": "path",
"required": true,
"schema": {"type": "string", "format": "uuid"}
},
"userId": {
"name": "user_id",
"in": "path",
"required": true,
"schema": {"type": "string", "format": "uuid"}
}
},
"schemas": {
"AuthConfigResponse": {
"type": "object",
"properties": {
"version": {"type": "string"},
"basePath": {"type": "string"},
"authMethods": {"type": "array"},
"apiKeyUsage": {"type": "object"},
"links": {"type": "object"}
}
},
"RegisterRequest": {
"type": "object",
"required": ["email", "password"],
"properties": {
"email": {"type": "string", "format": "email"},
"password": {"type": "string", "minLength": 8}
}
},
"LoginRequest": {
"type": "object",
"required": ["email", "password"],
"properties": {
"email": {"type": "string", "format": "email"},
"password": {"type": "string"}
}
},
"RefreshRequest": {
"type": "object",
"required": ["refreshToken"],
"properties": {
"refreshToken": {"type": "string"}
}
},
"InstantLinkRequest": {
"type": "object",
"required": ["email"],
"properties": {
"email": {"type": "string", "format": "email"}
}
},
"VerifyInstantLinkRequest": {
"type": "object",
"required": ["token"],
"properties": {
"token": {"type": "string"}
}
},
"MessageResponse": {
"type": "object",
"required": ["message"],
"properties": {
"message": {"type": "string"}
}
},
"MfaRequiredResponse": {
"type": "object",
"required": ["mfaRequired", "mfaToken", "userId"],
"properties": {
"mfaRequired": {"type": "boolean"},
"mfaToken": {"type": "string"},
"userId": {"type": "string", "format": "uuid"}
}
},
"SolanaChallengeRequest": {
"type": "object",
"required": ["publicKey"],
"properties": {
"publicKey": {
"type": "string",
"description": "Base58-encoded Solana public key"
}
}
},
"SolanaChallengeResponse": {
"type": "object",
"properties": {
"nonce": {
"type": "string",
"description": "Challenge nonce to sign"
},
"expiresAt": {
"type": "string",
"format": "date-time"
}
}
},
"SolanaAuthRequest": {
"type": "object",
"required": ["publicKey", "signature"],
"properties": {
"publicKey": {
"type": "string",
"description": "Base58-encoded Solana public key"
},
"signature": {
"type": "string",
"description": "Base58-encoded Ed25519 signature of the nonce"
}
}
},
"AuthResponse": {
"type": "object",
"properties": {
"user": {"$ref": "#/components/schemas/AuthUser"},
"tokens": {"$ref": "#/components/schemas/TokenPair"},
"isNewUser": {"type": "boolean"},
"apiKey": {
"type": "string",
"description": "API key (only returned for new users)"
}
}
},
"AuthUser": {
"type": "object",
"properties": {
"id": {"type": "string", "format": "uuid"},
"email": {"type": "string"},
"emailVerified": {"type": "boolean"},
"solanaPublicKey": {"type": "string"}
}
},
"TokenPair": {
"type": "object",
"properties": {
"accessToken": {"type": "string"},
"refreshToken": {"type": "string"},
"expiresIn": {"type": "integer"}
}
},
"ValidateApiKeyRequest": {
"type": "object",
"required": ["apiKey"],
"properties": {
"apiKey": {"type": "string"}
}
},
"ValidateApiKeyResponse": {
"type": "object",
"properties": {
"valid": {"type": "boolean"},
"userId": {"type": "string", "format": "uuid"}
}
},
"UserResponse": {
"type": "object",
"properties": {
"id": {"type": "string", "format": "uuid"},
"email": {"type": "string"},
"emailVerified": {"type": "boolean"},
"solanaPublicKey": {"type": "string"},
"createdAt": {"type": "string", "format": "date-time"}
}
},
"ApiKeyResponse": {
"type": "object",
"properties": {
"keyPrefix": {"type": "string", "description": "First 8 chars of key"},
"createdAt": {"type": "string", "format": "date-time"},
"lastUsedAt": {"type": "string", "format": "date-time"}
}
},
"RegenerateApiKeyResponse": {
"type": "object",
"properties": {
"apiKey": {"type": "string", "description": "New API key (shown only once)"}
}
},
"CreateOrgRequest": {
"type": "object",
"required": ["name"],
"properties": {
"name": {"type": "string"}
}
}
}
}
}