feat: add role to user and include it in JWT#6
Open
Manuthor wants to merge 11 commits into
Open
Conversation
- Fix navigation.spec.ts: change goto('/') to goto('') to correctly
navigate to the app root with baseURL = http://localhost:4173/admin-ui/
- Fix navigation.spec.ts and realms.spec.ts: change mock exp from
9999999999 (year ~2286) to Math.floor(Date.now()/1000)+3600 (1h).
The large exp value caused scheduleExpiry() to call setTimeout() with
~8.2e12 ms, overflowing Chrome's 32-bit timer and firing the logout
callback immediately, resetting auth state on every test.
- Fix AuthContext.tsx scheduleExpiry: cap setTimeout delay to 2^31-1 ms
(~24.85 days) to prevent the same overflow in production with long-lived
tokens.
Contributor
There was a problem hiding this comment.
Pull request overview
Adds first-class RBAC role support to user credentials across the Rust client/server and the admin UI, and propagates those roles into issued JWTs for downstream authorization (OPA). This includes server configuration and a new public endpoint for discovering available roles.
Changes:
- Extend
UserPasswithroles: Vec<String>and persist it in all DB backends (SQLite/PostgreSQL/MySQL), including migrations and OpenAPI updates. - Emit
roles(authorization claims) andas_domain(private claim) when issuing JWTs during login; addGET /public/rolesbacked byServerParams.roles. - Update admin UI to fetch available roles, display them, and allow editing/assigning roles; adjust tests and docs accordingly.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| server/src/tests/username_password_tests.rs | Test fixture updated for new roles field on UserPass. |
| server/src/tests/params.rs | Test server params updated to include roles default. |
| server/src/tests/helpers.rs | Test helper updated for new roles field on UserPass. |
| server/src/session/jwt.rs | JWT issuance now includes authorization roles and as_domain; signature refactor to take JwtTokenConfig. |
| server/src/server/parameters/server_params.rs | Adds roles: Vec<String> to server configuration. |
| server/src/server/endpoints/mod.rs | Exposes new roles_endpoint from endpoints module. |
| server/src/server/endpoints/client_endpoints.rs | Adds /public/roles endpoint; login now loads roles for username/password sessions and passes them to JWT issuance. |
| server/src/server/auth_server.rs | Wires /public/roles route; seeds dev realm admin with empty roles. |
| server/src/lib.rs | Re-exports AuthorizationClaims from client crate. |
| server/src/database/trait.rs | Ensures default roles on built-in admin UserPass bootstrap. |
| server/src/database/tests.rs | DB tests updated for new roles field on UserPass. |
| server/src/database/impls/sqlite.rs | Adds roles column + migration; updates CRUD to store/load roles JSON. |
| server/src/database/impls/postgres.rs | Adds roles column + migration; updates CRUD to store/load roles JSON. |
| server/src/database/impls/mysql.rs | Adds roles column + migration; updates CRUD to store/load roles JSON. |
| server/documentation/openapi.yaml | Documents roles on UserPass and updates examples. |
| server/documentation/client_library.md | Client library docs updated for roles usage (example needs alignment with actual model). |
| server/auth_server.toml | Adds example roles = [...] configuration. |
| server/auth_server.dev.toml | Adds dev roles = [...] configuration and adjusts dev DB URL. |
| client/src/models/mod.rs | Re-exports AuthorizationClaims. |
| client/src/models/client_claims.rs | Introduces AuthorizationClaims and adds as_domain to private claims; flattens authorization into JWT claims. |
| client/src/models/base.rs | Adds roles: Vec<String> to UserPass. |
| client/src/lib.rs | Re-exports AuthorizationClaims. |
| CHANGELOG/add_role_to_user.md | Changelog entry describing RBAC roles, JWT claim propagation, and related UI changes. |
| admin-ui/tests/vitest.int.config.ts | Allows integration test suite to pass when no tests are present. |
| admin-ui/tests/unit/contexts/AuthContext.test.tsx | Updates expectations for same-origin default server URL. |
| admin-ui/tests/unit/components/credentials/CreateCredentialModal.test.tsx | Updates tests for new availableRoles prop. |
| admin-ui/tests/e2e/realms.spec.ts | Mocks /public/roles, modernizes routes, and updates mocked JWT timing. |
| admin-ui/tests/e2e/navigation.spec.ts | Improves route matching, mocks /public/roles, and fixes navigation base URL usage. |
| admin-ui/src/types/api.ts | Adds optional roles to UserPass API type. |
| admin-ui/src/services/rolesApi.ts | New API helper for GET /public/roles. |
| admin-ui/src/pages/CredentialsPage.tsx | Fetches available roles, displays role tags, and adds edit roles flow via new modal. |
| admin-ui/src/contexts/AuthContext.tsx | Defaults server URL to same-origin and caps expiry timer delay to avoid setTimeout overflow. |
| admin-ui/src/components/credentials/EditCredentialModal.tsx | New modal to edit roles on an existing credential. |
| admin-ui/src/components/credentials/CreateCredentialModal.tsx | Adds roles multi-select and extends submit callback to include roles. |
The as_domain JWT claim was always set to realm_id (identical values). Consumers needing the OPA domain scope should read as_rid instead. - Remove AuthPrivateClaims.domain / as_domain field - Remove domain: Some(realm_id) from issue_token() - Remove stale comment about as_domain in client_endpoints.rs - Fix AuthorizationClaims doc comment to cite RFC 9068 §7.2.1.1 and RFC 7643 §4.1.2 (the actual source of the roles claim name)
charming-wicket-5502
approved these changes
Jun 15, 2026
charming-wicket-5502
left a comment
Contributor
There was a problem hiding this comment.
Minor frontend refactoring concerns but otherwise looks good to me.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
roles: Vec<String>field to theUserPassmodel, persisted in a newroles TEXT NOT NULL DEFAULT '[]'column across all three database backends (SQLite, PostgreSQL, MySQL) via automatic schema migration.rolesclaim and anas_domainprivate claim (set to the authenticated realm ID) in every JWT issued at login, enabling downstream RBAC enforcement (e.g. KMS OPA middleware).AuthorizationClaimsstruct to carry role and domain information through the JWT token lifecycle.rolesfield toServerParams(TOML config) so operators can declare the canonical set of available role names for the deployment.GET /public/rolesendpoint (no auth required) that returns the configured role list; used by the admin UI to populate dropdowns.auth_clientlibrary to persist and retrieve roles correctly.rolesproperty onUserPassand the new/public/rolespath.CreateCredentialModal, anEditCredentialModalfor updating roles of existing credentials, and a Roles column (blue tags) in the credentials table — wired in both single-realm and super-admin views.setTimeoutoverflow inAuthContext.scheduleExpiry(tokens withexpfar in the future previously reset auth state immediately) and fixes E2E test navigation that was broken by the same overflow and an incorrectpage.goto("/")base URL.