Repository navigation
v1.0.0-beta.72 lets the batch authorization check answer permissions a realm or a client owns, makes an absent and a null
realmIdmean the same thing on create, and stops introspection from listing grants a scope-restricted token cannot use. These notes cover the changes since v1.0.0-beta.71.
👀 Highlights
🔐 Realm- and client-owned permissions reach the batch check
POST /authorization/check evaluated global permission definitions only. A permission provisioned in a realm, or owned by a client, never appeared in the answer, so usePermissionCheck denied it in every console even though the introspection listed the grant (#3769).
The request now keeps two realms apart. realms and clients select which definitions are evaluated, by owner. targetRealms (the former meaning of realms) names the resource realms each definition is checked against.
POST /authorization/check
{
- "realms": "ownOrNull"
+ "realms": "granted",
+ "clients": "granted",
+ "targetRealms": "ownOrNull"
}Both owner selectors take own, ownOrNull, granted or a list of ids, and default to [null], the global definitions only. granted adds the owner of every definition the identity holds a grant of, which is how a user of realm B reaches a permission master owns without naming master. The kit store asks for granted on both.
Each answer entry now carries realmId and clientId (omitted when null), so one name can appear once per owner. A bare name still checks the global definition, so a check gating an owned permission names its owner by id:
const canSubmit = usePermissionCheck({
name: 'mtb_query_submit',
realmId: masterRealmId,
});The same { name, realmId?, clientId? } shape works for the APermissionCheck props, @authup/client-web-nuxt route meta (alone or mixed with names in one array) and the record helpers in @authup/access.
Warning
Upgrade the server and @authup/client-web-kit together. An older kit against a newer server, or the reverse, reads the wrong keys and lands on a deny-all evaluator, so every permission-gated control disappears.
Note
GET /authorization is camelCase now: each definition carries realmId, clientId and decisionStrategy, and @authup/access refuses a catalog in the old shape. The permissions grant list on the introspection response stays snake_case.
📖 POST /authorization/check answers realm- and client-owned permissions
🌐 A missing realmId means the same as null
On create, a body that omits realmId and one that sends realmId: null used to mean different things, and many JSON serializers drop a null field, so the difference did not survive the trip. They now mean the same, and the entity type decides what:
- Permissions, roles, scopes and policies without a realm are global rows. They used to land in the caller's realm.
- Users, clients, paths and identity providers keep landing in the caller's realm, and now accept
realmId: nulltoo (it used to be refused as an invalid uuid).
POST /roles
{
"name": "auditor",
+ "realmId": "<realm id>"
}A permission or role naming an owning clientId takes that client's realm instead, and a realm that differs from the client's is refused. The owning clientId can no longer be changed on update.
Lookups by name follow the same rule. PUT or POST /<entity>/<name> without realmId addresses the global row for the four global-capable entities, and the caller's realm for users, clients and identity providers, which used to look the name up in every realm. A body realmId that names no realm answers 400.
Warning
A realm admin holds its create grants at own reach, which excludes global rows. A realm admin creating a permission, role, scope or policy without realmId now gets 403 and has to send its realm id. The admin console already does.
Note
Existing rows are not migrated. Only new requests are read the new way.
📖 A missing realmId creates a global permission, role, scope or policy
🔎 Introspection reports no grants for a token without global
Since v1.0.0-beta.70 a token whose scope lacks global evaluates no grants on the request path, but both introspection endpoints still listed its full grant set. A resource server building createAuthorizationEvaluator from that answer allowed user_read for a token the server itself refuses on GET /users.
POST /token/introspect now reads the introspected token's scope, and GET /sessions/@me/introspect the request's own, and both report permissions: [] without global. Console cookie sessions carry global, so they are unchanged, and the kit store is unaffected: its verdicts already came from the batch check.
🧰 Smaller fixes worth knowing about
- The default per-user rate limit (
core.rateLimitUserMax,RATE_LIMIT_USER_MAX) rises from 6000 to 15000 requests a minute. A deployment that sets the key keeps its own value. nodemailermoves to 10.1.7,joseto 6.2.13 and@napi-rs/keyringto 2.1.2 (#3762).
⚠️ Heads-Up Before Upgrading
| Change | What to do |
|---|---|
| Batch check request and response | Upgrade the server, @authup/client-web-kit and @authup/client-web-nuxt together. Rename realms to targetRealms in hand-written calls. |
| Owned permissions need their owner | Pass realmId / clientId to usePermissionCheck, APermissionCheck and route meta for a permission a realm or client owns. |
GET /authorization is camelCase |
Upgrade @authup/access together with the server on resource servers. |
No realmId means global for permissions, roles, scopes, policies |
Send realmId (or use the nested /realms/:realmId/... route) where a script relied on the caller's realm. Realm admins must send it. |
| Custom global permissions reach every realm admin | Create a permission with realmId to keep it to one realm: a global one is granted to realm_admin on the next server start. |
Unknown body realmId answers 400 |
Fix callers that sent a stale or misspelled realm key. |
⬆️ Upgrading
For an installation using the operator CLI:
npm install authup@1.0.0-beta.72 --save-exactUpdate the @authup/* SDK packages your application consumes to the same release, @authup/client-web-kit, @authup/client-web-nuxt and @authup/access in particular.
👉 Changelog
Full diff: v1.0.0-beta.71...v1.0.0-beta.72
⚠ BREAKING CHANGES
- server-core: a permission, role, scope or policy created without a realmId is now global instead of landing in the caller's realm; a realm admin must send its realm id or receives 403. A name-keyed PUT or update without realmId addresses the global row (users, clients and identity providers: the caller's realm). An unknown realmId in the body answers 400. clientId can no longer be changed on update. Existing rows are not migrated; see the upgrade notes.
realmson POST /authorization/check now selects the definition realms; the former meaning istargetRealms, in the request and on each entry. GET /authorization answers realmId, clientId and decisionStrategy. Upgrade the server and @authup/client-web-kit together.
Features
- check realm- and client-owned permissions in the batch authorization check (#3770) (bff9f21), closes #3769
- server-config: raise the default per-user rate limit to 15000 requests a minute (68c0f11)
- server-core: treat an absent and a null realmId alike on create (#3771) (e72bfc5)