{"openapi":"3.1.0","info":{"title":"Silverpine SSO API","version":"0.1.0","description":"OAuth/OIDC, native mobile handoff, app-user, session, and admin automation APIs for Silverpine SSO."},"servers":[{"url":"https://sso.spsw.dev"}],"tags":[{"name":"Public"},{"name":"OAuth and OIDC"},{"name":"Mobile"},{"name":"Password Reset"},{"name":"Admin Apps"},{"name":"Admin Users"},{"name":"Admin Sessions"},{"name":"API Help"}],"security":[],"components":{"securitySchemes":{"adminBasic":{"type":"http","scheme":"basic","description":"Operational Basic admin credentials."},"adminBearer":{"type":"http","scheme":"bearer","description":"Operational admin bearer token."},"accessToken":{"type":"http","scheme":"bearer","description":"User or client access token returned by /token or /mobile/complete."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"error_description":{"type":"string"}}},"Health":{"type":"object","required":["ok","service"],"properties":{"ok":{"type":"boolean","example":true},"service":{"type":"string","example":"sso-server"}}},"App":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"clientId":{"type":"string"},"clientSecret":{"type":"string","description":"Returned only when an app or secret is created/rotated."},"authMode":{"type":"string","enum":["passwordless","password","client_credentials"]},"clientCredentialsScopes":{"type":"string","example":"api:read api:write"},"allowRefreshTokens":{"type":"boolean"},"requireTwoFactor":{"type":"boolean","description":"Per-app policy flag for requiring 2FA. Enforcement is handled by the MFA login flow."},"twoFactorMethods":{"type":"array","items":{"type":"string","enum":["totp","email","sms"]},"description":"Allowed 2FA methods for this app. totp means authenticator app."},"hasLogo":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"appName":{"type":"string"},"appClientId":{"type":"string"},"appAuthMode":{"type":"string","enum":["passwordless","password","client_credentials"]},"email":{"type":"string","format":"email"},"username":{"type":"string"},"displayName":{"type":"string"},"phoneNumber":{"type":"string","nullable":true},"userType":{"type":"string","enum":["standard","superuser"]},"enabled":{"type":"boolean"},"hasPassword":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"MfaFactor":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["totp","email","sms"]},"label":{"type":"string","nullable":true},"verifiedAt":{"type":"string","format":"date-time","nullable":true},"disabledAt":{"type":"string","format":"date-time","nullable":true},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Session":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"revokedAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date-time"}}},"TokenResponse":{"type":"object","properties":{"token_type":{"type":"string","example":"Bearer"},"access_token":{"type":"string"},"expires_in":{"type":"integer"},"expires_at":{"type":"string","format":"date-time"},"refresh_token":{"type":"string"},"refresh_expires_at":{"type":"string","format":"date-time"},"id_token":{"type":"string"},"scope":{"type":"string","example":"openid email profile"},"token_use":{"type":"string","enum":["access_token","client_credentials"]},"user":{"$ref":"#/components/schemas/User"},"app":{"$ref":"#/components/schemas/App"}}},"LoginLink":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"expiresAt":{"type":"string","format":"date-time"},"usedAt":{"type":"string","format":"date-time","nullable":true}}},"PasswordReset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"appId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"expiresAt":{"type":"string","format":"date-time"},"usedAt":{"type":"string","format":"date-time","nullable":true}}}}},"paths":{"/health":{"get":{"tags":["Public"],"summary":"Service health","responses":{"200":{"description":"Service is healthy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/.well-known/openid-configuration":{"get":{"tags":["OAuth and OIDC"],"summary":"OIDC discovery metadata","responses":{"200":{"description":"OIDC provider metadata."}}}},"/jwks.json":{"get":{"tags":["OAuth and OIDC"],"summary":"OIDC signing keys","responses":{"200":{"description":"JWKS containing active and previous public signing keys."}}}},"/authorize":{"get":{"tags":["OAuth and OIDC"],"summary":"Render or describe hosted OAuth login","parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["code"]},"description":"Requests an OAuth authorization 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","default":"openid email profile"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","enum":["S256"]}},{"name":"response_format","in":"query","required":false,"schema":{"type":"string","enum":["json"]}}],"responses":{"200":{"description":"HTML sign-in page, or JSON form details when response_format=json."},"400":{"description":"Invalid authorization request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["OAuth and OIDC"],"summary":"Submit hosted OAuth login","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"response_type":{"type":"string","example":"code"},"client_id":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"scope":{"type":"string","example":"openid email profile"},"state":{"type":"string"},"code_challenge":{"type":"string"},"code_challenge_method":{"type":"string","example":"S256"},"email":{"type":"string","format":"email","description":"Passwordless apps."},"username":{"type":"string","description":"Username/password apps."},"password":{"type":"string","format":"password","description":"Username/password apps."},"response_format":{"type":"string","enum":["json"]}}}},"application/json":{"schema":{"type":"object","properties":{"response_type":{"type":"string","example":"code"},"client_id":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"scope":{"type":"string","example":"openid email profile"},"state":{"type":"string"},"code_challenge":{"type":"string"},"code_challenge_method":{"type":"string","example":"S256"},"email":{"type":"string","format":"email","description":"Passwordless apps."},"username":{"type":"string","description":"Username/password apps."},"password":{"type":"string","format":"password","description":"Username/password apps."},"response_format":{"type":"string","enum":["json"]}}}}}},"responses":{"200":{"description":"Neutral login-link confirmation or JSON success."},"202":{"description":"2FA is required before final redirect; JSON responses include a challenge token and verify URL."},"303":{"description":"Successful username/password login redirects to the app with an authorization code."},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Username/password login failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mfa/challenge":{"post":{"tags":["OAuth and OIDC"],"summary":"Verify an MFA login challenge","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"challenge":{"type":"string"},"code":{"type":"string","pattern":"^[0-9]{6}$"},"response_format":{"type":"string","enum":["json"]}}}},"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"string"},"code":{"type":"string","pattern":"^[0-9]{6}$"},"response_format":{"type":"string","enum":["json"]}}}}}},"responses":{"200":{"description":"JSON success for clients that requested JSON."},"302":{"description":"Successful mobile login-link challenge redirects to the native callback with a ticket."},"303":{"description":"Successful browser challenge redirects to the app with an authorization code, or mobile password challenge redirects to the native callback with a ticket."},"400":{"description":"Code did not verify.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Challenge expired or is no longer valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many failed challenge attempts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mfa/setup/totp":{"post":{"tags":["OAuth and OIDC"],"summary":"Set up authenticator-app MFA for a pending sign-in","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"challenge":{"type":"string"},"code":{"type":"string","pattern":"^[0-9]{6}$","description":"Required to verify setup; omit to retrieve JSON setup details."},"response_format":{"type":"string","enum":["json"]}}}},"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"string"},"code":{"type":"string","pattern":"^[0-9]{6}$","description":"Required to verify setup; omit to retrieve JSON setup details."},"response_format":{"type":"string","enum":["json"]}}}}}},"responses":{"200":{"description":"Hosted authenticator setup page."},"202":{"description":"Authenticator setup details for JSON clients.","content":{"application/json":{"schema":{"type":"object"}}}},"303":{"description":"Successful setup redirects to the app with an authorization code, or to the native callback with a ticket."},"400":{"description":"Invalid setup request or code mismatch.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mfa/setup/sms":{"post":{"tags":["OAuth and OIDC"],"summary":"Start SMS MFA enrollment for a pending sign-in","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["challenge","phoneNumber"],"properties":{"challenge":{"type":"string"},"phoneNumber":{"type":"string","example":"+1 503 555 0199"}}}}}},"responses":{"200":{"description":"Hosted SMS challenge page after code delivery."},"202":{"description":"SMS setup code sent for JSON clients.","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid setup request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mfa/challenge/totp":{"post":{"tags":["OAuth and OIDC"],"summary":"Verify a TOTP MFA login challenge","deprecated":true,"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"challenge":{"type":"string"},"code":{"type":"string","pattern":"^[0-9]{6}$"},"response_format":{"type":"string","enum":["json"]}}}},"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"string"},"code":{"type":"string","pattern":"^[0-9]{6}$"},"response_format":{"type":"string","enum":["json"]}}}}}},"responses":{"200":{"description":"JSON success for clients that requested JSON."},"302":{"description":"Successful mobile login-link challenge redirects to the native callback with a ticket."},"303":{"description":"Successful browser challenge redirects to the app with an authorization code, or mobile password challenge redirects to the native callback with a ticket."},"400":{"description":"Code did not verify.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Challenge expired or is no longer valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many failed challenge attempts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/token":{"post":{"tags":["OAuth and OIDC"],"summary":"Exchange authorization code, refresh token, or client credentials","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token","client_credentials"],"default":"authorization_code"},"client_id":{"type":"string"},"client_secret":{"type":"string","format":"password"},"redirect_uri":{"type":"string","format":"uri"},"code":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"scope":{"type":"string","description":"Allowed scope subset for client_credentials."}}}},"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token","client_credentials"],"default":"authorization_code"},"client_id":{"type":"string"},"client_secret":{"type":"string","format":"password"},"redirect_uri":{"type":"string","format":"uri"},"code":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"scope":{"type":"string","description":"Allowed scope subset for client_credentials."}}}}}},"responses":{"200":{"description":"Token response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"OAuth error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Client authentication failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/userinfo":{"get":{"tags":["OAuth and OIDC"],"summary":"Read claims for an access token","security":[{"accessToken":[]}],"responses":{"200":{"description":"OIDC user claims."},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/introspect":{"post":{"tags":["OAuth and OIDC"],"summary":"Introspect an access or refresh token","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","format":"password"},"token":{"type":"string"}}}},"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","format":"password"},"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Token activity metadata."},"400":{"description":"OAuth error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/revoke":{"post":{"tags":["OAuth and OIDC"],"summary":"Revoke an access or refresh token","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","format":"password"},"token":{"type":"string"}}}},"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"client_secret":{"type":"string","format":"password"},"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Revocation result."},"400":{"description":"OAuth error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/logout/oidc":{"get":{"tags":["OAuth and OIDC"],"summary":"RP-initiated logout","parameters":[{"name":"client_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"post_logout_redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"303":{"description":"Redirects to an allowed post-logout URI or the SSO landing page."},"400":{"description":"Invalid logout request."}}}},"/connect/logout":{"get":{"tags":["OAuth and OIDC"],"summary":"RP-initiated logout","parameters":[{"name":"client_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"post_logout_redirect_uri","in":"query","required":false,"schema":{"type":"string","format":"uri"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"303":{"description":"Redirects to an allowed post-logout URI or the SSO landing page."},"400":{"description":"Invalid logout request."}}}},"/password-reset/request":{"get":{"tags":["Password Reset"],"summary":"Render username/password app reset request form","parameters":[{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"HTML reset request form."},"400":{"description":"Invalid client or auth mode."}}},"post":{"tags":["Password Reset"],"summary":"Submit self-service password reset request","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"identifier":{"type":"string","description":"Email or username."}}}},"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"identifier":{"type":"string","description":"Email or username."}}}}}},"responses":{"200":{"description":"Neutral confirmation page."},"400":{"description":"Invalid request."},"503":{"description":"Password reset email delivery is not configured."}}}},"/password-reset/{token}":{"get":{"tags":["Password Reset"],"summary":"Render password reset form","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"HTML reset form."},"404":{"description":"Unknown token."},"410":{"description":"Expired or used token."}}},"post":{"tags":["Password Reset"],"summary":"Complete password reset","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"password":{"type":"string","format":"password"},"confirmPassword":{"type":"string","format":"password"}}}},"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","format":"password"},"confirmPassword":{"type":"string","format":"password"}}}}}},"responses":{"200":{"description":"HTML completion page."},"400":{"description":"Invalid password."},"410":{"description":"Expired or used token."}}}},"/mobile/authorize":{"get":{"tags":["Mobile"],"summary":"Render or describe native mobile authorization","parameters":[{"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","default":"openid email profile"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge","in":"query","required":false,"schema":{"type":"string"}},{"name":"code_challenge_method","in":"query","required":false,"schema":{"type":"string","enum":["S256"]}},{"name":"response_format","in":"query","required":false,"schema":{"type":"string","enum":["json"]}}],"responses":{"200":{"description":"HTML mobile login page, or JSON form details when response_format=json."},"400":{"description":"Invalid mobile authorization request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Mobile"],"summary":"Submit native mobile authorization","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"scope":{"type":"string","example":"openid email profile"},"state":{"type":"string"},"code_challenge":{"type":"string"},"code_challenge_method":{"type":"string","example":"S256"},"email":{"type":"string","format":"email","description":"Passwordless apps."},"username":{"type":"string","description":"Username/password apps."},"password":{"type":"string","format":"password","description":"Username/password apps."},"response_format":{"type":"string","enum":["json"]}}}},"application/json":{"schema":{"type":"object","properties":{"client_id":{"type":"string"},"redirect_uri":{"type":"string","format":"uri"},"scope":{"type":"string","example":"openid email profile"},"state":{"type":"string"},"code_challenge":{"type":"string"},"code_challenge_method":{"type":"string","example":"S256"},"email":{"type":"string","format":"email","description":"Passwordless apps."},"username":{"type":"string","description":"Username/password apps."},"password":{"type":"string","format":"password","description":"Username/password apps."},"response_format":{"type":"string","enum":["json"]}}}}}},"responses":{"200":{"description":"Neutral login-link confirmation or JSON success."},"202":{"description":"2FA is required before final redirect; JSON responses include a challenge token and verify URL."},"303":{"description":"Successful username/password login redirects directly to the native callback with a ticket using POST/Redirect/Get."},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mobile/complete":{"post":{"tags":["Mobile"],"summary":"Redeem a native mobile handoff ticket","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id","ticket"],"properties":{"client_id":{"type":"string"},"ticket":{"type":"string"},"code_verifier":{"type":"string"}}}}}},"responses":{"200":{"description":"Token response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"OAuth error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/apps":{"get":{"tags":["Admin Apps"],"summary":"List apps visible to the current admin","security":[{"adminBasic":[]},{"adminBearer":[]}],"responses":{"200":{"description":"Visible apps.","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Admin Apps"],"summary":"Create an app","security":[{"adminBasic":[]},{"adminBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"clientId":{"type":"string"},"authMode":{"type":"string","enum":["passwordless","password"]},"requireTwoFactor":{"type":"boolean"},"twoFactorMethods":{"type":"array","items":{"type":"string","enum":["totp","email","sms"]}}}}}}},"responses":{"201":{"description":"Created app.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"}}}}}},"400":{"description":"Invalid app request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/apps/{appId}":{"delete":{"tags":["Admin Apps"],"summary":"Delete an app","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}]],"responses":{"200":{"description":"Deleted app.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"App not found, or not visible to this admin.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/apps/{appId}/secret":{"post":{"tags":["Admin Apps"],"summary":"Rotate app client secret","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Updated app and new client secret.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"},"clientSecret":{"type":"string"}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"App not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/apps/{appId}/redirect-settings":{"get":{"tags":["Admin Apps"],"summary":"Read redirect, CORS, post-logout, auth-mode, refresh-token, and 2FA settings","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"App redirect settings."},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"App not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Admin Apps"],"summary":"Replace redirect settings and app login policy","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"redirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"allowedOrigins":{"type":"array","items":{"type":"string","format":"uri"}},"postLogoutRedirectUris":{"type":"array","items":{"type":"string","format":"uri"}},"allowRefreshTokens":{"type":"boolean"},"requireTwoFactor":{"type":"boolean"},"twoFactorMethods":{"type":"array","items":{"type":"string","enum":["totp","email","sms"]}},"authMode":{"type":"string","enum":["passwordless","password"]}}}}}},"responses":{"200":{"description":"Updated redirect settings."},"400":{"description":"Invalid redirect settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/apps/{appId}/logo":{"get":{"tags":["Public"],"summary":"Fetch an app logo","parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Logo image."},"404":{"description":"Logo not found."}}}},"/api/users":{"get":{"tags":["Admin Users"],"summary":"List users visible to the current admin","security":[{"adminBasic":[]},{"adminBearer":[]}],"responses":{"200":{"description":"Visible users.","content":{"application/json":{"schema":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Admin Users"],"summary":"Create an app user by appId","security":[{"adminBasic":[]},{"adminBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["appId","email"],"properties":{"appId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"username":{"type":"string"},"displayName":{"type":"string"},"phoneNumber":{"type":"string"},"userType":{"type":"string","enum":["standard","superuser"]},"password":{"type":"string","format":"password","description":"Only used for username/password apps."}}}}}},"responses":{"201":{"description":"Created user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid user request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Email or username already exists for this app.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/apps/{appId}/users":{"get":{"tags":["Admin Users"],"summary":"List users for an app","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"App users.","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"$ref":"#/components/schemas/App"},"users":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"App not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Admin Users"],"summary":"Create a user for an app","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"appId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"username":{"type":"string"},"displayName":{"type":"string"},"phoneNumber":{"type":"string"},"userType":{"type":"string","enum":["standard","superuser"]},"password":{"type":"string","format":"password","description":"Only used for username/password apps."}}}}}},"responses":{"201":{"description":"Created user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid user request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Email or username already exists for this app.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/status":{"post":{"tags":["Admin Users"],"summary":"Enable or disable an app user","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"revokedSessions":{"type":"integer"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/email":{"post":{"tags":["Admin Users"],"summary":"Change an app user's email address","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","example":"user@example.com"}}}}}},"responses":{"200":{"description":"Updated user. Pending emailed login/password-reset links are expired and email MFA factors are disabled when the address changes.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"emailChanged":{"type":"boolean"},"disabledEmailFactor":{"type":"boolean"},"expiredLoginLinks":{"type":"integer"},"expiredPasswordResetTokens":{"type":"integer"}}}}}},"400":{"description":"Invalid email address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Email already exists for this app.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/phone":{"post":{"tags":["Admin Users"],"summary":"Set or clear an app user's SMS phone number","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"phoneNumber":{"type":"string","nullable":true,"example":"+1 503 555 0199"}}}}}},"responses":{"200":{"description":"Updated user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"400":{"description":"Invalid phone number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/role":{"post":{"tags":["Admin Users"],"summary":"Change an app user role","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userType"],"properties":{"userType":{"type":"string","enum":["standard","superuser"]}}}}}},"responses":{"200":{"description":"Updated user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"revokedSessions":{"type":"integer"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/password":{"post":{"tags":["Admin Users"],"summary":"Set or reset a username/password app user's password","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["password"],"properties":{"password":{"type":"string","format":"password","minLength":8}}}}}},"responses":{"200":{"description":"Updated user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"revokedSessions":{"type":"integer"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/mfa":{"get":{"tags":["Admin Users"],"summary":"List MFA factors for an app user","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"User MFA factors.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"},"factors":{"type":"array","items":{"$ref":"#/components/schemas/MfaFactor"}}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/mfa/totp/start":{"post":{"tags":["Admin Users"],"summary":"Start authenticator-app TOTP enrollment for an app user","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"TOTP enrollment started. Store the returned secret immediately; it is not returned again.","content":{"application/json":{"schema":{"type":"object","properties":{"factor":{"$ref":"#/components/schemas/MfaFactor"},"secret":{"type":"string"},"otpauthUrl":{"type":"string"}}}}}},"400":{"description":"Enrollment could not be started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/mfa/totp/verify":{"post":{"tags":["Admin Users"],"summary":"Verify an authenticator-app TOTP enrollment","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["factorId","code"],"properties":{"factorId":{"type":"string","format":"uuid"},"code":{"type":"string","pattern":"^[0-9]{6}$"}}}}}},"responses":{"200":{"description":"TOTP factor verified.","content":{"application/json":{"schema":{"type":"object","properties":{"factor":{"$ref":"#/components/schemas/MfaFactor"}}}}}},"400":{"description":"Code did not verify.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/mfa/{factorId}/disable":{"post":{"tags":["Admin Users"],"summary":"Disable a user's MFA factor","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],[{"name":"factorId","in":"path","required":true,"schema":{"type":"string"}}]],"responses":{"200":{"description":"MFA factor disabled.","content":{"application/json":{"schema":{"type":"object","properties":{"factor":{"$ref":"#/components/schemas/MfaFactor"}}}}}},"400":{"description":"MFA factor is invalid for this user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/password-reset":{"post":{"tags":["Admin Users"],"summary":"Send a password reset email for a username/password app user","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"includeUrl":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Password reset was created and sent.","content":{"application/json":{"schema":{"type":"object","properties":{"passwordReset":{"$ref":"#/components/schemas/PasswordReset"},"url":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request or app mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Password reset delivery is not configured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}/login-links":{"post":{"tags":["Admin Users"],"summary":"Create and optionally send a login link for an app user","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"redirectUri":{"type":"string","format":"uri"},"scope":{"type":"string","example":"openid email profile"},"state":{"type":"string"},"codeChallenge":{"type":"string"},"codeChallengeMethod":{"type":"string","example":"S256"},"sendEmail":{"type":"boolean","default":true},"includeUrl":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Login link was created.","content":{"application/json":{"schema":{"type":"object","properties":{"loginLink":{"$ref":"#/components/schemas/LoginLink"},"url":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Login link delivery is not configured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/users/{userId}":{"delete":{"tags":["Admin Users"],"summary":"Delete an app user","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted user.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/User"}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"User not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/sessions/{sessionId}/revoke":{"post":{"tags":["Admin Sessions"],"summary":"Revoke a session by id","security":[{"adminBasic":[]},{"adminBearer":[]}],"parameters":[{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked session.","content":{"application/json":{"schema":{"type":"object","properties":{"session":{"$ref":"#/components/schemas/Session"}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Session not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/help":{"get":{"tags":["API Help"],"summary":"Open logged-in API help chat","responses":{"200":{"description":"HTML API help chat page."},"303":{"description":"Redirect to landing when not logged in."}}}},"/api/help/chat":{"post":{"tags":["API Help"],"summary":"Ask a docs-scoped SSO API help question","security":[{"adminBasic":[]},{"adminBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{"message":{"type":"string"},"messages":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"API help answer.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"scope":{"type":"string"},"answer":{"type":"string"}}}}}},"401":{"description":"Admin authentication required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"API help is not configured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}