Skip to content

FlowAuth: surface assigned roles on token list (#7273)#7276

Merged
jakejellinek merged 2 commits intomasterfrom
flowauth/token-roles-visible
Apr 29, 2026
Merged

FlowAuth: surface assigned roles on token list (#7273)#7276
jakejellinek merged 2 commits intomasterfrom
flowauth/token-roles-visible

Conversation

@jakejellinek
Copy link
Copy Markdown
Contributor

@jakejellinek jakejellinek commented Apr 28, 2026

Closes #7273.

Summary

When a user views their tokens in FlowAuth, the response and UI show id, name, token, expires, server_name, username — but not the roles that were granted at mint time. The role information was only present inside the gzipped user_claims payload of the encrypted JWT, so there was no practical way to look at an existing token and see what permissions it carried.

Changes

  • models.py — new tokens_with_roles association table (mirroring the existing users_with_roles pattern) plus a roles relationship on TokenHistory.
  • token_management.pyadd_token populates the new association at mint time; list_my_tokens includes a roles field ([{id, name}, …]) in its response.
  • Alembic migrationa8c5e1d3f7b2_add_tokens_with_roles_assoc.py creates the new table. Down-revision is the current head (976c731ff30f).
  • FrontendTokenList.jsx passes roles through to Token.jsx, which renders a compact Roles: … caption under the nickname when present. Layout grid is otherwise unchanged.
  • Testtest_token_list_includes_assigned_roles mints a token and asserts the list endpoint returns the expected role names.
  • CHANGELOG — entry under [Unreleased] / Added.

Backwards compatibility

Purely additive on the wire. The JWT format is unchanged, so FlowAPI is unaffected. Existing token_history rows have no associated roles, so the UI simply omits the caption for them — those tokens get the new info on next reissue.

Test plan

  • Backend: pytest flowauth/backend/tests/test_token_generation.py::test_token_list_includes_assigned_roles passes.
  • Backend: full flowauth/backend test suite passes (no regressions).
  • Frontend: log in as a non-admin user, mint a token, confirm the role list appears under the token name.
  • Migration: flask db upgrade then flask db downgrade round-trips cleanly on a populated database.

Related work

This is the first of three planned PRs against FlowAuth. The other two are tracked under #7274 (drop the silent absolute-expiry cap so renewals don't require admin-bumps) and #7275 (add a real token renewal endpoint, which depends on this PR's tokens_with_roles table).

Summary by CodeRabbit

  • New Features

    • Token mint-time roles are now persisted and included in the token list endpoint, so each token returns its assigned role metadata.
    • Frontend displays assigned roles beneath each token name for clearer visibility.
  • Tests

    • Added test coverage verifying the token list includes assigned roles and role IDs.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely summarizes the main change: making token roles visible in the token list interface and API response.
Linked Issues check ✅ Passed All primary coding objectives from issue #7273 are met: the tokens_with_roles association table is created [#7273], roles are populated at mint time in add_token [#7273], roles are included in list_my_tokens response [#7273], frontend displays roles [#7273], and tests validate the implementation [#7273].
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #7273 objectives: database schema, ORM models, token management logic, API response formatting, frontend rendering, tests, and documentation are all focused on surfacing assigned roles.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch flowauth/token-roles-visible

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@cypress
Copy link
Copy Markdown

cypress Bot commented Apr 28, 2026

FlowAuth    Run #25965

Run Properties:  status check passed Passed #25965  •  git commit 746153b3cd: FlowAuth: add docstrings to tokens_with_roles migration upgrade/downgrade
Project FlowAuth
Branch Review flowauth/token-roles-visible
Run status status check passed Passed #25965
Run duration 00m 52s
Commit git commit 746153b3cd: FlowAuth: add docstrings to tokens_with_roles migration upgrade/downgrade
Committer Joachim Jellinek
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 4
View all changes introduced in this branch ↗︎

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
flowauth/backend/flowauth/token_management.py (1)

153-160: ⚠️ Potential issue | 🔴 Critical

Scope role selection to the current server/user before persisting.

roles=roles now stores the resolved Role rows, but current resolution is name-only. If two servers share a role name, the wrong role record can be selected and persisted/encoded.

🔧 Suggested fix
-    roles = []
+    user_roles_by_name = {ur.name: ur for ur in user_roles}
+    roles = []
     for requested_role in json["roles"]:
-        if requested_role["name"] not in [ur.name for ur in user_roles]:
+        role_name = requested_role["name"]
+        if role_name not in user_roles_by_name:
             raise Unauthorized(
-                f"Role '{requested_role['name']}' is not permitted for the current user"
+                f"Role '{role_name}' is not permitted for the current user"
             )
-        roles.append(Role.query.filter(Role.name == requested_role["name"]).first())
+        roles.append(user_roles_by_name[role_name])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@flowauth/backend/flowauth/token_management.py` around lines 153 - 160, The
TokenHistory entry is persisting resolved Role rows via roles=roles but the
current resolution uses name-only and can pick the wrong Role if multiple
servers share a role name; update the role resolution that builds the roles
variable (used when creating TokenHistory) to filter by the current server
(and/or current_user if applicable) — e.g. query Role where Role.name IN
provided_names AND Role.server_id == server.id (or Role.user_id ==
current_user.id if roles are user-scoped), then use those scoped Role objects
when constructing TokenHistory and when encoding the token so the
persisted/encoded roles reference the correct server-specific role records.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@flowauth/backend/tests/test_token_generation.py`:
- Line 99: The tuple unpacking from test_user_with_roles assigns uid, uname,
upass but uid is never used; update the unpack to avoid the unused variable
(e.g., unpack only uname and upass or rename uid to _uid) in the test function
where test_user_with_roles is consumed so the Ruff warning is resolved while
preserving uname and upass usage.

---

Outside diff comments:
In `@flowauth/backend/flowauth/token_management.py`:
- Around line 153-160: The TokenHistory entry is persisting resolved Role rows
via roles=roles but the current resolution uses name-only and can pick the wrong
Role if multiple servers share a role name; update the role resolution that
builds the roles variable (used when creating TokenHistory) to filter by the
current server (and/or current_user if applicable) — e.g. query Role where
Role.name IN provided_names AND Role.server_id == server.id (or Role.user_id ==
current_user.id if roles are user-scoped), then use those scoped Role objects
when constructing TokenHistory and when encoding the token so the
persisted/encoded roles reference the correct server-specific role records.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d596d44d-0a0d-49e9-ae96-a6cd0f432c58

📥 Commits

Reviewing files that changed from the base of the PR and between 5cf4399 and 9f78194.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • flowauth/backend/flowauth/migrations/versions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py
  • flowauth/backend/flowauth/models.py
  • flowauth/backend/flowauth/token_management.py
  • flowauth/backend/tests/test_token_generation.py
  • flowauth/frontend/src/Token.jsx
  • flowauth/frontend/src/TokenList.jsx

):
"""The token list endpoint exposes the roles that were assigned at mint time."""
with app.app_context():
uid, uname, upass = test_user_with_roles
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove unused unpacked variable.

Line 99 assigns uid but never uses it, which triggers the current Ruff warning set.

✏️ Suggested tidy-up
-        uid, uname, upass = test_user_with_roles
+        _uid, uname, upass = test_user_with_roles
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uid, uname, upass = test_user_with_roles
_uid, uname, upass = test_user_with_roles
🧰 Tools
🪛 Ruff (0.15.12)

[warning] 99-99: Unpacked variable uid is never used

Prefix it with an underscore or any other dummy variable pattern

(RUF059)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@flowauth/backend/tests/test_token_generation.py` at line 99, The tuple
unpacking from test_user_with_roles assigns uid, uname, upass but uid is never
used; update the unpack to avoid the unused variable (e.g., unpack only uname
and upass or rename uid to _uid) in the test function where test_user_with_roles
is consumed so the Ruff warning is resolved while preserving uname and upass
usage.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
flowauth/backend/flowauth/migrations/versions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py (1)

40-53: Add a standalone index for role_id on the association table.

The composite PK helps token_id lookups, but not role_id-only paths. Adding role_id index avoids avoidable scans on larger datasets.

♻️ Proposed migration diff
 def upgrade():
@@
     op.create_table(
         "tokens_with_roles",
         sa.Column("token_id", sa.Integer(), nullable=False),
         sa.Column("role_id", sa.Integer(), nullable=False),
@@
         sa.PrimaryKeyConstraint("token_id", "role_id"),
     )
+    op.create_index(
+        "ix_tokens_with_roles_role_id",
+        "tokens_with_roles",
+        ["role_id"],
+        unique=False,
+    )
@@
 def downgrade():
@@
+    op.drop_index("ix_tokens_with_roles_role_id", table_name="tokens_with_roles")
     op.drop_table("tokens_with_roles")

Also applies to: 68-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@flowauth/backend/flowauth/migrations/versions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py`
around lines 40 - 53, Add a standalone index on role_id for the association
table to speed up role-only lookups: after the
op.create_table("tokens_with_roles", ...) call that defines sa.Column("role_id",
...), create an index (e.g. via op.create_index) on the "tokens_with_roles"
table for the "role_id" column (name it something like
"ix_tokens_with_roles_role_id"); this uses the existing tokens_with_roles table
and role_id column defined in the migration and avoids changing the primary key
definition.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@flowauth/backend/flowauth/migrations/versions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py`:
- Around line 40-53: Add a standalone index on role_id for the association table
to speed up role-only lookups: after the op.create_table("tokens_with_roles",
...) call that defines sa.Column("role_id", ...), create an index (e.g. via
op.create_index) on the "tokens_with_roles" table for the "role_id" column (name
it something like "ix_tokens_with_roles_role_id"); this uses the existing
tokens_with_roles table and role_id column defined in the migration and avoids
changing the primary key definition.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2627e2a0-5383-4351-a65f-924a29c403fe

📥 Commits

Reviewing files that changed from the base of the PR and between 9f78194 and 5c75566.

📒 Files selected for processing (1)
  • flowauth/backend/flowauth/migrations/versions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py

Roles granted to a token at mint time were only ever stored inside the
gzipped JWT user_claims payload, so users had no practical way to
inspect what permissions an existing token carried. Add a
tokens_with_roles association table populated in add_token, expose the
roles on the GET /tokens/tokens/<server_id> response, and render them
under the nickname in the token list.

Backwards compatible: pre-existing token_history rows have no
associated roles and the UI simply omits the line.
…rade

Bumps docstring coverage on the PR above CodeRabbit's 80% threshold.
Existing migrations (73ea696e203d, 976c731ff30f) lack docstrings, but
they're not in this PR's diff so they don't count against the score.
@jakejellinek jakejellinek force-pushed the flowauth/token-roles-visible branch from 5c75566 to 746153b Compare April 29, 2026 09:59
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
flowauth/backend/tests/test_token_generation.py (1)

99-99: ⚠️ Potential issue | 🟡 Minor

Unused unpacked variable at Line 99.

uid is assigned but never used, matching the existing Ruff RUF059 warning previously raised on this PR.

Suggested tidy-up
-        uid, uname, upass = test_user_with_roles
+        _uid, uname, upass = test_user_with_roles
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@flowauth/backend/tests/test_token_generation.py` at line 99, The test unpacks
test_user_with_roles into uid, uname, upass but never uses uid, causing an
unused-variable warning; to fix it, change the unpack to ignore the first value
(e.g. use _ or _uid) so only uname and upass are treated as used, updating the
unpack expression in test_token_generation.py where test_user_with_roles is
destructured.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@flowauth/backend/tests/test_token_generation.py`:
- Around line 107-110: The test asserts the wrong status code for token minting:
update the expectation in test_token_generation.py so the response from the POST
to "/tokens/tokens/1" (stored in mint_response) is asserted to be 201 (the code
returned by flowauth.backend.flowauth.token_management's token creation path)
instead of 200; locate the mint_response assertion and change it to assert
mint_response.status_code == 201 to match token_management.py behavior.

---

Duplicate comments:
In `@flowauth/backend/tests/test_token_generation.py`:
- Line 99: The test unpacks test_user_with_roles into uid, uname, upass but
never uses uid, causing an unused-variable warning; to fix it, change the unpack
to ignore the first value (e.g. use _ or _uid) so only uname and upass are
treated as used, updating the unpack expression in test_token_generation.py
where test_user_with_roles is destructured.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 29638041-6619-4270-88d3-b9266732cc79

📥 Commits

Reviewing files that changed from the base of the PR and between 5c75566 and 746153b.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • flowauth/backend/flowauth/migrations/versions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py
  • flowauth/backend/flowauth/models.py
  • flowauth/backend/flowauth/token_management.py
  • flowauth/backend/tests/test_token_generation.py
  • flowauth/frontend/src/Token.jsx
  • flowauth/frontend/src/TokenList.jsx
✅ Files skipped from review due to trivial changes (2)
  • flowauth/frontend/src/TokenList.jsx
  • CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • flowauth/backend/flowauth/token_management.py
  • flowauth/frontend/src/Token.jsx
  • flowauth/backend/flowauth/models.py

Comment on lines +107 to +110
mint_response = client.post(
"/tokens/tokens/1", headers={"X-CSRF-Token": csrf_cookie}, json=token_req
)
assert mint_response.status_code == 200
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Status-code assertion appears incorrect for token minting.

Line 110 expects 200, but flowauth/backend/flowauth/token_management.py:160 returns 201 for successful token creation. This can make the new test fail while the API is behaving correctly.

Proposed fix
-        assert mint_response.status_code == 200
+        assert mint_response.status_code == 201
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@flowauth/backend/tests/test_token_generation.py` around lines 107 - 110, The
test asserts the wrong status code for token minting: update the expectation in
test_token_generation.py so the response from the POST to "/tokens/tokens/1"
(stored in mint_response) is asserted to be 201 (the code returned by
flowauth.backend.flowauth.token_management's token creation path) instead of
200; locate the mint_response assertion and change it to assert
mint_response.status_code == 201 to match token_management.py behavior.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 29, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.14%. Comparing base (b7b121d) to head (746153b).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
...rsions/a8c5e1d3f7b2_add_tokens_with_roles_assoc.py 85.71% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7276      +/-   ##
==========================================
+ Coverage   92.08%   92.14%   +0.05%     
==========================================
  Files         277      278       +1     
  Lines       10778    10794      +16     
  Branches      697      697              
==========================================
+ Hits         9925     9946      +21     
+ Misses        700      696       -4     
+ Partials      153      152       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jakejellinek jakejellinek merged commit 09bec6a into master Apr 29, 2026
39 of 40 checks passed
@jakejellinek jakejellinek deleted the flowauth/token-roles-visible branch April 29, 2026 10:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FlowAuth: surface assigned roles on the user's token list

1 participant