# Ternis Auth & SSO Complete Developer & Agent Reference (llms-full.txt) ============================================================================= System: Ternis Auth & SSO Single Identity Provider Issuer: https://auth.ternis.net Architecture: Laravel OAuth 2.0 (RFC 6749) + OpenID Connect 1.0 + UUID Primary Keys Multi-Domain: auth.ternis.net, auth.ternis.org, auth.ternis.dev, auth.t-api.de, auth.thosted.de, user.t-api.de, user.t-cdn.de, avatar.t-cdn.de, account.ternis.org Classification: Ternis Members, General Users, Paying Customers, Partners TABLE OF CONTENTS ----------------- 1. Architecture & Multi-Domain Model 2. Identification Strategy (UUIDs) 3. User Tiers & Entitlements 4. OpenID Connect Discovery & Configuration 5. OAuth 2.0 Grant Flows & PKCE 6. Endpoints Reference & Payloads 7. SDK / Client Integration Examples (TypeScript, Python, PHP) 8. Error Handling & RFC 6749 Error Codes ============================================================================= 1. ARCHITECTURE & MULTI-DOMAIN MODEL ============================================================================= Ternis Auth operates across interconnected domain clusters sharing an identical underlying state store: - `auth.ternis.net`: Global production authority for OAuth authorization and token issuance. - `auth.ternis.org`: Official community and non-profit foundation authentication server. - `auth.ternis.dev`: Sandbox environment for third-party developers, partners, and testing. - `auth.t-api.de`: Dedicated API authentication and developer gateway. - `auth.thosted.de`: Cloud Services SSO gateway and permitted OAuth callback domain. - `user.t-cdn.de` & `avatar.t-cdn.de`: Dedicated t-CDN cookieless media edge for avatars (`/{user_id}.png`, `/{username}.png`, `.svg`, etc.). - `user.t-api.de`: Dedicated user profile picture and avatar CDN (`/{user_id}.png`, `/{username}.png`, with SVG, initials, and fallback silhouette). - `account.ternis.org` & `account.ternis.net`: User-facing Self-Service Account Management Center (sessions, credentials, authorized applications, organization memberships, billing portal). Dynamic Context Resolution: All endpoints automatically resolve the requesting domain context. When sending cross-origin requests, include standard CORS headers or the `X-Ternis-Domain: auth.ternis.net` header for deterministic behavior. ============================================================================= 2. IDENTIFICATION STRATEGY (UUIDs) ============================================================================= Every persistent entity in the system utilizes standard RFC 4122 Version 4 UUIDs: - Users: `users.id` (UUID format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx) - OAuth Clients: `oauth_clients.id` (UUID) - Organizations: `organizations.id` (UUID) - Memberships: `memberships.id` (UUID) - Subscriptions: `customer_subscriptions.id` (UUID) - Partner Profiles: `partner_profiles.id` (UUID) - Audit Logs: `sso_audit_logs.id` (UUID) Foreign key relationships strictly use UUIDs with appropriate database indexing. ============================================================================= 3. USER TIERS & ENTITLEMENTS ============================================================================= Ternis Auth provides four first-class user classifications: A. TERNIS MEMBER (`ternis_member`): - Internal employees, core team engineers, and verified open-source contributors. - Entitled to `ternis:member` scope. - Includes membership affiliations in `organizations` where type = `internal_ternis`. - Granted internal repository access, moderation rights, and member badges. B. GENERAL USER (`general_user`): - Standard registered users. - Access to standard SSO across ecosystem services. - Basic scopes: `openid`, `profile`, `email`, `ternis:sso`. C. PAYING CUSTOMER (`paying_customer`): - Users with active commercial subscription plans (`starter`, `pro`, `enterprise`, `custom`). - Entitled to `ternis:customer` scope. - Access to customer support portals, billing management, and commercial API quotas. D. VERIFIED PARTNER (`partner`): - Organizations and third-party developers building on the Ternis platform. - Entitled to `ternis:partner` scope. - Allowed to self-provision confidential OAuth 2.0 clients, configure webhooks, and utilize higher API rate limits. ============================================================================= 4. OPENID CONNECT DISCOVERY ============================================================================= The discovery endpoint is available at: `GET https://auth.ternis.net/.well-known/openid-configuration` and RFC 8414 metadata at: `GET https://auth.ternis.net/.well-known/oauth-authorization-server` Example JSON Response: { "issuer": "https://auth.ternis.net", "authorization_endpoint": "https://auth.ternis.net/oauth/authorize", "token_endpoint": "https://auth.ternis.net/oauth/token", "userinfo_endpoint": "https://auth.ternis.net/oauth/userinfo", "jwks_uri": "https://auth.ternis.net/oauth/jwks", "registration_endpoint": "https://auth.ternis.net/api/v1/oauth/clients", "response_types_supported": ["code", "token"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["RS256"], "scopes_supported": [ "openid", "profile", "email", "ternis:sso", "ternis:member", "ternis:customer", "ternis:partner", "ternis:admin" ], "token_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post", "none" ], "code_challenge_methods_supported": ["S256", "plain"] } ============================================================================= 5. OAUTH 2.0 GRANT FLOWS & PKCE ============================================================================= A. Authorization Code Flow with PKCE (Recommended for SPAs, Mobile & Web): 1. Generate code_verifier (cryptographically random string 43-128 chars). 2. Calculate code_challenge = BASE64URL(SHA256(code_verifier)). 3. Redirect user to: `https://auth.ternis.net/oauth/authorize?response_type=code&client_id=CLIENT_UUID&redirect_uri=REDIRECT_URI&scope=openid%20profile%20email%20ternis:sso&state=CSRF_STATE&code_challenge=CHALLENGE&code_challenge_method=S256` 4. After user consent, user redirected to `REDIRECT_URI?code=AUTH_CODE&state=CSRF_STATE`. 5. POST exchange at `https://auth.ternis.net/oauth/token`: Headers: `Content-Type: application/x-www-form-urlencoded` Body: grant_type=authorization_code &client_id=CLIENT_UUID &client_secret=CLIENT_SECRET (optional for public clients) &redirect_uri=REDIRECT_URI &code=AUTH_CODE &code_verifier=CODE_VERIFIER B. Client Credentials Grant (Machine-to-Machine / Partner Server-to-Server): POST `https://auth.ternis.net/oauth/token` Body: grant_type=client_credentials &client_id=CLIENT_UUID &client_secret=CLIENT_SECRET &scope=ternis:partner C. Refresh Token Grant: POST `https://auth.ternis.net/oauth/token` Body: grant_type=refresh_token &refresh_token=REFRESH_TOKEN &client_id=CLIENT_UUID &client_secret=CLIENT_SECRET ============================================================================= 6. ENDPOINTS REFERENCE ============================================================================= Endpoint: GET https://auth.ternis.net/oauth/userinfo Headers: Authorization: Bearer Accept: application/json Response Schema (200 OK): { "sub": "9ba3ce8a-211b-4f9e-a841-f62f3f9821a0", "name": "Jane Doe", "preferred_username": "janedoe", "email": "jane@ternis.org", "email_verified": true, "picture": "https://avatar.ternis.net/jane.png", "user_type": "ternis_member", "role": "admin", "status": "active", "ternis_member": { "is_member": true, "member_badge": "ternis-core", "organizations": { "ternis-core-team": "Ternis Core Engineering" } }, "ternis_customer": { "is_paying": false, "plan": "free", "status": "none" }, "ternis_partner": null } Endpoint: GET https://auth.ternis.net/api/v1/user Headers: Authorization: Bearer Response includes extended properties, active subscriptions array, organizations array with full permissions objects. Endpoint: GET https://auth.ternis.net/api/domains Returns active routing metadata, CORS configuration, and list of supported ecosystem domains. Endpoint: GET https://auth.ternis.net/avatar/{identifier} (or https://user.t-api.de/{user_id}.png / https://user.t-api.de/{username}.png) Parameters: - identifier: UUID, username, or email with optional format extension (.png, .svg, .jpg, .webp) - size: integer (16 to 1024, default: 256) - fallback: 'default', 'silhouette', 'initials', or '404' - bg: optional hex background color override (e.g. '4F46E5') - color: optional hex foreground color override (e.g. 'FFFFFF') Features: - Deterministic color selection and initials rendering for users. - Automatic neutral silhouette fallback for missing/unregistered identifiers (HTTP 200 with X-Ternis-Fallback: default-avatar). - High performance, edge-cache friendly headers (Cache-Control, ETag). Endpoint: GET https://auth.ternis.net/api/plans (and GET https://auth.ternis.net/api/v1/plans) Returns public / authenticated list of commercial plans with price_cents, currency, billing_interval, and features map. Endpoint: GET https://auth.ternis.net/api/v1/user/plan Headers: Authorization: Bearer Returns user's current plan, features object, and list of active entitlement keys: { "user_id": "9ba3ce8a-211b-4f9e-a841-f62f3f9821a0", "plan": { "id": "...", "name": "Pro Tier", "slug": "pro", "price_cents": 2900, "currency": "EUR" }, "features": { "domains_limit": 50, "api_rate_limit": 5000, "ssl_certificates": true }, "entitlements": ["domains_limit", "api_rate_limit", "ssl_certificates"], "status": "active" } Endpoint: GET|POST https://auth.ternis.net/api/v1/user/addresses Headers: Authorization: Bearer Provides address book management. Addresses include standard OpenID Connect address claim representation (`formatted`, `street_address`, `locality`, `region`, `postal_code`, `country`). Endpoint: GET|POST https://auth.ternis.net/api/v1/user/emails Headers: Authorization: Bearer Manage secondary emails. Verification via POST https://auth.ternis.net/api/v1/user/emails/{id}/verify or public token link. Endpoint: GET https://auth.ternis.net/api/v1/user/balance Headers: Authorization: Bearer Returns current ecosystem credit balance (in cents) and recent transactions synchronized with ternisdomains.de: { "user_id": "9ba3ce8a-211b-4f9e-a841-f62f3f9821a0", "balance_cents": 25000, "formatted_balance": "€250.00", "currency": "EUR" } Endpoint: POST https://auth.ternis.net/api/v1/user/balance/charge Headers: Authorization: Bearer , Content-Type: application/json Atomically deducts balance for domain purchases or services: { "amount_cents": 1299, "service": "ternisdomains.de", "description": "Domain Registration: example.de (1 year)", "reference_id": "DOM-99124", "idempotency_key": "tx_98a72b6c1" } ============================================================================= 7. INTEGRATION EXAMPLES ============================================================================= TypeScript / Node.js: ```typescript import axios from 'axios'; interface TernisUserInfo { sub: string; name: string; email: string; user_type: 'ternis_member' | 'general_user' | 'paying_customer' | 'partner'; is_ternis_member?: boolean; } async function getTernisUser(accessToken: string): Promise { const response = await axios.get('https://auth.ternis.net/oauth/userinfo', { headers: { Authorization: `Bearer ${accessToken}`, Accept: 'application/json', }, }); return response.data; } ``` Python: ```python import requests def fetch_ternis_user(access_token: str) -> dict: url = "https://auth.ternis.net/oauth/userinfo" headers = { "Authorization": f"Bearer {access_token}", "Accept": "application/json" } response = requests.get(url, headers=headers) response.raise_for_status() return response.json() ``` PHP / Laravel Client: ```php use Illuminate\Support\Facades\Http; $response = Http::withToken($accessToken) ->acceptJson() ->get('https://auth.ternis.net/oauth/userinfo'); $userInfo = $response->json(); $isTernisMember = $userInfo['user_type'] === 'ternis_member'; ``` ============================================================================= 8. ERROR CODES (RFC 6749 COMPLIANT) ============================================================================= - `invalid_request`: Request is missing a parameter or includes unsupported parameter. - `invalid_client`: Client authentication failed. - `invalid_grant`: Authorization code or refresh token is invalid or expired. - `unauthorized_client`: Authenticated client not authorized to use this authorization grant type. - `unsupported_grant_type`: Authorization grant type not supported. - `invalid_scope`: Requested scope is invalid, unknown, or exceeds user entitlement.