# Kaboot Authentik Blueprint - PRODUCTION # Copy this file to kaboot-setup-production.yaml and update the domain. # # IMPORTANT: Remove or rename kaboot-setup.yaml when using this file # to avoid conflicting configurations. # # Prerequisites: # - Set AUTHENTIK_BOOTSTRAP_PASSWORD and AUTHENTIK_BOOTSTRAP_TOKEN in .env # - Mount this directory to /blueprints/custom in docker-compose.yml # - Update KABOOT_DOMAIN and AUTH_DOMAIN below with your actual domains # # yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json --- version: 1 metadata: name: Kaboot Application Setup (Production) labels: blueprints.goauthentik.io/description: "Complete Kaboot OAuth2/OIDC setup for production" context: kaboot_domain: kaboot.example.com auth_domain: auth.example.com entries: # ═══════════════════════════════════════════════════════════════════════════════ # CUSTOM INVALIDATION FLOW (must be defined before brand that references it) # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-logout-stage model: authentik_stages_user_logout.userlogoutstage identifiers: name: kaboot-logout attrs: name: kaboot-logout - id: kaboot-redirect-stage model: authentik_stages_redirect.redirectstage identifiers: name: kaboot-redirect-to-app attrs: name: kaboot-redirect-to-app mode: static target_static: !Format ["https://%s", !Context kaboot_domain] - id: kaboot-invalidation-flow model: authentik_flows.flow identifiers: slug: kaboot-invalidation-flow attrs: name: Kaboot Logout Flow title: Logging out... slug: kaboot-invalidation-flow designation: invalidation authentication: none background: /media/branding/background.svg - id: kaboot-invalidation-logout-binding model: authentik_flows.flowstagebinding identifiers: target: !KeyOf kaboot-invalidation-flow stage: !KeyOf kaboot-logout-stage attrs: order: 0 evaluate_on_plan: true re_evaluate_policies: false - id: kaboot-invalidation-redirect-binding model: authentik_flows.flowstagebinding identifiers: target: !KeyOf kaboot-invalidation-flow stage: !KeyOf kaboot-redirect-stage attrs: order: 10 evaluate_on_plan: true re_evaluate_policies: false # ═══════════════════════════════════════════════════════════════════════════════ # FLOW BACKGROUNDS # ═══════════════════════════════════════════════════════════════════════════════ - id: update-authentication-flow-background model: authentik_flows.flow identifiers: slug: default-authentication-flow attrs: title: Welcome to Kaboot! background: /media/branding/background.svg - id: update-authorization-flow-background model: authentik_flows.flow identifiers: slug: default-provider-authorization-implicit-consent attrs: background: /media/branding/background.svg # NOTE: enrollment-flow background is set in the ENROLLMENT FLOW section below # (cannot update a flow before it's created) # ═══════════════════════════════════════════════════════════════════════════════ # GROUPS # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-users-group model: authentik_core.group identifiers: name: kaboot-users attrs: name: kaboot-users - id: kaboot-ai-access-group model: authentik_core.group identifiers: name: kaboot-ai-access attrs: name: kaboot-ai-access # ═══════════════════════════════════════════════════════════════════════════════ # GROUPS SCOPE MAPPING # ═══════════════════════════════════════════════════════════════════════════════ - id: groups-scope-mapping model: authentik_providers_oauth2.scopemapping identifiers: managed: goauthentik.io/providers/oauth2/scope-kaboot-groups attrs: name: "Kaboot Groups Scope" scope_name: groups description: "Include user groups in the token" expression: | return [group.name for group in user.ak_groups.all()] # ═══════════════════════════════════════════════════════════════════════════════ # OAUTH2/OIDC PROVIDER # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-oauth2-provider model: authentik_providers_oauth2.oauth2provider identifiers: name: Kaboot OAuth2 attrs: name: Kaboot OAuth2 authorization_flow: !Find [authentik_flows.flow, [slug, default-provider-authorization-implicit-consent]] invalidation_flow: !KeyOf kaboot-invalidation-flow signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Internal JWT Certificate]] client_type: public client_id: kaboot-spa redirect_uris: - url: !Format ["https://%s/callback", !Context kaboot_domain] matching_mode: strict - url: !Format ["https://%s/silent-renew.html", !Context kaboot_domain] matching_mode: strict - url: !Format ["https://%s", !Context kaboot_domain] matching_mode: strict access_code_validity: minutes=1 access_token_validity: minutes=30 refresh_token_validity: days=30 sub_mode: hashed_user_id include_claims_in_id_token: true issuer_mode: per_provider property_mappings: - !Find [authentik_providers_oauth2.scopemapping, [scope_name, openid]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, profile]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, email]] - !Find [authentik_providers_oauth2.scopemapping, [scope_name, offline_access]] - !KeyOf groups-scope-mapping # ═══════════════════════════════════════════════════════════════════════════════ # APPLICATION # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-application model: authentik_core.application identifiers: slug: kaboot attrs: name: Kaboot slug: kaboot provider: !KeyOf kaboot-oauth2-provider policy_engine_mode: any meta_launch_url: !Format ["https://%s", !Context kaboot_domain] - id: kaboot-group-policy-binding model: authentik_policies.policybinding identifiers: target: !KeyOf kaboot-application group: !KeyOf kaboot-users-group attrs: order: 0 enabled: true negate: false timeout: 30 # ═══════════════════════════════════════════════════════════════════════════════ # BRANDING (must be after application is created) # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-brand model: authentik_brands.brand identifiers: domain: !Context auth_domain attrs: domain: !Context auth_domain default: false branding_title: Kaboot branding_logo: /media/branding/logo.svg branding_favicon: /media/branding/logo.svg flow_authentication: !Find [authentik_flows.flow, [slug, default-authentication-flow]] flow_invalidation: !KeyOf kaboot-invalidation-flow flow_user_settings: !Find [authentik_flows.flow, [slug, default-user-settings-flow]] default_application: !KeyOf kaboot-application attributes: settings: theme: base: light css: | :root { --ak-accent: #2563eb; --ak-primary: #2563eb; --ak-primary-dark: #1e40af; --ak-primary-light: #60a5fa; --ak-error: #ef4444; --ak-success: #22c55e; --pf-global--FontFamily--sans-serif: "Inter", system-ui, -apple-system, sans-serif; } body { background-color: #2563eb !important; } .pf-c-login__main { background-color: #ffffff !important; border-radius: 2rem !important; box-shadow: 0 10px 0 rgba(0,0,0,0.1) !important; padding: 3rem !important; max-width: 500px !important; margin: 0 auto; } .pf-c-form-control { border: 2px solid #e5e7eb !important; border-radius: 1rem !important; padding: 0.75rem 1rem !important; font-weight: 600 !important; color: #333 !important; font-size: 1rem !important; box-shadow: none !important; transition: all 0.2s ease !important; } .pf-c-form-control:focus { border-color: #2563eb !important; outline: none !important; } .pf-c-button.pf-m-primary { background-color: #333333 !important; color: #ffffff !important; border: none !important; border-radius: 1rem !important; padding: 0.75rem 1.5rem !important; font-weight: 800 !important; font-size: 1.1rem !important; box-shadow: 0 6px 0 #000000 !important; transform: translateY(0) !important; transition: all 0.1s ease !important; text-transform: uppercase !important; letter-spacing: 0.05em !important; } .pf-c-button.pf-m-primary:hover { background-color: #1a1a1a !important; } .pf-c-button.pf-m-primary:active { transform: translateY(6px) !important; box-shadow: none !important; } .pf-c-button.pf-m-secondary, .pf-c-button.pf-m-link { color: #2563eb !important; font-weight: 600 !important; } .pf-c-title { font-weight: 900 !important; color: #111827 !important; text-align: center !important; margin-bottom: 1.5rem !important; } .pf-c-brand { filter: drop-shadow(0 4px 6px rgba(0,0,0,0.1)); } .pf-c-alert { border-radius: 1rem !important; border: 2px solid transparent !important; box-shadow: 0 4px 0 rgba(0,0,0,0.05) !important; } .pf-c-alert.pf-m-danger { background-color: #fef2f2 !important; border-color: #fca5a5 !important; color: #991b1b !important; } .pf-c-login__main-footer-links-item-link { color: #6b7280 !important; font-weight: 500 !important; } .pf-c-background-image { display: none !important; } # ═══════════════════════════════════════════════════════════════════════════════ # PASSWORD POLICY # ═══════════════════════════════════════════════════════════════════════════════ - id: password-complexity-policy model: authentik_policies_password.passwordpolicy identifiers: name: password-complexity attrs: name: password-complexity password_field: password length_min: 8 amount_uppercase: 1 amount_lowercase: 1 amount_digits: 1 error_message: "Password must be at least 8 characters with 1 uppercase, 1 lowercase, and 1 digit." # ═══════════════════════════════════════════════════════════════════════════════ # ENROLLMENT STAGES # ═══════════════════════════════════════════════════════════════════════════════ - id: enrollment-prompt-stage model: authentik_stages_prompt.promptstage identifiers: name: enrollment-prompt attrs: name: enrollment-prompt fields: - !Find [authentik_stages_prompt.prompt, [name, default-source-enrollment-field-username]] - !Find [authentik_stages_prompt.prompt, [name, default-user-settings-field-email]] - !Find [authentik_stages_prompt.prompt, [name, default-password-change-field-password]] - !Find [authentik_stages_prompt.prompt, [name, default-password-change-field-password-repeat]] validation_policies: - !KeyOf password-complexity-policy - id: enrollment-user-write-stage model: authentik_stages_user_write.userwritestage identifiers: name: enrollment-user-write attrs: name: enrollment-user-write user_creation_mode: always_create create_users_as_inactive: false create_users_group: !KeyOf kaboot-users-group user_type: internal - id: enrollment-user-login-stage model: authentik_stages_user_login.userloginstage identifiers: name: enrollment-user-login attrs: name: enrollment-user-login session_duration: hours=24 remember_me_offset: days=30 network_binding: no_binding geoip_binding: no_binding terminate_other_sessions: false # ═══════════════════════════════════════════════════════════════════════════════ # ENROLLMENT FLOW # ═══════════════════════════════════════════════════════════════════════════════ - id: enrollment-flow model: authentik_flows.flow identifiers: slug: enrollment-flow attrs: name: Enrollment Flow title: Sign Up slug: enrollment-flow designation: enrollment authentication: none background: /media/branding/background.svg - id: enrollment-flow-prompt-binding model: authentik_flows.flowstagebinding identifiers: target: !KeyOf enrollment-flow stage: !KeyOf enrollment-prompt-stage attrs: order: 10 evaluate_on_plan: true re_evaluate_policies: false invalid_response_action: retry - id: enrollment-flow-user-write-binding model: authentik_flows.flowstagebinding identifiers: target: !KeyOf enrollment-flow stage: !KeyOf enrollment-user-write-stage attrs: order: 20 evaluate_on_plan: true re_evaluate_policies: false invalid_response_action: retry - id: enrollment-flow-user-login-binding model: authentik_flows.flowstagebinding identifiers: target: !KeyOf enrollment-flow stage: !KeyOf enrollment-user-login-stage attrs: order: 30 evaluate_on_plan: true re_evaluate_policies: false invalid_response_action: retry # ═══════════════════════════════════════════════════════════════════════════════ # LINK ENROLLMENT FLOW TO DEFAULT LOGIN # ═══════════════════════════════════════════════════════════════════════════════ - id: update-identification-stage model: authentik_stages_identification.identificationstage identifiers: name: default-authentication-identification attrs: enrollment_flow: !KeyOf enrollment-flow user_fields: - email - username case_insensitive_matching: true show_matched_user: true show_source_labels: false pretend_user_exists: true