Skip to content

Technical reference: Access control

This chapter documents the technical details of how the platform enforces access control. This information is useful for system administrators configuring tenants and roles, and for developers extending the platform.

Access rule format

Access rules use a hierarchical pattern: aihub.[user|admin].<service>.<resource>.<identifier>

Examples:

aihub.user.agent.>                      # All agents (user access)
aihub.admin.agent.research.*            # All research agents (admin access)
aihub.user.knowledge.hr-docs.policies   # Specific knowledge namespace
aihub.admin.service.tenant              # Tenant management service

Wildcards

Single-level (*) matches exactly one segment:

  • agent.research.* matches agent.research.instance-1 but not agent.research.team.instance-1

Multi-level (>) matches one or more segments at the end:

  • agent.> matches agent.research.instance-1, agent.analysis.team.special, and any other agent path
  • Must be the last token in the rule

Admin vs user rules

Rules starting with aihub.admin.* grant administrative access. Users with admin access automatically have equivalent user access.

A user with aihub.admin.agent.> can access resources requiring either aihub.admin.agent.* or aihub.user.agent.*.

The chat interface is a separate axis

The rules above govern the platform API. The chat interface has its own administrator role, granted by the AIHubSysAdmin Keycloak realm role rather than by any tenant role or access rule. Holding aihub.admin.* in a tenant does not make you a chat administrator, and being a chat administrator does not grant visibility into other users' uploads or conversations - those are scoped to their owner by default. See ADR: Scope OpenWebUI Admins to Their Own Files and Chats.

Permission resolution

When a request arrives, the platform:

  1. Extracts the user's identity from the authentication token
  2. Reads the X-Tenant-Id header to determine the tenant context
  3. Queries the user's roles within that specific tenant
  4. Collects all access rules from those roles
  5. Retrieves the tenant's access rules
  6. Checks if both the tenant and the user permit the requested action

Two-layer checking

Access requires passing both layers:

Layer 1: Tenant boundary - Does the tenant allow this resource at all?

If the tenant's access rules don't include the requested resource, access is denied immediately without checking user roles.

Layer 2: User permissions - Does the user's role permit this action?

After confirming the tenant allows the resource, the system checks if the user's roles grant the required permission.

Both must pass for access to be granted.

Example

Tenant has: aihub.user.agent.research.*

User has: aihub.user.agent.> (from their role)

User requests: aihub.user.agent.research.instance-1

  • Tenant check: ✓ (tenant allows research agents)
  • User check: ✓ (user role allows all agents)
  • Result: Access granted

User requests: aihub.user.agent.finance.instance-1

  • Tenant check: ✗ (tenant only allows research agents)
  • Result: Access denied (user check not evaluated)

Service-level permissions

Each service requires a base permission: aihub.user.service.<service-name>

Before checking resource-specific permissions, the system verifies the user has access to the service itself.

To access an agent, you need:

  • Service access: aihub.user.service.agent
  • Resource access: aihub.user.agent.<agent-class>.<agent-id>

If the tenant doesn't grant service access, no resources in that service are accessible regardless of other rules.

Path parameter substitution

Permission templates use placeholders that resolve from the request:

Template: aihub.user.agent.{agent_class}.{agent_id}

Request: GET /api/v1/agents/research/instance-alpha

Resolved permission: aihub.user.agent.research.instance-alpha

The system checks this concrete permission against the user and tenant access rules.

Access levels

The system returns three levels:

ACCESS_DENIED: No permission. Returns HTTP 403.

ACCESS_USER: User-level access to view and interact with the resource.

ACCESS_ADMIN: Admin-level access to modify, configure, or delete the resource.

Controllers can differentiate between user and admin access for audit purposes, though many operations only check whether access is granted (not denied).

Configuration through environment

Configure default behavior through environment variables:

bash
# Startup tenant (seeded on first boot; an ordinary tenant thereafter).
# Leave ACCESS_RULES empty to derive the ceiling from the models this instance serves,
# minus AIHUB_TENANT_DEFAULT_ACCESS_EXCLUDED_MODELS. Set "aihub.admin.>" for unrestricted
# access, which also skips the model-gateway lookup at first boot.
AIHUB_STARTUP_TENANT_NAME="Swiss AI Hub"
AIHUB_STARTUP_TENANT_ACCESS_RULES=""
AIHUB_TENANT_DEFAULT_ACCESS_EXCLUDED_MODELS="text-generation/Apertus-70B-Instruct-2509"

# Agent blueprints a new tenant's ceiling grants. Every other blueprint stays hidden from that
# tenant until a sysadmin grants it.
AIHUB_TENANT_DEFAULT_ACCESS_AGENT_CLASSES="LLMWrappingAgent,FewShotAgent,RAGAgent"

# Automatic user signup
AIHUB_USER_SIGNUP_DEFAULT_TENANT="default"
AIHUB_USER_SIGNUP_DEFAULT_ROLES="AIHubUser,AIHubAgentUser"
FIRST_AIHUB_USER_SIGNUP_DEFAULT_ROLES="AIHubAdmin"

What a new tenant starts with

A tenant created with no explicit rules does not get a wildcard. Its ceiling is derived, and the two curated families behave differently:

Models are read from the live gateway roster. A capability with nothing excluded collapses to a wildcard (aihub.user.model.embedding.>), so models added to it later reach new tenants unattended. A capability holding an exclusion enumerates its survivors instead.

Agents are named from a configured list — the standard blueprint set. Every other blueprint stays hidden from that tenant: it is absent from Admin → Agents rather than shown and refused, because the blueprint list is filtered by the same per-class rules. Two rules are granted per class, aihub.admin.agent.<Class> and aihub.admin.agent.<Class>.>, since creating an instance is guarded on the bare root (see Validation rules).

Agents use an allow list where models use exclusions because the two rosters differ in kind. Model names vary between CPU and GPU deployments, so a fixed list would leave a GPU tenant with no chat model. Agent class names are fixed at build time, and the discovered-class roster is still empty when the startup tenant is seeded at first boot — an exclusion would have nothing to subtract from and would grant that tenant no agents at all.

Both settings are seeds, read once while the ceiling is computed. Afterwards the tenant's stored rules are the only authority, so granting a further blueprint or model is an ordinary access-rule edit in the tenant editor — no redeploy, and the setting has no say in it. Existing tenants are untouched and keep whatever ceiling they already have.

Sysadmin access

Users with the Keycloak realm role AIHubSysAdmin receive implicit admin access to every tenant and every resource. The two-stage tenant/user check described above is bypassed — a sysadmin is treated as an admin everywhere.

Sysadmins can also act without a tenant context, which enables cross-tenant endpoints such as the tenant administration UI. Every sysadmin is a real Keycloak user with a real user id, so their actions remain traceable in Langfuse and they appear in tenant member listings like any other user.

Assign the AIHubSysAdmin realm role in Keycloak directly or via identity provider mappers. The platform also seeds a dedicated Superuser account from SUPERUSER_EMAIL / SUPERUSER_PASSWORD (the username is seeded equal to SUPERUSER_EMAIL, so this account logs in with its email) and materializes SUPERUSER_TOKEN as a bearer token for that user so internal services can call the API without a browser session.

Use sparingly — sysadmin access exists for platform administration, not day-to-day operations.

Validation rules

Access Rule Format Requirements

When creating access rules:

Required format:

  • Must start with aihub.user. or aihub.admin.
  • Only lowercase letters, numbers, dots, hyphens, underscores, *, >
  • Multi-level wildcard > only at the end

> does not match its own root:

aihub.admin.knowledge.> matches aihub.admin.knowledge.hr-docs but not the bare aihub.admin.knowledge> requires at least one further segment. Some permissions are guarded on a bare root precisely because the resource does not exist yet: creating a knowledge database is checked against aihub.admin.knowledge, since a database that has not been created cannot be named by a rule. A rule set that should cover both has to carry both forms, which is why AIHubKnowledgeAdmin is seeded with aihub.admin.knowledge and aihub.admin.knowledge.>. This applies to tenant ceilings as much as to roles: a ceiling holding only the .> form caps the root permission away from every role in the tenant.

Prohibited:

  • Uppercase letters
  • Special characters other than ., -, _, *, >
  • > in the middle of a rule

The system validates rules when creating or editing tenants and roles. Invalid rules trigger an error with the specific problem.

Common patterns

Broad platform access

aihub.admin.>

Full admin access to everything. Use for sysadmin tenants.

Service administrators

aihub.admin.service.user
aihub.admin.service.role
aihub.admin.service.tenant

Can manage users, roles, and tenants but not other services.

Department access

aihub.user.agent.department-finance.*
aihub.user.knowledge.finance-docs.>
aihub.user.process.finance-workflows.*

Access to finance-specific resources only.

Read-only access

aihub.user.agent.>
aihub.user.knowledge.>

Can view and use agents and knowledge but cannot create or modify.

Power user

aihub.user.>
aihub.admin.agent.<department>.*
aihub.admin.knowledge.<department>-docs.>

User access everywhere, admin access only to department resources.

Debugging access issues

Troubleshooting Checklist

When troubleshooting, check these in order:

  1. Tenant selection: Verify the user selected the intended tenant
  2. Tenant boundary: Confirm the tenant's access rules include the resource
  3. User membership: Verify the user belongs to the tenant
  4. Role assignment: Check the user has roles in that tenant
  5. Role rules: Review what those roles permit
  6. Service access: Verify service-level permission exists

The platform returns detailed error messages indicating which permission failed. Use this to identify the missing rule.

Performance notes

Access checking is optimized:

  • Rules are compiled once per request
  • Multiple permission checks for the same user reuse the compiled rules
  • Complex wildcard patterns have minimal performance impact
  • Role changes take effect immediately without cache delays

Switching tenants triggers a full cache invalidation in the frontend, causing data to be refetched.

Built with ❤️ in Switzerland 🇨🇭