ADR: centralize Google OAuth via Authentik social source — deferred until third Google service #5

Open
opened 2026-06-17 10:43:53 +00:00 by mathias · 0 comments
Owner

Context

Two homelab services currently do their own Google OAuth: tapir (YouTube, internal/auth/auth.go) and the planned email-triage-agent (Gmail). Each holds its own refresh tokens in SOPS and runs its own authorization code flow. As more Google-connected services are added, this pattern creates:

  • One OAuth consent per service per account (user has to authorize each service separately)
  • N separate SOPS secrets for N services × M accounts
  • No central revocation — revoking access requires finding and deleting all service-specific tokens
  • No user-facing view of "what has access to my Google account"

Proposed architecture

Use Authentik as the Google OAuth broker. One Google Social OAuth2 source in Authentik covers all services.

User → Authentik login (Google social source, one-time consent)
         ↓
Authentik holds Google refresh token per user
         ↓
tapir / email-triage-agent / future services
  → request token from Authentik for this user + required scopes
  → never hold their own Google credentials

Benefits:

  • One browser consent per user, ever (all scopes requested upfront)
  • Central revocation in Authentik UI
  • New services request tokens without new OAuth flows
  • Consistent with existing Authentik OIDC pattern (tapir-web, cobalt-dingo, claude-ai MCP)

Scope gate — do NOT implement now

This is an ADR, not an active work item. Build email-triage-agent with per-service OAuth first (same as tapir today) to ship value fast. Migrate both to Authentik-centralized tokens as a follow-up once:

  1. email-triage-agent Phase 1 is live and proven
  2. A third Google-connected service is being planned

The migration then covers tapir + email-triage-agent + the new service in one pass, paying the migration cost once.

What the migration would involve

  1. Configure Authentik Google Social OAuth2 source with all required scopes:

    • youtube.readonly, youtube.force-ssl (tapir)
    • gmail.readonly, gmail.modify (email-triage-agent)
    • Any future scopes
  2. Build a token-forwarding mechanism: services call an Authentik endpoint to get a short-lived access token for a given user. Authentik handles refresh internally.

  3. Remove per-service SOPS secrets and tapir auth / email-triage-agent auth CLI subcommands.

  4. Update tapir and email-triage-agent to fetch tokens from Authentik instead of SOPS.

Risk

Deferred — not yet assessed. Assess at migration time. Key risk: Authentik token forwarding requires a custom Property Mapping or a small proxy service — not out-of-the-box. Prototype before committing.

Decision

Deferred. Build per-service OAuth now. Migrate to Authentik-centralized when the third Google service materializes.

Related

  • homelab#3 — ntfy fix
  • homelab#4 — email-triage-agent
  • mathias/tapir internal/auth/auth.go — current per-service OAuth pattern
  • ADR-0001 — Authentik migration from Dex (precedent for IdP centralization)
## Context Two homelab services currently do their own Google OAuth: tapir (YouTube, `internal/auth/auth.go`) and the planned email-triage-agent (Gmail). Each holds its own refresh tokens in SOPS and runs its own authorization code flow. As more Google-connected services are added, this pattern creates: - One OAuth consent per service per account (user has to authorize each service separately) - N separate SOPS secrets for N services × M accounts - No central revocation — revoking access requires finding and deleting all service-specific tokens - No user-facing view of "what has access to my Google account" ## Proposed architecture Use Authentik as the Google OAuth broker. One Google Social OAuth2 source in Authentik covers all services. ``` User → Authentik login (Google social source, one-time consent) ↓ Authentik holds Google refresh token per user ↓ tapir / email-triage-agent / future services → request token from Authentik for this user + required scopes → never hold their own Google credentials ``` Benefits: - One browser consent per user, ever (all scopes requested upfront) - Central revocation in Authentik UI - New services request tokens without new OAuth flows - Consistent with existing Authentik OIDC pattern (tapir-web, cobalt-dingo, claude-ai MCP) ## Scope gate — do NOT implement now This is an ADR, not an active work item. Build email-triage-agent with per-service OAuth first (same as tapir today) to ship value fast. Migrate both to Authentik-centralized tokens as a follow-up once: 1. email-triage-agent Phase 1 is live and proven 2. A third Google-connected service is being planned The migration then covers tapir + email-triage-agent + the new service in one pass, paying the migration cost once. ## What the migration would involve 1. Configure Authentik Google Social OAuth2 source with all required scopes: - `youtube.readonly`, `youtube.force-ssl` (tapir) - `gmail.readonly`, `gmail.modify` (email-triage-agent) - Any future scopes 2. Build a token-forwarding mechanism: services call an Authentik endpoint to get a short-lived access token for a given user. Authentik handles refresh internally. 3. Remove per-service SOPS secrets and `tapir auth` / `email-triage-agent auth` CLI subcommands. 4. Update tapir and email-triage-agent to fetch tokens from Authentik instead of SOPS. ## Risk **Deferred — not yet assessed.** Assess at migration time. Key risk: Authentik token forwarding requires a custom Property Mapping or a small proxy service — not out-of-the-box. Prototype before committing. ## Decision **Deferred.** Build per-service OAuth now. Migrate to Authentik-centralized when the third Google service materializes. ## Related - homelab#3 — ntfy fix - homelab#4 — email-triage-agent - `mathias/tapir internal/auth/auth.go` — current per-service OAuth pattern - ADR-0001 — Authentik migration from Dex (precedent for IdP centralization)
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/homelab#5