# Kaboot Authentik Blueprint # This blueprint automatically configures all Authentik resources needed for Kaboot. # Place in authentik/blueprints/ and it will be auto-imported on container startup. # # Prerequisites: # - Set AUTHENTIK_BOOTSTRAP_PASSWORD and AUTHENTIK_BOOTSTRAP_TOKEN in .env # - Mount this directory to /blueprints/custom in docker-compose.yml # # # What this creates: # - Kaboot OAuth2/OIDC Provider (public client) # - Kaboot Application # - kaboot-users Group # - Enrollment flow with prompt, user write, and login stages # - Password complexity policy # - Test user (kaboottest) - for manual browser testing # - Service account (kaboot-test-service) - for API testing # # yaml-language-server: $schema=https://goauthentik.io/blueprints/schema.json --- version: 1 metadata: name: Kaboot Application Setup labels: blueprints.goauthentik.io/description: "Complete Kaboot OAuth2/OIDC setup with enrollment flow" entries: # ═══════════════════════════════════════════════════════════════════════════════ # BRANDING # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-brand model: authentik_brands.brand identifiers: domain: localhost attrs: domain: localhost default: true 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: !Find [authentik_flows.flow, [slug, default-invalidation-flow]] flow_user_settings: !Find [authentik_flows.flow, [slug, default-user-settings-flow]] attributes: settings: theme: base: light css: | /* Kaboot Theme for Authentik */ :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; } /* Background color fallback (image set via Flow settings) */ body { background-color: #2563eb !important; } /* Login Card */ .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; } /* Inputs */ .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; } /* Primary Button - Kaboot Signature 3D Style */ .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; } /* Secondary/Link Buttons */ .pf-c-button.pf-m-secondary, .pf-c-button.pf-m-link { color: #2563eb !important; font-weight: 600 !important; } /* Titles */ .pf-c-title { font-weight: 900 !important; color: #111827 !important; text-align: center !important; margin-bottom: 1.5rem !important; } /* Logo styling if present in header */ .pf-c-brand { filter: drop-shadow(0 4px 6px rgba(0,0,0,0.1)); } /* Alert/Notification boxes */ .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; } /* Footer links */ .pf-c-login__main-footer-links-item-link { color: #6b7280 !important; font-weight: 500 !important; } /* Hide the default background image if any */ .pf-c-background-image { display: none !important; } # ═══════════════════════════════════════════════════════════════════════════════ # 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-invalidation-flow-background model: authentik_flows.flow identifiers: slug: default-invalidation-flow attrs: 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 # ═══════════════════════════════════════════════════════════════════════════════ # 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 # ═══════════════════════════════════════════════════════════════════════════════ # 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: !Find [authentik_flows.flow, [slug, default-provider-invalidation-flow]] client_type: public client_id: kaboot-spa redirect_uris: - url: http://localhost:5173/callback matching_mode: strict - url: http://localhost:5173/silent-renew.html matching_mode: strict - url: http://localhost:5173 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]] # ═══════════════════════════════════════════════════════════════════════════════ # 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: http://localhost:5173 - 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 # ═══════════════════════════════════════════════════════════════════════════════ # 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 - 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 # ═══════════════════════════════════════════════════════════════════════════════ # TEST USER (for manual browser testing) # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-test-user model: authentik_core.user identifiers: username: kaboottest attrs: username: kaboottest name: Kaboot Test email: kaboottest@test.com path: users is_active: true groups: - !KeyOf kaboot-users-group - !KeyOf kaboot-ai-access-group # ═══════════════════════════════════════════════════════════════════════════════ # SERVICE ACCOUNT (for API/automated testing) # ═══════════════════════════════════════════════════════════════════════════════ - id: kaboot-test-service-account model: authentik_core.user identifiers: username: kaboot-test-service attrs: username: kaboot-test-service name: Kaboot Test Service path: users type: service_account is_active: true groups: - !KeyOf kaboot-users-group - !KeyOf kaboot-ai-access-group