From f8252bcd0c63b9dfc41a212718f90eccfa207495 Mon Sep 17 00:00:00 2001 From: Gao Sun <14722250+gao-sun@users.noreply.github.com> Date: Wed, 10 Dec 2025 00:31:15 -0800 Subject: [PATCH] docs: handle user permission change --- .../_handle-user-permission-change.mdx | 31 +++++++++++++++++++ docs/authorization/global-api-resources.mdx | 7 ++--- .../organization-level-api-resources.mdx | 3 ++ .../organization-permissions.mdx | 3 ++ package.json | 1 + 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 docs/authorization/fragments/_handle-user-permission-change.mdx diff --git a/docs/authorization/fragments/_handle-user-permission-change.mdx b/docs/authorization/fragments/_handle-user-permission-change.mdx new file mode 100644 index 00000000000..edfd75b5dfd --- /dev/null +++ b/docs/authorization/fragments/_handle-user-permission-change.mdx @@ -0,0 +1,31 @@ +### Optional: Handle user permission change \{#optional-handle-user-permission-change} + +User permissions can change at any time. Because Logto issues JWTs for RBAC, permission updates only appear in newly issued tokens, and never modify existing JWTs. + +:::info Scope subset rule +An access token can only include scopes that were requested in the original OAuth authorization flow. +Even if a user gains new permissions, the token issued later can only contain a subset of the originally requested scopes. +To access newly granted scopes that were not part of the initial request, the client must run a new authorization flow. +::: + +#### Downscoped permissions + +When a user loses permissions: + +- Newly issued tokens immediately reflect the reduced scopes. +- Existing JWTs keep the old scopes until they expire. +- Your API should always validate scopes and rely on short token lifetimes. + +If you need faster reactions, implement your own signal that tells clients to refresh their tokens. + +#### Enlarged permissions + +{props.type === "global" &&

For global API resources, when a user gains permissions, enlarged permissions will NOT show up through refresh. The client must perform a new OAuth authorization flow to obtain a token that includes the new scopes. This can happen silently if the user has an active Logto session.

} + +{props.type === "organization" &&

For organization tokens, when a user gains permissions, enlarged permissions will show up on the next issuance (refresh or token request). A new token is still required, but no full re-auth is needed unless the new scopes exceed the original request set.

} + +#### Recommendations + +- Validate scopes in your API on every call. +- Keep token expiration short. +- Add optional notifications if you need immediate permission-change propagation. diff --git a/docs/authorization/global-api-resources.mdx b/docs/authorization/global-api-resources.mdx index 9e0db69028a..577492616f7 100644 --- a/docs/authorization/global-api-resources.mdx +++ b/docs/authorization/global-api-resources.mdx @@ -6,6 +6,7 @@ import illustration from '@site/docs/authorization/assets/rbac-global-api-resour import AuthorizationRequestExample from '@site/docs/authorization/fragments/AuthorizationRequestExample'; import ClientCredentialsRequestExample from '@site/docs/authorization/fragments/ClientCredentialsRequestExample'; import TokenRequestExample from '@site/docs/authorization/fragments/TokenRequestExample'; +import HandleUserPermissionChange from '@site/docs/authorization/fragments/_handle-user-permission-change.mdx'; import TabItem from '@theme/TabItem'; import Tabs from '@theme/Tabs'; @@ -192,11 +193,7 @@ When your API receives a request with a Logto-issued access token, you should: For step-by-step and language-specific guides, see [How to validate access tokens](/authorization/validate-access-tokens). -### Optional: Handle user permission change \{#optional-handle-user-permission-change} - -:::info -👷 Work in progress. 🚧 -::: + ## Best practices and security tips \{#best-practices-and-security-tips} diff --git a/docs/authorization/organization-level-api-resources.mdx b/docs/authorization/organization-level-api-resources.mdx index 800c2bba8a8..44494406b85 100644 --- a/docs/authorization/organization-level-api-resources.mdx +++ b/docs/authorization/organization-level-api-resources.mdx @@ -6,6 +6,7 @@ import illustration from '@site/docs/authorization/assets/rbac-organization-leve import AuthorizationRequestExample from '@site/docs/authorization/fragments/AuthorizationRequestExample'; import ClientCredentialsRequestExample from '@site/docs/authorization/fragments/ClientCredentialsRequestExample'; import TokenRequestExample from '@site/docs/authorization/fragments/TokenRequestExample'; +import HandleUserPermissionChange from '@site/docs/authorization/fragments/_handle-user-permission-change.mdx'; import TabItem from '@theme/TabItem'; import Tabs from '@theme/Tabs'; @@ -210,6 +211,8 @@ When your app receives an organization token, you should: For step-by-step and language-specific guides, see [How to validate access tokens](/authorization/validate-access-tokens). + + ## Best practices and security tips \{#best-practices-and-security-tips} - **Always validate the organization context:** Don’t trust just the token; check the `organization_id` claim for every organization-scoped API call. diff --git a/docs/authorization/organization-permissions.mdx b/docs/authorization/organization-permissions.mdx index 7f0c2dcde14..004dcc9e58e 100644 --- a/docs/authorization/organization-permissions.mdx +++ b/docs/authorization/organization-permissions.mdx @@ -6,6 +6,7 @@ import illustration from '@site/docs/authorization/assets/rbac-organization-perm import AuthorizationRequestExample from '@site/docs/authorization/fragments/AuthorizationRequestExample'; import ClientCredentialsRequestExample from '@site/docs/authorization/fragments/ClientCredentialsRequestExample'; import TokenRequestExample from '@site/docs/authorization/fragments/TokenRequestExample'; +import HandleUserPermissionChange from '@site/docs/authorization/fragments/_handle-user-permission-change.mdx'; import TabItem from '@theme/TabItem'; import Tabs from '@theme/Tabs'; @@ -198,6 +199,8 @@ When your app receives an organization token, you should: For step-by-step and language-specific guides, see [How to validate access tokens](/authorization/validate-access-tokens). + + ## Best practices and security tips \{#best-practices-and-security-tips} - **Never rely solely on UI enforcement:** Always validate permissions on the backend for critical actions. diff --git a/package.json b/package.json index 9941736336d..e880a2b70b5 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "glob@>=10.2.0 <10.5.0": "^10.5.0" }, "onlyBuiltDependencies": [ + "@swc/core", "core-js", "core-js-pure", "sharp"