Skip to content

feat: Support DPoP in /token endpoint - #1581

Merged
gtema merged 6 commits into
mainfrom
dpop
Oct 22, 2026
Merged

gtema merged 6 commits into
mainfrom
dpop

Conversation

@gtema

@gtema gtema commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator
  • feat(oauth2): Add effective DPoP mode
  • feat(oauth2): Bind client credentials to DPoP key
  • feat(oauth2): Bind authorization code to DPoP key
  • feat(oauth2): Bind device code grant to DPoP key
  • feat(oauth2): Bind refresh tokens to DPoP key
  • feat(oauth2): Bind token exchange to DPoP key

gtema added 6 commits October 22, 2026 17:43
Resolve the DPoP mode of a request as the strictest of the global,
domain and client levels, as described in ADR 0043 section 1. The
client flag means required, and the global value is a floor for the
domain setting.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
Add the shared DPoP handling of the token endpoint: replay cache and
nonce generator on the service state, the proof header checks with
rate limiting, nonce challenge and error codes, and wire it into the
client_credentials grant, which now returns token_type DPoP and a cnf
claim when a proof is accepted (ADR 0043 section 3).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
Accept dpop_jkt on /authorize and keep it on the pre-auth session and
the authorization code. The authorization_code grant validates the
proof before it redeems the code, requires the code's key when one was
announced, and issues a DPoP-typed access token with a cnf claim and a
refresh token family bound to the same key (ADR 0043 section 3).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
Validate the DPoP proof of every device code poll before the grant is
fetched, require the key stored with the grant when there is one, and
issue a DPoP-typed access token with a cnf claim and a bound refresh
token family (ADR 0043 section 3).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
Require a proof from the family key on every refresh of a bound
family and revoke the family when a valid proof from another key is
presented, as for a detected reuse. A missing, stale or replayed proof
is only a bad request and never ends a session (ADR 0043 section 3.3).
Rotated access tokens carry the cnf claim.

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
Check the proof of a token exchange before the subject token and bind
the exchanged token to its key, rejecting the request when the
effective mode is required and no proof is sent. A subject token that
carries a cnf claim is refused rather than exchanged for an unbound
token (ADR 0043 section 4).

Assisted-by: Claude <noreply@anthropic.com>
Signed-off-by: Artem Goncharov <artem.goncharov@gmail.com>
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

🐰 Bencher Report

Projectkeystone
Branchdpop
Testbedubuntu-latest

🚨 3 Alerts

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
Command_Serde/unpack/deleteLatency
nanoseconds (ns)
📈 plot
🚷 threshold
🚨 alert (🔔)
218.11 ns
(+51.72%)Baseline: 143.76 ns
215.92 ns
(101.02%)

Command_Serde/unpack/set_indexLatency
nanoseconds (ns)
📈 plot
🚷 threshold
🚨 alert (🔔)
188.93 ns
(+55.93%)Baseline: 121.17 ns
179.39 ns
(105.32%)

get_dbLatency
nanoseconds (ns)
📈 plot
🚷 threshold
🚨 alert (🔔)
0.40 ns
(+34.93%)Baseline: 0.29 ns
0.38 ns
(104.98%)

Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
Command_Serde/apply/remove📈 view plot
🚷 view threshold
84,236.00 ns
(-39.36%)Baseline: 138,920.41 ns
263,914.11 ns
(31.92%)
Command_Serde/apply/set📈 view plot
🚷 view threshold
91,185.00 ns
(-36.57%)Baseline: 143,767.73 ns
248,736.11 ns
(36.66%)
Command_Serde/pack/delete📈 view plot
🚷 view threshold
142.00 ns
(+23.86%)Baseline: 114.65 ns
164.29 ns
(86.43%)
Command_Serde/pack/delete_index📈 view plot
🚷 view threshold
121.74 ns
(+18.13%)Baseline: 103.05 ns
144.10 ns
(84.48%)
Command_Serde/pack/set📈 view plot
🚷 view threshold
244.02 ns
(+31.06%)Baseline: 186.20 ns
271.28 ns
(89.95%)
Command_Serde/pack/set_index📈 view plot
🚷 view threshold
121.93 ns
(+17.83%)Baseline: 103.48 ns
146.33 ns
(83.33%)
Command_Serde/unpack/delete📈 view plot
🚷 view threshold
🚨 view alert (🔔)
218.11 ns
(+51.72%)Baseline: 143.76 ns
215.92 ns
(101.02%)

Command_Serde/unpack/delete_index📈 view plot
🚷 view threshold
178.26 ns
(+46.69%)Baseline: 121.53 ns
181.16 ns
(98.40%)
Command_Serde/unpack/set📈 view plot
🚷 view threshold
296.92 ns
(+33.53%)Baseline: 222.36 ns
341.91 ns
(86.84%)
Command_Serde/unpack/set_index📈 view plot
🚷 view threshold
🚨 view alert (🔔)
188.93 ns
(+55.93%)Baseline: 121.17 ns
179.39 ns
(105.32%)

Payload_encryption/pack/remove_cmd📈 view plot
🚷 view threshold
144.17 ns
(+35.68%)Baseline: 106.25 ns
158.58 ns
(90.91%)
Payload_encryption/pack/set_cmd📈 view plot
🚷 view threshold
269.20 ns
(+40.28%)Baseline: 191.90 ns
292.52 ns
(92.03%)
Payload_encryption/unpack/remove_cmd📈 view plot
🚷 view threshold
212.51 ns
(+45.63%)Baseline: 145.93 ns
217.43 ns
(97.74%)
Payload_encryption/unpack/set_cmd📈 view plot
🚷 view threshold
290.10 ns
(+27.84%)Baseline: 226.93 ns
348.96 ns
(83.13%)
Raft_1Node_Latency/prefix/1node📈 view plot
🚷 view threshold
5,008,800.00 ns
(+39.00%)Baseline: 3,603,328.28 ns
8,713,442.50 ns
(57.48%)
Raft_1Node_Latency/read/1node📈 view plot
🚷 view threshold
34,923.00 ns
(+2.05%)Baseline: 34,222.53 ns
52,430.36 ns
(66.61%)
Raft_1Node_Latency/remove/1node📈 view plot
🚷 view threshold
254,330.00 ns
(-28.99%)Baseline: 358,162.03 ns
601,466.39 ns
(42.28%)
Raft_1Node_Latency/write/1node📈 view plot
🚷 view threshold
285,910.00 ns
(-27.37%)Baseline: 393,651.41 ns
773,437.05 ns
(36.97%)
build_snapshot/default📈 view plot
🚷 view threshold
2,174.50 ns
(+4.68%)Baseline: 2,077.34 ns
2,810.68 ns
(77.37%)
fernet token/project📈 view plot
🚷 view threshold
1,703.40 ns
(+35.06%)Baseline: 1,261.23 ns
1,743.97 ns
(97.67%)
get_data_keyspace📈 view plot
🚷 view threshold
0.36 ns
(+22.86%)Baseline: 0.29 ns
0.38 ns
(95.33%)
get_db📈 view plot
🚷 view threshold
🚨 view alert (🔔)
0.40 ns
(+34.93%)Baseline: 0.29 ns
0.38 ns
(104.98%)

get_fernet_token_timestamp/project📈 view plot
🚷 view threshold
180.71 ns
(+37.90%)Baseline: 131.04 ns
183.36 ns
(98.56%)
get_keyspace📈 view plot
🚷 view threshold
4.55 ns
(-32.91%)Baseline: 6.78 ns
15.89 ns
(28.62%)
🐰 View full continuous benchmarking report in Bencher

@github-actions

Copy link
Copy Markdown

🧪 Tempest Identity Compatibility Results (advisory, non-blocking)

rust

Totals
======
Ran: 133 tests in 33.2092 sec.
 - Passed: 81
 - Skipped: 4
 - Expected Fail: 0
 - Unexpected Success: 0
 - Failed: 48
Sum of execute time for each test: 29.9579 sec.
Failed test IDs
===== FAILED TESTS (target=rust) =====
tempest.api.identity.admin.v3.test_credentials.CredentialsTestJSON.test_credentials_create_get_update_delete[id-7cd59bf9-bda4-4c72-9467-d21cab278355,smoke]
tempest.api.identity.admin.v3.test_domain_configuration.DomainConfigurationTestJSON.test_create_domain_config_and_show_config_groups_and_options[id-9e3ff13c-f597-4f01-9377-d6c06c2a1477]
tempest.api.identity.admin.v3.test_domain_configuration.DomainConfigurationTestJSON.test_create_update_and_delete_domain_config_groups_and_opts[id-c7510fa2-6661-4170-9c6b-4783a80651e9]
tempest.api.identity.admin.v3.test_domain_configuration.DomainConfigurationTestJSON.test_show_default_group_config_and_options[id-11a02bf0-6f94-4380-b3b0-c8dc18fc0d22]
tempest.api.identity.admin.v3.test_domains_negative.DomainsNegativeTestJSON.test_delete_active_domain[gate,id-1f3fbff5-4e44-400d-9ca1-d953f05f609b,negative]
tempest.api.identity.admin.v3.test_default_project_id.TestDefaultProjectId.test_default_project_id[id-d6110661-6a71-49a7-a453-b5e26640ff6d]
tempest.api.identity.admin.v3.test_oauth_consumers.OAUTHConsumersV3Test.test_create_and_show_consumer[id-c8307ea6-a86c-47fd-ae7b-5b3b2caca76d]
tempest.api.identity.admin.v3.test_oauth_consumers.OAUTHConsumersV3Test.test_delete_consumer[id-fdfa1b7f-2a31-4354-b2c7-f6ae20554f93]
tempest.api.identity.admin.v3.test_oauth_consumers.OAUTHConsumersV3Test.test_list_consumers[id-09ca50de-78f2-4ffb-ac71-f2254036b2b8]
tempest.api.identity.admin.v3.test_oauth_consumers.OAUTHConsumersV3Test.test_update_consumer[id-080a9b1a-c009-47c0-9979-5305bf72e3dc]
setUpClass (tempest.api.identity.admin.v3.test_endpoint_groups.EndPointGroupsTest)
tempest.api.identity.admin.v3.test_policies.PoliciesTestJSON.test_create_update_delete_policy[id-e544703a-2f03-4cf2-9b0f-350782fdb0d3,smoke]
tempest.api.identity.admin.v3.test_policies.PoliciesTestJSON.test_list_policies[id-1a0ad286-2d06-4123-ab0d-728893a76201]
tempest.api.identity.admin.v3.test_list_projects.ListProjectsTestJSON.test_list_projects_with_parent[id-6edc66f5-2941-4a17-9526-4073311c1fac]
tempest.api.identity.admin.v3.test_project_tags.IdentityV3ProjectTagsTest.test_list_update_delete_project_tags[id-7c123aac-999d-416a-a0fb-84b915ab10de]
tempest.api.identity.admin.v3.test_groups.GroupsV3TestJSON.test_group_users_add_list_delete[id-1598521a-2f36-4606-8df9-30772bd51339,smoke]
tempest.api.identity.admin.v3.test_groups.GroupsV3TestJSON.test_list_user_groups[id-64573281-d26a-4a52-b899-503cb0f4e4ec]
tempest.api.identity.admin.v3.test_projects.ProjectsTestJSON.test_create_is_domain_project[id-a7eb9416-6f9b-4dbb-b71b-7f73aaef59d5]
tempest.api.identity.admin.v3.test_projects.ProjectsTestJSON.test_project_create_with_parent[id-1854f9c0-70bc-4d11-a08a-1c789d339e3d]
tempest.api.identity.admin.v3.test_inherits.InheritsV3TestJSON.test_inherit_assign_check_revoke_roles_on_projects_group[id-26021436-d5a4-4256-943c-ded01e0d4b45]
tempest.api.identity.admin.v3.test_inherits.InheritsV3TestJSON.test_inherit_assign_check_revoke_roles_on_projects_user[id-18b70e45-7687-4b72-8277-b8f1a47d7591]
tempest.api.identity.admin.v3.test_inherits.InheritsV3TestJSON.test_inherit_assign_list_check_revoke_roles_on_domains_group[id-c7a8dda2-be50-4fb4-9a9c-e830771078b1]
tempest.api.identity.admin.v3.test_inherits.InheritsV3TestJSON.test_inherit_assign_list_check_revoke_roles_on_domains_user[id-4e6f0366-97c8-423c-b2be-41eae6ac91c8]
tempest.api.identity.admin.v3.test_inherits.InheritsV3TestJSON.test_inherit_assign_list_revoke_user_roles_on_domain[id-3acf666e-5354-42ac-8e17-8b68893bcd36]
tempest.api.identity.admin.v3.test_inherits.InheritsV3TestJSON.test_inherit_assign_list_revoke_user_roles_on_project_tree[id-9f02ccd9-9b57-46b4-8f77-dd5a736f3a06]
tempest.api.identity.admin.v3.test_tokens.TokensV3TestJSON.test_get_available_domain_scopes[id-ec5ecb05-af64-4c04-ac86-4d9f6f12f185]
tempest.api.identity.v3.test_application_credentials.ApplicationCredentialsV3Test.test_create_application_credential_expires[id-852daf0c-42b5-4239-8466-d193d0543ed3]
tempest.api.identity.admin.v3.test_tokens.TokensV3TestJSON.test_rescope_token[id-565fa210-1da1-4563-999b-f7b5b67cf112]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_assignments_for_domain_roles[id-3859df7e-5b78-4e4d-b10e-214c8953842a]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_assignments_for_implied_roles_create_delete[id-c8828027-df48-4021-95df-b65b92c7429e]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_grant_list_revoke_role_to_group_on_domain[id-4bf8a70b-e785-413a-ad53-9f91ce02faa7]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_grant_list_revoke_role_to_group_on_project[id-cbf11737-1904-4690-9613-97bcbb3df1c4]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_grant_list_revoke_role_to_user_on_domain[id-6c9a2940-3625-43a3-ac02-5dcec62ef3bd]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_implied_domain_roles[id-eb1e1c24-1bc4-4d47-9748-e127a1852c82]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_implied_roles_create_check_show_delete[id-c90c316c-d706-4728-bcba-eb1912081b69]
tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_api_media_types[id-657c1970-4722-4189-8831-7325f3bc4265,smoke]
tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_api_version_resources[id-b9232f5e-d9e5-4d97-b96c-28d3db4de1bd,smoke]
tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_identity_v3_existence[id-79aec9ae-710f-4c54-a4fc-3aa25b4feac3]
tempest.api.identity.v3.test_api_discovery.TestApiDiscovery.test_list_api_versions[id-721f480f-35b6-46c7-846e-047e6acea0dc,smoke]
tempest.api.identity.admin.v3.test_roles.RolesV3TestJSON.test_role_create_update_show_list[id-18afc6c0-46cf-4911-824e-9989cc056c3a,smoke]
tempest.api.identity.v3.test_tokens.TokensV3Test.test_validate_token[id-a9512ac3-3909-48a4-b395-11f438e16260]
tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_get_trusts_all[id-4773ebd5-ecbf-4255-b8d8-b63e6f72b65d,smoke]
tempest.api.identity.admin.v3.test_users_negative.UsersNegativeTest.test_create_user_for_non_existent_domain[id-e75f006c-89cc-477b-874d-588e4eab4b17,negative]
tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_get_trusts_query[id-6268b345-87ca-47c0-9ce3-37792b43403a]
tempest.api.identity.v3.test_catalog.IdentityCatalogTest.test_catalog_standardization[id-56b57ced-22b8-4127-9b8a-565dfb0207e2]
tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_trust_expire[id-0ed14b66-cefd-4b5c-a964-65759453e292]
tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_trust_impersonate[id-5a0a91a4-baef-4a14-baba-59bf4d7fcace]
tempest.api.identity.admin.v3.test_trusts.TrustsV3TestJSON.test_trust_noimpersonate[id-ed2a8779-a7ac-49dc-afd7-30f32f936ed2]
===== END FAILED TESTS (target=rust) =====

View full run

@github-actions

Copy link
Copy Markdown

🦢 Load Test Results

Goose Attack Report

Plan Overview

Action Started Stopped Elapsed Users
Increasing 26-10-22 17:13:31 26-10-22 17:13:55 00:00:24 0 → 45
Maintaining 26-10-22 17:13:55 26-10-22 17:14:25 00:00:30 45
Decreasing 26-10-22 17:14:25 26-10-22 17:14:25 00:00:00 0 ← 45

Request Metrics

Method Name # Requests # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
DELETE DELETE /v3/auth/tokens 54 0 458.31 134 604 1.80 0.00
DELETE DELETE /v3/projects/:id (teardown) 1 0 146.00 146 146 0.03 0.00
DELETE DELETE /v3/roles/:id (teardown) 1 0 95.00 95 95 0.03 0.00
DELETE DELETE /v3/users/:id (teardown) 2 0 200.50 92 309 0.07 0.00
DELETE DELETE /v4/mappings/rulesets/:mapping_id (cc teardown) 1 0 16.00 16 16 0.03 0.00
DELETE DELETE /v4/mappings/rulesets/:mapping_id (teardown) 1 0 292.00 292 292 0.03 0.00
DELETE DELETE /v4/oauth2/:domain_id/clients/:provider_id (cc teardown) 1 0 16.00 16 16 0.03 0.00
DELETE DELETE /v4/oauth2/:domain_id/clients/:provider_id (teardown) 1 0 116.00 116 116 0.03 0.00
GET 599 0 488.58 268 734 19.97 0.00
GET GET /SCIM/v2/:domain_id/Users (sync reconcile list) 47 31 300.70 3 737 1.57 1.03
GET GET /v3/auth/tokens (validate new) 54 0 444.35 261 625 1.80 0.00
GET GET /v3/auth/tokens (validate revoked) 54 0 393.96 64 544 1.80 0.00
GET GET /v3/projects/:id 68 0 448.29 288 581 2.27 0.00
GET GET /v3/projects/:id (catalog) 100 0 445.87 234 636 3.33 0.00
GET GET /v3/role_assignments 52 0 468.37 299 704 1.73 0.00
GET GET /v3/role_assignments?role.id 51 0 421.98 280 593 1.70 0.00
GET GET /v3/role_assignments?scope.domain.id 51 0 442.63 307 578 1.70 0.00
GET GET /v3/role_assignments?user.id 52 0 435.23 293 602 1.73 0.00
GET GET /v3/roles 136 0 447.74 286 641 4.53 0.00
GET GET /v3/roles/:id 67 0 452.76 283 623 2.23 0.00
GET GET /v3/users/:id 128 0 474.32 272 672 4.27 0.00
GET GET /v3/users/:id (catalog) 125 0 459.19 250 620 4.17 0.00
GET GET /v4/api-keys 34 0 432.88 297 626 1.13 0.00
GET GET /v4/api-keys/:client_id 35 0 446.43 252 656 1.17 0.00
GET GET /v4/mappings/rulesets 34 0 442.91 307 578 1.13 0.00
GET GET /v4/mappings/rulesets/:mapping_id 35 0 430.37 310 563 1.17 0.00
GET GET /v4/oauth2/:domain_id/.well-known/openid-configuration 1931 0 23.11 3 357 64.37 0.00
GET GET /v4/oauth2/:domain_id/clients 35 0 421.66 296 534 1.17 0.00
GET GET /v4/oauth2/:domain_id/clients/:provider_id 36 0 434.19 247 621 1.20 0.00
GET GET /v4/oauth2/:domain_id/jwks 1929 0 22.62 2 350 64.30 0.00
GET GET /v4/scim_realms 22 0 437.73 353 564 0.73 0.00
GET GET /v4/scim_realms/:domain_id/:provider_id 22 0 437.77 288 607 0.73 0.00
POST POST /v3/auth/tokens 51 0 424.25 246 565 1.70 0.00
POST POST /v3/auth/tokens (password, invalid) 48 0 642.04 379 1207 1.60 0.00
POST POST /v3/auth/tokens (password, project-scoped) 75 0 918.99 635 1337 2.50 0.00
POST POST /v3/auth/tokens (password, unscoped) 75 0 718.01 399 1079 2.50 0.00
POST POST /v3/auth/tokens (rescope to system) 119 0 511.02 323 693 3.97 0.00
POST POST /v3/auth/tokens (rescope, invalid project) 72 0 420.38 266 578 2.40 0.00
POST POST /v3/auth/tokens (system-scoped, bootstrap admin) 69 0 893.30 543 1299 2.30 0.00
POST POST /v4/api-keys/:client_id/revoke (teardown) 1 0 82.00 82 82 0.03 0.00
POST POST /v4/oauth2/:domain_id/device_authorization 525 0 56.80 9 393 17.50 0.00
POST POST /v4/oauth2/:domain_id/token (client_credentials) 15 0 621.20 314 974 0.50 0.00
PUT PUT /v4/scim_realms/:domain_id/:provider_id 23 0 492.91 293 734 0.77 0.00
Aggregated 6832 31 194.71 2 1337 227.73 1.03

Response Time Metrics

Method Name 50%ile (ms) 60%ile (ms) 70%ile (ms) 80%ile (ms) 90%ile (ms) 95%ile (ms) 99%ile (ms) 100%ile (ms)
DELETE DELETE /v3/auth/tokens 470 490 500 500 600 600 600 600
DELETE DELETE /v3/projects/:id (teardown) 146 146 146 146 146 146 146 146
DELETE DELETE /v3/roles/:id (teardown) 95 95 95 95 95 95 95 95
DELETE DELETE /v3/users/:id (teardown) 92 92 92 309 309 309 309 309
DELETE DELETE /v4/mappings/rulesets/:mapping_id (cc teardown) 16 16 16 16 16 16 16 16
DELETE DELETE /v4/mappings/rulesets/:mapping_id (teardown) 292 292 292 292 292 292 292 292
DELETE DELETE /v4/oauth2/:domain_id/clients/:provider_id (cc teardown) 16 16 16 16 16 16 16 16
DELETE DELETE /v4/oauth2/:domain_id/clients/:provider_id (teardown) 116 116 116 116 116 116 116 116
GET 490 500 500 600 600 600 700 700
GET GET /SCIM/v2/:domain_id/Users (sync reconcile list) 350 370 420 600 600 700 700 700
GET GET /v3/auth/tokens (validate new) 450 460 480 490 500 600 600 600
GET GET /v3/auth/tokens (validate revoked) 400 410 440 470 500 500 500 500
GET GET /v3/projects/:id 440 470 480 500 500 581 581 581
GET GET /v3/projects/:id (catalog) 440 460 490 500 600 600 600 600
GET GET /v3/role_assignments 470 480 500 500 600 600 600 700
GET GET /v3/role_assignments?role.id 430 440 460 480 500 500 500 593
GET GET /v3/role_assignments?scope.domain.id 460 470 480 500 500 500 500 578
GET GET /v3/role_assignments?user.id 430 460 470 500 500 600 600 600
GET GET /v3/roles 450 480 500 500 500 500 600 600
GET GET /v3/roles/:id 460 480 500 500 600 600 600 600
GET GET /v3/users/:id 470 500 500 600 600 600 600 672
GET GET /v3/users/:id (catalog) 470 490 500 500 600 600 600 600
GET GET /v4/api-keys 430 450 480 480 500 500 600 600
GET GET /v4/api-keys/:client_id 440 450 480 500 600 600 656 656
GET GET /v4/mappings/rulesets 450 460 500 500 500 500 578 578
GET GET /v4/mappings/rulesets/:mapping_id 420 430 470 500 500 500 563 563
GET GET /v4/oauth2/:domain_id/.well-known/openid-configuration 16 20 24 29 42 59 140 357
GET GET /v4/oauth2/:domain_id/clients 430 440 460 470 500 500 500 500
GET GET /v4/oauth2/:domain_id/clients/:provider_id 430 460 470 500 500 600 600 600
GET GET /v4/oauth2/:domain_id/jwks 17 20 23 29 41 53 120 350
GET GET /v4/scim_realms 440 450 470 480 500 500 564 564
GET GET /v4/scim_realms/:domain_id/:provider_id 420 440 460 500 600 600 600 600
POST POST /v3/auth/tokens 420 440 460 490 500 500 565 565
POST POST /v3/auth/tokens (password, invalid) 600 700 700 700 900 1,000 1,000 1,000
POST POST /v3/auth/tokens (password, project-scoped) 900 1,000 1,000 1,000 1,000 1,000 1,000 1,000
POST POST /v3/auth/tokens (password, unscoped) 700 700 800 800 900 900 1,000 1,000
POST POST /v3/auth/tokens (rescope to system) 500 500 600 600 600 600 693 693
POST POST /v3/auth/tokens (rescope, invalid project) 400 440 460 480 500 500 578 578
POST POST /v3/auth/tokens (system-scoped, bootstrap admin) 900 900 1,000 1,000 1,000 1,000 1,000 1,000
POST POST /v4/api-keys/:client_id/revoke (teardown) 82 82 82 82 82 82 82 82
POST POST /v4/oauth2/:domain_id/device_authorization 47 53 63 76 93 120 220 390
POST POST /v4/oauth2/:domain_id/token (client_credentials) 600 600 700 700 800 800 974 974
PUT PUT /v4/scim_realms/:domain_id/:provider_id 500 500 500 600 600 600 700 700
Aggregated 33 64 380 460 500 600 900 1,000

Status Code Metrics

Method Name Status Codes
DELETE DELETE /v3/auth/tokens 54 [204]
DELETE DELETE /v3/projects/:id (teardown) 1 [204]
DELETE DELETE /v3/roles/:id (teardown) 1 [204]
DELETE DELETE /v3/users/:id (teardown) 2 [204]
DELETE DELETE /v4/mappings/rulesets/:mapping_id (cc teardown) 1 [204]
DELETE DELETE /v4/mappings/rulesets/:mapping_id (teardown) 1 [204]
DELETE DELETE /v4/oauth2/:domain_id/clients/:provider_id (cc teardown) 1 [204]
DELETE DELETE /v4/oauth2/:domain_id/clients/:provider_id (teardown) 1 [204]
GET 599 [200]
GET GET /SCIM/v2/:domain_id/Users (sync reconcile list) 31 [401], 16 [429]
GET GET /v3/auth/tokens (validate new) 54 [200]
GET GET /v3/auth/tokens (validate revoked) 54 [404]
GET GET /v3/projects/:id 68 [200]
GET GET /v3/projects/:id (catalog) 100 [200]
GET GET /v3/role_assignments 52 [200]
GET GET /v3/role_assignments?role.id 51 [200]
GET GET /v3/role_assignments?scope.domain.id 51 [200]
GET GET /v3/role_assignments?user.id 52 [200]
GET GET /v3/roles 136 [200]
GET GET /v3/roles/:id 67 [200]
GET GET /v3/users/:id 128 [200]
GET GET /v3/users/:id (catalog) 125 [200]
GET GET /v4/api-keys 34 [200]
GET GET /v4/api-keys/:client_id 35 [200]
GET GET /v4/mappings/rulesets 34 [200]
GET GET /v4/mappings/rulesets/:mapping_id 35 [200]
GET GET /v4/oauth2/:domain_id/.well-known/openid-configuration 1,931 [200]
GET GET /v4/oauth2/:domain_id/clients 35 [200]
GET GET /v4/oauth2/:domain_id/clients/:provider_id 36 [200]
GET GET /v4/oauth2/:domain_id/jwks 1,929 [200]
GET GET /v4/scim_realms 22 [200]
GET GET /v4/scim_realms/:domain_id/:provider_id 22 [200]
POST POST /v3/auth/tokens 51 [201]
POST POST /v3/auth/tokens (password, invalid) 48 [401]
POST POST /v3/auth/tokens (password, project-scoped) 75 [201]
POST POST /v3/auth/tokens (password, unscoped) 75 [201]
POST POST /v3/auth/tokens (rescope to system) 119 [201]
POST POST /v3/auth/tokens (rescope, invalid project) 72 [401]
POST POST /v3/auth/tokens (system-scoped, bootstrap admin) 69 [201]
POST POST /v4/api-keys/:client_id/revoke (teardown) 1 [200]
POST POST /v4/oauth2/:domain_id/device_authorization 525 [200]
POST POST /v4/oauth2/:domain_id/token (client_credentials) 15 [200]
PUT PUT /v4/scim_realms/:domain_id/:provider_id 23 [200]
Aggregated 16 [429], 54 [404], 151 [401], 62 [204], 389 [201], 6,160 [200]

Transaction Metrics

Transaction # Times Run # Fails Average (ms) Min (ms) Max (ms) RPS Failures/s
ReadHeavy
0.0 1 0 6.00 6 6 0.03 0.00
0.1 86 0 504.66 345 679 2.87 0.00
0.2 86 0 452.33 299 631 2.87 0.00
0.3 85 0 456.62 268 632 2.83 0.00
TokenLifecycle
1.0 0 0 0.00 0 0 0.00 0.00
1.1 54 0 1720.30 929 2162 1.80 0.00
ValidateToken
2.0 0 0 0.00 0 0 0.00 0.00
2.1 113 0 539.72 356 734 3.77 0.00
UserCRUD
3.0 0 0 0.00 0 0 0.00 0.00
3.1 0 0 0.00 0 0 0.00 0.00
3.2 128 0 474.36 272 672 4.27 0.00
3.3 2 0 200.50 92 309 0.07 0.00
ProjectCRUD
4.0 0 0 0.00 0 0 0.00 0.00
4.1 0 0 0.00 0 0 0.00 0.00
4.2 68 0 448.38 288 581 2.27 0.00
4.3 1 0 146.00 146 146 0.03 0.00
RoleCRUD
5.0 0 0 0.00 0 0 0.00 0.00
5.1 0 0 0.00 0 0 0.00 0.00
5.2 67 0 452.81 283 623 2.23 0.00
5.3 1 0 95.00 95 95 0.03 0.00
RoleList
6.0 0 0 0.00 0 0 0.00 0.00
6.1 136 0 447.79 286 641 4.53 0.00
RoleAssignmentList
7.0 0 0 0.00 0 0 0.00 0.00
7.1 52 0 468.46 299 704 1.73 0.00
7.2 52 0 435.31 293 602 1.73 0.00
7.3 51 0 442.67 307 578 1.70 0.00
7.4 51 0 422.04 280 593 1.70 0.00
UserRead
8.0 0 0 0.00 0 0 0.00 0.00
8.1 128 0 503.12 355 673 4.27 0.00
8.2 125 0 459.29 250 620 4.17 0.00
ProjectRead
9.0 0 0 0.00 0 0 0.00 0.00
9.1 101 0 457.22 294 592 3.37 0.00
9.2 100 0 445.88 234 636 3.33 0.00
PasswordAuth
10.0 75 0 718.09 399 1079 2.50 0.00
10.1 75 0 919.03 635 1337 2.50 0.00
PasswordAuthNegative
11.0 48 0 642.10 379 1207 1.60 0.00
Rescope
12.0 0 0 0.00 0 0 0.00 0.00
12.1 119 0 511.06 323 693 3.97 0.00
RescopeNegative
13.0 0 0 0.00 0 0 0.00 0.00
13.1 72 0 420.40 266 578 2.40 0.00
SystemScopeAuth
14.0 69 0 893.36 543 1299 2.30 0.00
ApiKeyCRUD
15.0 0 0 0.00 0 0 0.00 0.00
15.1 0 0 0.00 0 0 0.00 0.00
15.2 35 0 446.51 252 656 1.17 0.00
15.3 34 0 432.88 297 626 1.13 0.00
15.4 1 0 82.00 82 82 0.03 0.00
MappingCRUD
16.0 0 0 0.00 0 0 0.00 0.00
16.1 0 0 0.00 0 0 0.00 0.00
16.2 35 0 430.46 310 563 1.17 0.00
16.3 34 0 442.94 307 578 1.13 0.00
16.4 1 0 292.00 292 292 0.03 0.00
OAuth2ClientCRUD
17.0 0 0 0.00 0 0 0.00 0.00
17.1 0 0 0.00 0 0 0.00 0.00
17.2 36 0 434.28 247 621 1.20 0.00
17.3 35 0 421.71 296 534 1.17 0.00
17.4 1 0 116.00 116 116 0.03 0.00
OAuth2ClientCredentials
18.0 0 0 0.00 0 0 0.00 0.00
18.1 0 0 0.00 0 0 0.00 0.00
18.2 15 0 621.27 314 974 0.50 0.00
18.3 1 0 33.00 33 33 0.03 0.00
OAuth2DeviceAuthorization
19.0 525 0 56.85 10 393 17.50 0.00
OAuth2Discovery
20.0 1929 0 22.66 2 350 64.30 0.00
20.1 1931 0 23.15 3 357 64.37 0.00
ScimRealmRead
21.0 0 0 0.00 0 0 0.00 0.00
21.1 22 0 437.86 288 607 0.73 0.00
21.2 22 0 437.77 353 564 0.73 0.00
21.3 23 0 492.91 293 734 0.77 0.00
ScimSync
22.0 0 0 0.00 0 0 0.00 0.00
22.1 0 0 0.00 0 0 0.00 0.00
22.2 0 0 0.00 0 0 0.00 0.00
22.3 48 0 649.65 219 1034 1.60 0.00
22.4 47 0 0.00 0 0 1.57 0.00
22.5 47 0 0.00 0 0 1.57 0.00
22.6 1 0 0.00 0 0 0.03 0.00
Aggregated 6769 0 196.52 2 2162 225.63 0.00

Scenario Metrics

Transaction # Users # Times Run Average (ms) Min (ms) Max (ms) Scenarios/s Iterations
ReadHeavy 4 85 1420.13 1102 1767 2.83 21.25
TokenLifecycle 3 51 1761.84 1468 2162 1.70 17.00
ValidateToken 2 111 542.23 356 734 3.70 55.50
UserCRUD 2 126 476.40 272 672 4.20 63.00
ProjectCRUD 1 67 449.21 288 581 2.23 67.00
RoleCRUD 1 66 454.85 283 623 2.20 66.00
RoleList 2 134 449.60 290 641 4.47 67.00
RoleAssignmentList 3 51 1776.29 1485 2026 1.70 17.00
UserRead 4 125 964.72 695 1174 4.17 31.25
ProjectRead 3 99 904.38 653 1133 3.30 33.00
PasswordAuth 4 73 1637.64 1150 2071 2.43 18.25
PasswordAuthNegative 1 47 645.09 379 1207 1.57 47.00
Rescope 2 117 512.32 323 693 3.90 58.50
RescopeNegative 1 71 421.13 266 578 2.37 71.00
SystemScopeAuth 2 67 893.01 543 1299 2.23 33.50
ApiKeyCRUD 1 34 885.62 703 1137 1.13 34.00
MappingCRUD 1 34 874.44 684 1108 1.13 34.00
OAuth2ClientCRUD 1 35 861.74 689 1014 1.17 35.00
OAuth2ClientCredentials 1 15 2122.80 1735 2611 0.50 15.00
OAuth2DeviceAuthorization 1 524 56.73 10 393 17.47 524.00
OAuth2Discovery 3 1928 46.24 7 383 64.27 642.67
ScimRealmRead 1 22 1377.45 1171 1657 0.73 22.00
ScimSync 1 47 655.96 219 1034 1.57 47.00
Aggregated 45 3929 344.43 7 2611 130.97 2019.92

Error Metrics

Method Name # Error
GET GET /SCIM/v2/:domain_id/Users (sync reconcile list) 50 401 Unauthorized: GET /SCIM/v2/:domain_id/Users (sync reconcile list)
POST POST /SCIM/v2/:domain_id/Users (sync provision) 1 401 Unauthorized: POST /SCIM/v2/:domain_id/Users (sync provision)
POST POST /v3/auth/tokens (password, invalid) 112 401 Unauthorized: POST /v3/auth/tokens (password, invalid)
POST POST /v3/auth/tokens (rescope, invalid project) 190 401 Unauthorized: POST /v3/auth/tokens (rescope, invalid project)
GET GET /v3/auth/tokens (validate revoked) 200 404 Not Found: GET /v3/auth/tokens (validate revoked)
GET GET /SCIM/v2/:domain_id/Users (sync reconcile list) 38 429 Too Many Requests: GET /SCIM/v2/:domain_id/Users (sync reconcile list)

View full report

@gtema
gtema added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 9f7edcd Oct 22, 2026
42 checks passed
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.

1 participant