# ๐Ÿชช SSO & Identity > [!NOTE] > Authentik is the identity provider for this fleet โ€” self-hosted rather than an external IdP, for the same reason Vault is self-hosted in [`docs/secrets-and-pki.md`](secrets-and-pki.md): internal-only apps shouldn't need to trust a third party just to authenticate a login, and the two-zone reverse-proxy model in [`docs/dns-naming.md`](dns-naming.md) only works if the identity provider itself lives inside that same trust boundary. ## Dual-zone registration Every new app gets a Proxy Provider + Application pair registered per reverse-proxy zone it's actually exposed on โ€” up to two registrations for the same app, one per zone from [`docs/dns-naming.md`](dns-naming.md), driven by actual need rather than registering every app on both zones by default. ## OIDC login: the redirect crosses zones, every time For an app using native OIDC, the login always follows the same path: 1. User opens the app on the **browser-facing zone**. 2. The app redirects the browser to Authentik to do the actual OAuth authorize/token exchange. 3. That exchange happens against Authentik's own address on the **service-to-service zone** โ€” reachable from a browser for this one hop specifically, even though that zone doesn't get the mutual-TLS treatment the browser-facing zone does. 4. On success, the browser lands back on the app, still on the browser-facing zone. So an app's OIDC discovery/authority setting always points at the service-to-service zone, even though the app itself is normally reached on the browser-facing zone โ€” the two zones are defined in [`docs/dns-naming.md`](dns-naming.md). This is confirmed against one real app's actual login flow, not assumed to hold for every app without checking. Every other app-specific setting (token lifetime, scopes, flow type) doesn't generalize the same way โ€” each app's own OIDC documentation gets read fresh rather than copying another app's provider config, since those details genuinely differ per vendor. ## Git access: least privilege, not the admin account ```mermaid flowchart LR CI["CI / Orchestration engine
see docs/orchestration.md"] -->|scoped write| Bot["Dedicated bot account
non-admin"] Bot --> Repo["Gitea"] Other["Other hosts"] -->|read-only| Deploy["Deploy keys
per host"] Deploy --> Repo ``` Automation should never run with more privilege than it needs. CI and orchestration pushes (the flows described in [`docs/orchestration.md`](orchestration.md)) run through a dedicated, non-admin bot account with scoped write access โ€” never through an administrator identity. Hosts that only need to *read* get separate read-only deploy keys instead of any shared credential. The practical payoff: if an automation credential ever leaks, the blast radius is "can push to specific repos," not "has full admin control of the Git server." --- Related: [`docs/dns-naming.md`](dns-naming.md), [`docs/orchestration.md`](orchestration.md), [`docs/secrets-and-pki.md`](secrets-and-pki.md) ยท Stacks: [`stacks/identity-and-security/authentik/`](../stacks/identity-and-security/authentik/), [`stacks/platform/gitea/`](../stacks/platform/gitea/)