{"openapi":"3.1.0","info":{"title":"uEngage Auth API (business surface)","version":"0.1.0","description":"Service-to-service (`client_credentials`) and human (`authorization_code` + PKCE) auth for the platform. JWTs signed with RS256; verify via the JWKS document at `/auth/business/jwks.json`. Customer auth (`/auth/customer/*`) is reserved for a future iteration.","license":{"name":"Proprietary"}},"servers":[{"url":"https://api.platform.uengage.io","description":"Production"}],"paths":{"/auth/business/oauth/token":{"post":{"tags":["oauth"],"summary":"OAuth2 token endpoint (3 grant types)","description":"Mint an access token. Three grant types are supported: `client_credentials` for services (Basic auth), `authorization_code` for users completing PKCE login, and `refresh_token` for renewing user sessions. Other grants return 400 `unsupported_grant_type`.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type"],"properties":{"grant_type":{"type":"string","enum":["client_credentials","authorization_code","refresh_token"]},"scope":{"type":"string","description":"Space-separated scope list (client_credentials only)"},"code":{"type":"string","description":"authorization_code only"},"code_verifier":{"type":"string","description":"authorization_code only - PKCE verifier"},"client_id":{"type":"string"},"client_secret":{"type":"string","description":"client_credentials only (or use Basic auth)"},"redirect_uri":{"type":"string","description":"authorization_code only - must match the original /authorize request"},"refresh_token":{"type":"string","description":"refresh_token only"}}}}}},"responses":{"200":{"description":"Access token minted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"invalid_request, invalid_grant, or unsupported_grant_type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}},"401":{"description":"invalid_client (Basic auth verification failed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthError"}}}}}}},"/auth/business/authorize":{"get":{"tags":["oauth"],"summary":"Initiate browser-based user login (auth_code + PKCE)","description":"Validates the OAuth client + tenant, stashes the flow context (PKCE challenge, redirect_uri, state) under an ephemeral flow id, and returns an HTML login form. The form POSTs back to `/auth/business/login` to complete the flow.","parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["code"]}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri"}},{"name":"scope","in":"query","required":false,"schema":{"type":"string"}},{"name":"tenant","in":"query","required":true,"schema":{"type":"string"},"description":"Tenant id; validated against the business service"},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":true,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":true,"schema":{"type":"string","enum":["S256"]}},{"name":"nonce","in":"query","required":false,"schema":{"type":"string"},"description":"Round-tripped into the id token"}],"responses":{"200":{"description":"Login page HTML","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Missing / invalid parameters or unknown tenant"},"503":{"description":"Tenant lookup against the business service failed"}}}},"/auth/business/login":{"post":{"tags":["oauth"],"summary":"Submit login credentials (form-encoded)","description":"Validates `email` + `password` against the user store, mints a single-use auth code bound to the original PKCE challenge + redirect_uri, then 302s to `redirect_uri?code=...&state=...`. Failed login re-renders the form with a 401.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["flow_id","email","password"],"properties":{"flow_id":{"type":"string"},"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password"}}}}}},"responses":{"302":{"description":"Login successful — redirects to the OAuth client `redirect_uri` with `code` and `state`","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"400":{"description":"Missing fields or expired flow"},"401":{"description":"Bad credentials — login page re-rendered"}}}},"/auth/business/jwks.json":{"get":{"tags":["oauth"],"summary":"JSON Web Key Set for token signature verification","description":"Public keys for RS256 verification of access + id tokens. Cache aggressively (24h is fine) — during rotation both old and new keys are served until tokens signed with the previous key have all expired.","responses":{"200":{"description":"JWKS document","content":{"application/jwk-set+json":{"schema":{"$ref":"#/components/schemas/JsonWebKeySet"}}}}}}},"/auth/business/health":{"get":{"tags":["ops"],"summary":"Liveness probe","responses":{"200":{"description":"Service is live","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}}}}}}}}},"/auth/business/ready":{"get":{"tags":["ops"],"summary":"Readiness probe","responses":{"200":{"description":"Service is ready","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}}}}}}}}}},"components":{"schemas":{"TokenResponse":{"type":"object","required":["access_token","token_type","expires_in"],"properties":{"access_token":{"type":"string","description":"JWT, RS256, verify against /jwks.json"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer","example":1800},"scope":{"type":"string"},"refresh_token":{"type":"string","description":"Opaque, ~32 bytes base64url. Only on user grants."},"id_token":{"type":"string","description":"OIDC id token (JWT). Only on user grants."}}},"OAuthError":{"type":"object","required":["error"],"properties":{"error":{"type":"string","enum":["invalid_request","invalid_client","invalid_grant","unauthorized_client","unsupported_grant_type","invalid_scope","access_denied","server_error","temporarily_unavailable","not_implemented"]},"error_description":{"type":"string"}}},"JsonWebKeySet":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","items":{"type":"object","required":["kty","kid","alg","use","n","e"],"properties":{"kty":{"type":"string","enum":["RSA"]},"kid":{"type":"string"},"alg":{"type":"string","enum":["RS256"]},"use":{"type":"string","enum":["sig"]},"n":{"type":"string"},"e":{"type":"string"}}}}}}}}}