permission: cache user info and parallelize resolution

The permission backend previously resolved userInfo and minted a plugin
request token sequentially for every authorize request with user
credentials. On high-traffic endpoints this meant two serial internal
HTTP round-trips per request, even when the same user made many
requests in quick succession.

This change:

1. Adds a 5-second TTL cache to DefaultUserInfoService so that repeated
   getUserInfo() calls for the same user return the cached result
   without an HTTP call to the auth backend.

2. Parallelises the getUserInfo() and getPluginRequestToken() calls in
   the permission backend's handleRequest via Promise.all, saving one
   sequential round-trip on cache misses.

Signed-off-by: Fredrik Adelöw <freben@gmail.com>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2026-05-14 11:53:36 +02:00
parent ada7df7929
commit 2f0519cba3
12 changed files with 306 additions and 51 deletions
@@ -0,0 +1,5 @@
---
'@backstage/plugin-permission-backend': patch
---
The permission backend no longer populates the removed `token` and `identity` fields on `PolicyQueryUser`, and no longer calls `auth.getPluginRequestToken()` during policy evaluation. This removes one internal round-trip per authorize request.
@@ -0,0 +1,11 @@
---
'@backstage/plugin-permission-node': minor
---
**BREAKING**: Cleaned up the `PolicyQueryUser` type:
- `token`**Removed.** Was previously deprecated in favor of `credentials` with `coreServices.auth`.
- `expiresInSeconds`**Removed.** Was previously deprecated.
- `identity`**Removed.** Was previously deprecated in favor of `info`.
- `info`**Deprecated.** Still required and populated for now; will be made optional and then removed in a future release.
- `credentials` — Unchanged.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-defaults': patch
---
Added a new `CachedUserInfoService` decorator that wraps `DefaultUserInfoService` with a 5-second TTL cache and in-flight request coalescing. The decorator is wired in via `userInfoServiceFactory` using a shared root-level cache. Repeated `getUserInfo()` calls for the same user token within the TTL window return the cached result without making an HTTP call to the auth backend. Note that custom `UserInfoService` implementations registered via their own factory will not benefit from this cache automatically.