Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: clarify token revocation #2749

Merged
merged 4 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions uaa/slateCustomizations/source/index.html.md.erb
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,39 @@ _Response Fields_
Added in UAA 3.3.0
</aside>

Both access and refresh tokens can be passed to the ``/revoke`` endpoint.

When an access token is successfully passed to the ``/revoke`` endpoint, and then when the same token is
passed to the UAA Introspect Token endpoint (``/introspect``), the UAA Introspect Token endpoint
will respond with ``"active": false``.

If the access token is in the JWT format (as opposed to the opaque format), the server config ``uaa.jwt.revocable`` or
the Identity Zone config ``config.tokenPolicy.jwtRevocable`` must be set to ``true`` for
the revocation to work. However, OAuth resource servers are not required to call the UAA Introspect
Token endpoint to validate the token. Once issued, from a security point of view, a valid access token
in the JWT format should be considered valid until its expiry. Hence, we do not recommend
relying on this endpoint to revoke access tokens in the JWT format. If the ability
to remove/limit access after the tokens are issued is important to you, we recommend the following instead:

* Ask the OAuth client to use opaque tokens only, so that the OAuth resource server is required to use
peterhaochen47 marked this conversation as resolved.
Show resolved Hide resolved
the UAA Introspect Token endpoint to validate that the tokens have not been revoked.
peterhaochen47 marked this conversation as resolved.
Show resolved Hide resolved
* If the access tokens are in the JWT format, configure the access tokens to be short-lived
(e.g. a few minutes), and when needed, revoke the more long-lived refresh tokens so that they
may no longer be used to obtain refreshed access tokens.

When a refresh token is successfully passed to the ``/revoke`` endpoint,
peterhaochen47 marked this conversation as resolved.
Show resolved Hide resolved
the refresh token can no longer be used to perform the Refresh Token grant.

Refresh tokens in any format can be revoked using the "Revoke all tokens for a user" endpoint (``/oauth/token/revoke/user/{userId}``),
the "Revoke all tokens for a client" endpoint (``/oauth/token/revoke/client/{clientId}``), or
the "Revoke all tokens for a user and client combination" endpoint (``/oauth/token/revoke/user/{userId}/client/{clientId}``).

Comment on lines +404 to +407
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe link to the API docs could be useful for all the different endpoints?

Copy link
Member Author

Choose a reason for hiding this comment

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

I find that more than trivial to execute, but please feel free to make further improvements to the doc yourself.

Refresh tokens in the opaque format can be individually revoked using
the "Revoke a single token" endpoint (``/oauth/token/revoke/{tokenId}``).
However, refresh tokens in the JWT format can only be individually revoked using
peterhaochen47 marked this conversation as resolved.
Show resolved Hide resolved
the "Revoke a single token" endpoint when the server config ``uaa.jwt.revocable`` or
the Identity Zone config ``config.tokenPolicy.jwtRevocable`` is set to ``true``.

### Revoke all tokens for a user

<%= render('TokenEndpointDocs/revokeAllTokens_forAUser/curl-request.md') %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class TokenEndpointDocs extends AbstractTokenMockMvcTests {

private final ParameterDescriptor clientIdParameter = parameterWithName(CLIENT_ID).optional(null).type(STRING).description("A unique string representing the registration information provided by the client, the recipient of the token. Optional if it is passed as part of the Basic Authorization header or as part of the client_assertion.");
private final ParameterDescriptor clientSecretParameter = parameterWithName("client_secret").optional(null).type(STRING).description("The [secret passphrase configured](#change-secret) for the OAuth client. Optional if it is passed as part of the Basic Authorization header or if client_assertion is sent as part of private_key_jwt authentication.");
private final ParameterDescriptor opaqueFormatParameter = parameterWithName(REQUEST_TOKEN_FORMAT).optional(null).type(STRING).description("Can be set to `" + OPAQUE.getStringValue() + "` to retrieve an opaque and revocable token or to `" + JWT.getStringValue() + "` to retrieve a JWT token. If not set the zone setting config.tokenPolicy.jwtRevocable is used.");
private final ParameterDescriptor opaqueFormatParameter = parameterWithName(REQUEST_TOKEN_FORMAT).optional(null).type(STRING).description("Can be set to `" + OPAQUE.getStringValue() + "` to retrieve an opaque token or to `" + JWT.getStringValue() + "` to retrieve a JWT token. Please refer to the Revoke Tokens endpoint doc for information about the revocability of opaque vs. jwt tokens. If not set the zone setting config.tokenPolicy.jwtRevocable is used.");
private final ParameterDescriptor scopeParameter = parameterWithName(SCOPE).optional(null).type(STRING).description("The list of scopes requested for the token. Use when you wish to reduce the number of scopes the token will have.");
private final ParameterDescriptor loginHintParameter = parameterWithName("login_hint").optional(null).type(STRING).description("<small><mark>UAA 75.5.0</mark></small> Indicates the identity provider to be used. The passed string has to be a URL-Encoded JSON Object, containing the field `origin` with value as `origin_key` of an identity provider. Note that this identity provider must support the grant type `password`.");
private final ParameterDescriptor codeVerifier = parameterWithName(PkceValidationService.CODE_VERIFIER).description("<small><mark>UAA 75.5.0</mark></small> [PKCE](https://tools.ietf.org/html/rfc7636) Code Verifier. A `code_verifier` parameter must be provided if a `code_challenge` parameter was present in the previous call to `/oauth/authorize`. The `code_verifier` must match the used `code_challenge` (according to the selected `code_challenge_method`)").attributes(key("constraints").value("Optional"), key("type").value(STRING));
Expand Down
Loading