diff --git a/authentik/blueprints/kaboot-setup-production.yaml.example b/authentik/blueprints/kaboot-setup-production.yaml.example index 561bf5b..1c9ef5e 100644 --- a/authentik/blueprints/kaboot-setup-production.yaml.example +++ b/authentik/blueprints/kaboot-setup-production.yaml.example @@ -16,6 +16,15 @@ metadata: name: Kaboot Application Setup (Production) labels: blueprints.goauthentik.io/description: "Complete Kaboot OAuth2/OIDC setup for production" + blueprints.goauthentik.io/instantiate: "true" + +depends_on: + - default/flow-default-authentication-flow.yaml + - default/flow-default-invalidation-flow.yaml + - default/flow-default-provider-authorization-implicit-consent.yaml + - default/flow-default-provider-invalidation.yaml + - default/flow-default-user-settings-flow.yaml + - system/providers-oauth2.yaml context: kaboot_domain: kaboot.example.com @@ -127,7 +136,7 @@ entries: scope_name: groups description: "Include user groups in the token" expression: | - return [group.name for group in user.ak_groups.all()] + return {"groups": [group.name for group in request.user.ak_groups.all()]} # ═══════════════════════════════════════════════════════════════════════════════ # OAUTH2/OIDC PROVIDER diff --git a/authentik/blueprints/kaboot-setup.yaml b/authentik/blueprints/kaboot-setup.yaml index 91e6ef8..106a170 100644 --- a/authentik/blueprints/kaboot-setup.yaml +++ b/authentik/blueprints/kaboot-setup.yaml @@ -23,8 +23,71 @@ metadata: name: Kaboot Application Setup labels: blueprints.goauthentik.io/description: "Complete Kaboot OAuth2/OIDC setup with enrollment flow" + blueprints.goauthentik.io/instantiate: "true" + +# This blueprint depends on default authentik resources being created first. +# The depends_on ensures proper ordering during initial bootstrap. +depends_on: + - default/flow-default-authentication-flow.yaml + - default/flow-default-invalidation-flow.yaml + - default/flow-default-provider-authorization-implicit-consent.yaml + - default/flow-default-provider-invalidation.yaml + - default/flow-default-user-settings-flow.yaml + - system/providers-oauth2.yaml 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: http://localhost:5173 + + - 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 + # ═══════════════════════════════════════════════════════════════════════════════ # GROUPS # ═══════════════════════════════════════════════════════════════════════════════ @@ -56,7 +119,7 @@ entries: scope_name: groups description: "Include user groups in the token" expression: | - return [group.name for group in user.ak_groups.all()] + return {"groups": [group.name for group in request.user.ak_groups.all()]} # ═══════════════════════════════════════════════════════════════════════════════ # OAUTH2/OIDC PROVIDER @@ -69,7 +132,7 @@ entries: 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]] + invalidation_flow: !KeyOf kaboot-invalidation-flow signing_key: !Find [authentik_crypto.certificatekeypair, [name, authentik Internal JWT Certificate]] client_type: public client_id: kaboot-spa @@ -134,7 +197,7 @@ entries: 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_invalidation: !KeyOf kaboot-invalidation-flow flow_user_settings: !Find [authentik_flows.flow, [slug, default-user-settings-flow]] default_application: !KeyOf kaboot-application attributes: @@ -266,13 +329,6 @@ entries: 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: diff --git a/server/src/db/connection.ts b/server/src/db/connection.ts index 0387c18..2e9c02e 100644 --- a/server/src/db/connection.ts +++ b/server/src/db/connection.ts @@ -112,7 +112,7 @@ const runMigrations = () => { const quizTableInfo = db.prepare("PRAGMA table_info(quizzes)").all() as { name: string }[]; const hasShareToken = quizTableInfo.some(col => col.name === "share_token"); if (!hasShareToken) { - db.exec("ALTER TABLE quizzes ADD COLUMN share_token TEXT UNIQUE"); + db.exec("ALTER TABLE quizzes ADD COLUMN share_token TEXT"); console.log("Migration: Added share_token to quizzes"); } @@ -124,8 +124,8 @@ const runMigrations = () => { const shareTokenIndex = db.prepare("SELECT name FROM sqlite_master WHERE type='index' AND name='idx_quizzes_share_token'").get(); if (!shareTokenIndex) { - db.exec("CREATE INDEX idx_quizzes_share_token ON quizzes(share_token)"); - console.log("Migration: Created index on quizzes.share_token"); + db.exec("CREATE UNIQUE INDEX idx_quizzes_share_token ON quizzes(share_token)"); + console.log("Migration: Created unique index on quizzes.share_token"); } }; diff --git a/server/src/db/schema.sql b/server/src/db/schema.sql index 6e8c11f..09f900d 100644 --- a/server/src/db/schema.sql +++ b/server/src/db/schema.sql @@ -60,7 +60,5 @@ CREATE TABLE IF NOT EXISTS game_sessions ( ); CREATE INDEX IF NOT EXISTS idx_quizzes_user ON quizzes(user_id); -CREATE INDEX IF NOT EXISTS idx_quizzes_share_token ON quizzes(share_token); CREATE INDEX IF NOT EXISTS idx_questions_quiz ON questions(quiz_id); CREATE INDEX IF NOT EXISTS idx_options_question ON answer_options(question_id); -CREATE INDEX IF NOT EXISTS idx_game_sessions_updated ON game_sessions(updated_at);