Table of Contents | ||
---|---|---|
|
Review Changes
For those viewing this document after the initial review meeting, here are the core changes made since then:
Removed Device Code flow
Device code flow would only be used when a browser is not available. It is advantageous when in a setting with limited input features (e.g. a smart TV). Synapse is almost never used in this setting (a keyboard, or copy-paste is always available to a user). It does not seem like it is worth the engineering effort at this time.
Added Synapse Client refresh token generation
A user may generate client refresh tokens via the API/Web Client and paste them into a client/configuration file. Intended to replace device code flow.
Added sequence diagrams
Added detail to use cases (no major changes from what was discussed)
Added a section on PKCE
Overview and Use Cases
Added detail to workflow use case
Sequence diagrams
Removed CLI use case and related requirements
Requirements for workflows use case is a subset of the CLI requirements. Let’s tackle workflows first and talk about CLI later.
Renamed endpoints for auditing tokens from
/oauth2/permissions
to/oauth2/grantedClients
Overview and Selected Use Case
This document will outline the design and implementation of OAuth 2.0 refresh tokens and token revocation in Synapse.
...
Token Revocation:
Jira Legacy | ||||||
---|---|---|---|---|---|---|
|
Refresh Tokens
...
Use Case: Workflows
Users are interested in running workflows (which require access to a user’s identity and resources. Refresh tokens are an optional component defined in the OAuth 2.0 specification.
Use Cases for Refresh Tokens
The two key use cases we plan to enable with refresh tokens are support for workflow resource access, and OAuth authentication in the Synapse command line apps.
Refresh Tokens for Workflows
Users are interested in running workflows (which require access to a user’s Synapse resources) on workflow engines operated by a third party. Because the workflow engine is operated by a third party, it is unacceptable for a user to authorize access using their username and password, or their API key. The short-lived OAuth access tokens currently in Synapse are not sufficient for this use case either, because a submission to a workflow engine may sit in a queue and/or execute for a duration exceeding the lifetime of an access Synapse resources) on workflow engines operated by a third party. Because the workflow engine is operated by a third party, it is unacceptable for a user to authorize access using their username and password, or their API key. The short-lived OAuth access tokens currently in Synapse are not sufficient for this use case either, because a submission to a workflow engine may sit in a queue and/or execute for a duration exceeding the lifetime of an access token (currently 24 hours).
These issues are can be overcome by issuing a refresh token to the workflow engine.
...
Refresh Tokens
Refresh tokens would allow a 3rd party client to request a new access token from Synapse. This enables OAuth clients to have long-lived access to a user’s identity and resources. Refresh tokens are an optional component defined in the OAuth 2.0 specification.
Info |
---|
Details about how evaluations and workflows could interact are intended as examples and are not the focus of this document |
...
Note that in this example, there is no authorization/consent flow. This is because consent to third party access is granted by submitting a job to the evaluation queue. There may be other scenarios involving workflows that do not utilize evaluations, and a typical authorization /consent flow code flow, including granting consent, may be used
Refresh Tokens for Synapse Command Line Applications
To authenticate in a Synapse CLI, a user must provide either their username and password, or an API key. This information is then stored locally to authenticate in the future.
Ideally, users should not enter/save their password anywhere other than the Synapse login page in the browser. Entering/storing the passwords in a command line application leaves the user susceptible to attack by anyone who can view that user’s files or command history.
Using an API key is better, but current flaws are that a user may only have one active API key at any time, the API key is unscoped, and it never expires.
With refresh tokens, users can authenticate their session in a browser, and a refresh token may be stored locally. Multiple refresh tokens may be issued, allowing for granular, machine-level access and revocation. We can also require the refresh token to expire if unused for a certain period of time, reducing the risk of a token being discovered on a forgotten machine.
...
Tokens may also be generated by the user in cases where the command line client cannot be authorized via a browser (e.g. ssh, cronjobs/noninteractive sessions). If a user is logged into the web client, they could create them there.
...
Token Revocation
Because refresh tokens allow a user to issue long-lived access to a 3rd party client, we should allow users and clients to revoke this access. This gives a user more control over their data, and additional services allow a user to audit their granted permissions so they may re-evaluate the services with access to their data. In cases where a client no longer needs access to a Synapse user’s resources, they may revoke the token in order to prevent future unauthorized access.
User-centric token revocation is not defined in any of the OAuth Specifications. The OIDC Specification § 16.18 simply suggests it:
The Authorization Server SHOULD provide a mechanism for the End-User to revoke Access Tokens and Refresh Tokens granted to a Client.
Thus the design for this feature is influenced by other services, such as those showcased by Okta/OAuth.com on their page Listing Authorizations.
Use Cases for user-centric token revocation
A user may no longer trust or need to use an OAuth client that has been granted access to their Synapse identity and resources (revoke all tokens from one client)
A user may no longer have access to a machine with their Synapse credentials used for a command line application, but they do not wish to expire all machines on which they are authenticated (revoke one token from one client)
A user may forget about a machine on which they have authenticated, and would benefit from being signed out automatically (token expiration)
Client-centric token revocation is defined in RFC 7009. From the RFC:
From an end-user's perspective, OAuth is often used to log into a certain site or application. This revocation mechanism allows a client to invalidate its tokens if the end-user logs out, changes identity, or uninstalls the respective application. Notifying the authorization server that the token is no longer needed allows the authorization server to clean up data associated with that token (e.g., session data) and the underlying authorization grant. This behavior prevents a situation in which there is still a valid authorization grant for a particular client of which the end-user is not aware. This way, token revocation prevents abuse of abandoned tokens and facilitates a better end-user experience since invalidated authorization grants will no longer turn up in a list of authorization grants the authorization server might present to the end-user.
...
Use Case for client-centric token revocation in context
Resource access is no longer needed by the client. As an example, a job executed by an OAuth client may no longer require access to a user’s Synapse account at the conclusion of a job. They may revoke the token to ensure it is no longer valid.
Token Revocation Behavior
Currently, only short-lived access tokens are minted in Synapse, and these tokens cannot be revoked because they are not stored in the database.
Since we will be issuing long-lived refresh tokens, we will need a mechanism to revoke refresh tokens. While not necessary, it would be ideal to also revoke the access tokens themselves. (RFC 7009 § 2)
To accomplish this, we can store refresh tokens in the database, which can be revoked by a user or client with a REST API call. Once the refresh token is revoked, it may no longer be used to generate access tokens.
By linking an access token to its associated refresh token, we are able to invalidate access tokens without storing them in the database.
Linking Access Tokens to Refresh Tokens
Access tokens are JWTs, so they can securely transmit information. Thus we can link any particular access token to the refresh token that permits it to be issued by adding a claim to the access token that contains its corresponding refresh token ID. The JWT specification § 4.2 suggests we use a namespace for this claim, (e.g. Auth0 recommends a URL like https://synapse.org/refresh_token_id
or https://sagebionetworks.org/refresh_token_id
, but we should be able to use a reverse domain name like org.sagebionetworks.repo.model.oauth.claims.refresh_token_id
). As a side note, I think we are already in violation of this specification, since we currently use nonstandard, non-namespaced claims such as orcid
, is_certified
, etc. We should determine if we should get back “in-spec” and add namespaces to the existing claims (breaking API change).
When we verify the access token, we can deserialize the JWT and make a database call to see if the corresponding refresh token is revoked. If the refresh token is revoked, we reject the request.
Similarly, when an access token is revoked, we just revoke the refresh token (RFC 7009 § 2.1: “If the token passed to the [revocation] request is an access token, the server MAY revoke the respective refresh token as well.”)
Since we are now storing refresh tokens in the database, we can link them to the user and show them when the user wants to see them. Since access tokens are directly linked to refresh tokens, we need not show them (under this design, we couldn’t because we don’t even store them)
Additional Scope: offline_access
Per OIDC Core 1.0 § 11, we should only permit the use of a refresh token when a client requests the offline_access
scope.
When offline_access
is not requested, we can issue only a short-lived access token that is not associated with a refresh token (this is the current behavior of the system).
(Aside: the specification only requires that without the offline_access
scope, a refresh token may not be used to issue tokens that access identity. The specification does not dictate that we could not otherwise use a refresh token. For the sake of simplicity, we can apply this to all permissions and only issue refresh tokens when offline_access
is approved.)
REST API
This section will identify four new objects used in the REST API, eight new endpoints, and an extended implementation for an existing endpoint.
New objects
There are four new objects proposed in this document.
OAuthClientAuthorization
This object can be used to show a user the OAuth clients that have access to the requesting user’s resources and identity. Using this information, the user can identify the client that has access, how long the client has had access, and how recently the client has accessed that user’s resources by requesting a new access token.
...
Field
...
Type
...
Description
...
client
...
...
Client information that can be displayed to the end user
...
authorizedOn
...
date-time
...
The time when access was first granted (i.e. the issue date of the oldest active refresh token)
...
lastUsed
...
date-time
...
The most recent time a refresh token was used to issue a new access token
OAuthRefreshTokenInformation
This object captures information about an active refresh token, intended to be seen by the user whose resources can be accessed by the token. Note that the token itself is not shown.
...
Field
...
Type
...
Description
...
tokenId
...
integer
...
Unique ID of the token
...
clientId
...
integer
...
Unique ID of the client that possesses this token
...
name
...
string
...
A human-readable identifier for the token. We may initially set this to a string of random words. The user is able to overwrite this field (e.g to identify the machine on which this token lives)
...
scopes
...
Array<OAuthScope>
...
The scopes that the client can request using this refresh token
...
authorizedOn
...
date-time
...
The time when this token was first issued
...
lastUsed
...
date-time
...
The most recent time this refresh token was used to issue a new access token
...
modifiedOn
...
date-time
...
The last time this token’s metadata (i.e. name) was updated.
...
etag
...
string
...
For OCC
OAuthTokenRevocationRequest
This object is used when a client makes a request to revoke a refresh/access token. It is defined by RFC 7009 § 2.1.
...
Field
...
Type
...
Description
...
token
...
string
...
The token to revoke
...
token_type_hint
...
enum
...
The type of token to revoke (must be access_token
or refresh_token
)
GenerateOAuthTokenRequest
This object is used when a user triggers generation of an OAuth refresh token used in command line apps.
...
Field
...
Type
...
Description
...
name
...
string
...
An optional identifier for the token. Must be unique among this user’s tokens.
...
scopes
...
Array<OAuthScope>
...
The scopes that this token grants access to.
New API Endpoints
Eight new endpoints and an extension of implementation for one existing endpoint are proposed.
Viewing applications that have OAuth access to a user’s account
Endpoint: GET /oauth2/permissions/
Request body: none
Return body: PaginatedList<OAuthClientAuthorization>
Returns a paginated list of the clients and permissions that the user has granted. Allows a user to audit which parties have access to their resources.
Viewing tokens for an application that has OAuth access to a user’s account
Endpoint: GET /oauth2/permissions/:client_id/tokens
Path Parameter: client_id
: returned tokens will be associated with this OAuth2 client
Request body: none
Return body: PaginatedList<OAuthRefreshTokenInformation>
Returns a paginated list of the clients and permissions that the user has granted. Allows a user to audit which parties have access to their resources.
User revocation of a client’s access
Endpoint: POST /oauth2/permissions/:client_id/revoke
Path Parameter: client_id
: the OAuth2 client that will no longer have access to the user’s resources and/or identity
Response: On successful revocation, return HTTP 200. No body.
Upon calling this method, the refresh token and access tokens held by the specified client for the authenticated user making the API call will be revoked.
Update metadata for a token
Endpoint: PUT /oauth2/permissions/:client_id/tokens/:token_id
Request Parameters:
client_id
: the OAuth2 client that is associated with the tokentoken_id
: the token to update
Request Body: OAuthRefreshTokenInformation
Response: On successful update, return HTTP 200. No body
Upon calling this method, the token identifier will be updated
In practice, only the token name can be updated.
User revocation of a particular access token
Endpoint: POST /oauth2/permissions/:client_id/tokens/:token_id/revoke
Request Parameters:
client_id
: the OAuth2 client that is associated with the token to revoketoken_id
: the token to revoke
Response: On successful revocation, return HTTP 200. No body.
Upon calling this method, the refresh token and access tokens held by the specified client for the authenticated user making the API call will be revoked.
Client revocation of a token
Endpoint: POST /oauth2/revoke
Request Body: OAuthTokenRevocationRequest
Response: By RFC 7009 § 2.2, on successful revocation, HTTP 200. No body.
Upon calling this method, the refresh/access token and associated tokens held by this client and associated with the user are revoked. Note: a specific path for this endpoint is not named by OAuth 2.0/OIDC specifications.
Client retrieval of token metadata
Endpoint: GET /oauth2/token/:token_id/metadata
Request Parameter: token_id
- the ID of the token to gather metadata about
Response: OAuthRefreshTokenInformation
The client can call this endpoint to get token metadata name. This metadata can be displayed to the user so that they may more easily identify the token in use when auditing/revoking tokens.
Requesting a new access token with a refresh token
Endpoint: POST /oauth2/token
This method exists. This feature proposal would add support for grant_type=refresh_token
, and return a refresh token for grant_type=code
. For details, see OIDC Core 1.0 § 12.1, 12.2.
Additionally, we should require that a refresh token be passed in the request body and not as a request parameter. If the token is passed as a request parameter, it will be logged in the web application firewall and on the server, so it is insecure.
We should also consider enabling the device code flow (this is the “smart TV” flow: the client will request a short code from Synapse and display the code to the user. The user enters the code into Synapse on a separate device, and the authorization is approved), for cases where a user may be accessing a Synapse command line app without access to a browser.
Requesting a refresh token for command line apps
Endpoint: POST /oauth2/token/cli
Request Body: GenerateOAuthTokenRequest
Response: String (an OAuth refresh token)
A user can call this method to generate a refresh token that can be used by the Synapse command line clients. The UI should inform the user that this token cannot be shown again after it is generated.
The user may do this to generate revocable refresh tokens that may be used by Synapse command line clients where an OAuth authorization code flow is not available, e.g. when ssh’d or in non-interactive sessions like Jenkins.
This may be considered a replacement for API keys.
Public vs. Private Clients - A Security Note
It is important to understand the distinction between confidential and public OAuth clients, and how they would interact with Synapse (RFC 6749 § 2.1).
A confidential client is capable of keeping their credentials confidential. The example given in the OAuth specification is a web application running on a web server. In another context, this could also be a workflow engine. Maintaining the confidentiality of the client credentials adds an additional layer of security because the credentials must be supplied when using a refresh token to request an access token.
A public client cannot ensure that their credentials are confidential. Examples given in the OAuth specification are user agent based applications (i.e. a single-page application where the client code runs in the browser) and native applications (where the client credentials may be extracted or decompiled, exposing a client secret). In our context, the Synapse CLI applications would act as public clients (i.e. the client secret is not a secret).
A major implication of this is that refresh tokens issued to public clients (e.g. the Synapse Python client) are no more secure than bearer tokens (any user may use it because the client secret is not confidential).
Despite the security flaw, this scheme is used in practice
For native apps integrating with Google, they simply suggest embedding your secret in the app, noting that it is not really a secret
GSUtil, the command line app for interfacing with Google Cloud, stores credentials in the app
MSAL, Microsoft’s current authorization library, indicates that Microsoft internally discerns public/confidential clients (public clients do not have a secret).
This doesn’t remove all of the benefits of using OAuth in Synapse CLIs. Using OAuth still accomplishes
Removing password from the authentication flow
Scoped access
Ability to issue multiple tokens and revoke them individually
Additional usage context for a user (e.g. for a particular refresh token or client you can say “Used for Synapse CLI 2 days ago”)
Backend Implementation Detail: Database Model
This section covers implementation details that will not be visible to users of the new services, and is not necessary to read to have an understanding of how to use the new services.
To support revoking refresh tokens, we will need to track them in the database. As mentioned earlier, we can trace access tokens to a refresh token by adding a refresh token ID to the access token as a JWT claim. By doing this, we only need to store records of refresh tokens in the database.
We hash the token to reduce the severity of tokens being exposed. It is proposed that tokens will be randomly generated, and then hashed using SHA256, but changing this is open to discussion.
New DB Table: OAUTH_REFRESH_TOKENS
...
Name
...
Type
...
Notes
...
ID
...
INTEGER
...
Primary key
...
TOKEN_HASH
...
CHAR(64)
...
SHA256 hash of the refresh token passed to the client
...
NAME
...
VARCHAR(256)
...
Human-readable identifier for the token
...
USER_ID
...
BIGINT
...
Foreign key reference to the principal whose resources this token grants access to
...
CLIENT_ID
...
BIGINT
...
The client that this token is issued to
...
SCOPE
...
VARCHAR(256)
...
The scope/permissions that the refresh token allows. Stored as a serialized array of strings (is there a better way to do this? a binary column for each possible scope?)
...
CREATED_ON
...
TIMESTAMP
...
When this refresh token was created
...
LAST_USED
...
TIMESTAMP
...
The last time this refresh token was used to issue an access token
...
MODIFIED_ON
...
TIMESTAMP
...
The last time this token was modified (i.e. the name was changed)
...
ETAG
...
CHAR(36)
...
For OCC
...
Token Revocation
Because refresh tokens allow a user to issue long-lived access to a 3rd party client, we should allow users and clients to revoke this access. This gives a user more control over their data, and additional services allow a user to audit their granted permissions so they may re-evaluate the services with access to their data. In cases where a client no longer needs access to a Synapse user’s resources, they may revoke the token in order to prevent future unauthorized access.
User-centric token revocation is not defined in any of the OAuth Specifications. The OIDC Specification § 16.18 simply suggests it:
The Authorization Server SHOULD provide a mechanism for the End-User to revoke Access Tokens and Refresh Tokens granted to a Client.
Thus the design for this feature is influenced by other services, such as those showcased by Okta/OAuth.com on their page Listing Authorizations.
Use Cases for user-centric token revocation
An user may no longer trust or need to use an OAuth client that has been granted access to their Synapse identity and resources
Client-centric token revocation is defined in RFC 7009. From the RFC:
From an end-user's perspective, OAuth is often used to log into a certain site or application. This revocation mechanism allows a client to invalidate its tokens if the end-user logs out, changes identity, or uninstalls the respective application. Notifying the authorization server that the token is no longer needed allows the authorization server to clean up data associated with that token (e.g., session data) and the underlying authorization grant. This behavior prevents a situation in which there is still a valid authorization grant for a particular client of which the end-user is not aware. This way, token revocation prevents abuse of abandoned tokens and facilitates a better end-user experience since invalidated authorization grants will no longer turn up in a list of authorization grants the authorization server might present to the end-user.
...
Use Case for client-centric token revocation in context
Resource access is no longer needed by the client. As an example, a job executed by an OAuth client may no longer require access to a user’s Synapse resources at the conclusion of a job. They may revoke the token to ensure it is no longer valid.
Token Revocation Behavior
Currently, only short-lived access tokens are minted in Synapse, and these tokens cannot be revoked because they are not stored in the database.
Since we will be issuing long-lived refresh tokens, we will need a mechanism to revoke refresh tokens. While not necessary, it would be ideal to also revoke the access tokens themselves. (RFC 7009 § 2)
To accomplish this, we can store refresh tokens in the database, which can be revoked by a user or client with a REST API call. Once the refresh token is revoked, it may no longer be used to generate access tokens.
By linking an access token to its associated refresh token, we are able to invalidate access tokens without storing them in the database.
Linking Access Tokens to Refresh Tokens
Access tokens are JWTs, so they can securely transmit information. Thus we can link any particular access token to the refresh token that permits it to be issued by adding a claim to the access token that contains its corresponding refresh token ID. The JWT specification § 4.2 suggests we use a namespace for this claim, (e.g. Auth0 recommends a URL like https://synapse.org/refresh_token_id
or https://sagebionetworks.org/refresh_token_id
, but we should be able to use a reverse domain name like org.sagebionetworks.repo.model.oauth.claims.refresh_token_id
). As a side note, I think we are already in violation of this specification, since we currently use nonstandard, non-namespaced claims such as orcid
, is_certified
, etc. We should determine if we should get back “in-spec” and add namespaces to the existing claims (breaking API change).
When we verify the access token, we can deserialize the JWT and make a database call to see if the corresponding refresh token is revoked. If the refresh token is revoked, we reject the request.
Similarly, when an access token is revoked, we just revoke the refresh token (RFC 7009 § 2.1: “If the token passed to the [revocation] request is an access token, the server MAY revoke the respective refresh token as well.”)
Since we are now storing refresh tokens in the database, we can link them to the user and show them when the user wants to see them. Since access tokens are directly linked to refresh tokens, we need not show them (under this design, we couldn’t because we don’t even store them)
Additional Scope: offline_access
Per OIDC Core 1.0 § 11, we should only permit the use of a refresh token when a client requests the offline_access
scope.
When offline_access
is not requested, we can issue only a short-lived access token that is not associated with a refresh token (this is the current behavior of the system).
(Aside: the specification only requires that without the offline_access
scope, a refresh token may not be used to issue tokens that access identity. The specification does not dictate that we could not otherwise use a refresh token. For the sake of simplicity, we can apply this to all permissions and only issue refresh tokens when offline_access
is approved.)
REST API
This section will identify three new objects used in the REST API, seven new endpoints, and an extended implementation for an existing endpoint.
New objects
There are three new objects proposed in this document.
OAuthClientAuthorization
This object can be used to show a user the OAuth clients that have access to the requesting user’s resources and identity. Using this information, the user can identify the client that has access, how long the client has had access, and how recently the client has accessed that user’s resources by requesting a new access token.
Field | Type | Description |
---|---|---|
client | Client information that can be displayed to the end user | |
authorizedOn | date-time | The time when access was first granted (i.e. the issue date of the oldest active refresh token) |
lastUsed | date-time | The most recent time a refresh token was used to issue a new access token |
OAuthRefreshTokenInformation
This object captures information about an active refresh token, intended to be seen by the user whose resources can be accessed by the token. Note that the token itself is not shown.
Field | Type | Description |
---|---|---|
tokenId | integer | Unique ID of the token |
clientId | integer | Unique ID of the client that possesses this token |
name | string | A human-readable identifier for the token. We may initially set this to a string of random words. The user is able to overwrite this field (e.g to identify the machine on which this token lives) |
scopes | Array<OAuthScope> | The scopes that the client can request using this refresh token |
authorizedOn | date-time | The time when this token was first issued |
lastUsed | date-time | The most recent time this refresh token was used to issue a new access token |
modifiedOn | date-time | The last time this token’s metadata (i.e. name) was updated. |
etag | string | For OCC |
OAuthTokenRevocationRequest
This object is used when a client makes a request to revoke a refresh/access token. It is defined by RFC 7009 § 2.1.
Field | Type | Description |
---|---|---|
token | string | The token to revoke |
token_type_hint | enum | The type of token to revoke (must be |
New API Endpoints
This section outlines new endpoints and the behavior of each.
As a note, all new methods that can be accessed on behalf of a user (i.e. with a session token or access token) are organized under /oauth2/audit
. All client actions (that require client credentials) are organized under /oauth2/token
.
Viewing applications that have OAuth access to a user’s account
Endpoint: GET /oauth2/audit/grantedClients
Request body: none
Return body: PaginatedList<OAuthClientAuthorization>
Returns a paginated list of the clients and permissions that the user has granted. Allows a user to audit which parties have access to their resources.
Viewing tokens for an application that has OAuth access to a user’s account
Endpoint: GET /oauth2/audit/grantedClients/:client_id/tokens
Path Parameter: client_id
: returned tokens will be associated with this OAuth2 client
Request body: none
Return body: PaginatedList<OAuthRefreshTokenInformation>
Returns a paginated list of the clients and permissions that the user has granted. Allows a user to audit which parties have access to their resources.
User revocation of a client’s access
Endpoint: POST /oauth2/audit/grantedClients/:client_id/revoke
Path Parameter: client_id
: the OAuth2 client that will no longer have access to the user’s resources and/or identity
Response: On successful revocation, return HTTP 200. No body.
Upon calling this method, the refresh token and access tokens held by the specified client for the authenticated user making the API call will be revoked.
Update metadata for a token
Endpoint: PUT /oauth2/audit/tokens/:token_id/metadata
Request Parameters:
client_id
: the OAuth2 client that is associated with the tokentoken_id
: the token to update
Request Body: OAuthRefreshTokenInformation
Response: On successful update, return HTTP 200. No body
Upon calling this method, the token identifier will be updated
In practice, only the token name can be updated.
User revocation of a particular token
Endpoint: POST /oauth2/audit/tokens/:token_id/revoke
Request Parameters:
client_id
: the OAuth2 client that is associated with the token to revoketoken_id
: the token to revoke
Response: On successful revocation, return HTTP 200. No body.
Upon calling this method, the refresh token and access tokens held by the specified client for the authenticated user making the API call will be revoked.
Client revocation of a token
Endpoint: POST /oauth2/revoke
Request Body: OAuthTokenRevocationRequest
Response: By RFC 7009 § 2.2, on successful revocation, HTTP 200. No body.
Upon calling this method, the refresh/access token and associated tokens held by this client and associated with the user are revoked. Note: a specific path for this endpoint is not named by OAuth 2.0/OIDC specifications.
Retrieval of token metadata
Endpoint (users): GET /oauth2/audit/tokens/:token_id/metadata
Endpoint (clients): GET /oauth2/token/:token_id/metadata
Request Parameter: token_id
- the ID of the token to gather metadata about
Response: OAuthRefreshTokenInformation
The client can call this endpoint to get token metadata name. This metadata can be displayed to the user so that they may more easily identify the token in use when auditing/revoking tokens.
Additional grant types to issue tokens
Endpoint: POST /oauth2/token
This method exists. This feature proposal would add support for grant_type=refresh_token
, and return a refresh token for grant_type=code
. For details, see OIDC Core 1.0 § 12.1, 12.2.
Public vs. Confidential Clients
We will initially require that all of our clients are confidential. Public clients (where credentials are not secrets, e.g. a native application or single page app), are permitted by the OAuth specification, but require additional security consideration that we do not support at this time.
FAQ/Anticipated Concerns
Does adding refresh tokens break any existing behavior?
It should not because we are merely extending the access token with a reference to its refresh token ID. Current clients would not see the refresh token without requesting the offline_access
scope, and if they did receive it, they may ignore it. The duration of access tokens is unchanged.
PKCE - What does it protect against?
This design document has been revised to only support confidential OAuth clients at this time. The threat mitigated by PKCE only applies to certain types of public clients, so it . The duration of access tokens is unchanged.
...
is not necessary for this feature. We should consider adding it when we support public/native OAuth clients.
Expand | ||
---|---|---|
| ||
PKCE is an additional safeguard that specifically applies to native applications (e.g. a command line app) using the authorization code flow (i.e. the user authenticates in a browser, and is redirected back to the native app with an authorization code). The threat in this situation is that when the user is redirected back to the app through a custom URI or to a temporary local webserver, a malicious app may be the recipient of the redirect, rather than the intended client. The malicious app now has access to the authorization code. Because the client credentials are not confidential (due to the intended application being a native app), the authorization code gives the malicious app access to the user’s account. The solution is PKCE:
If the authorization code is hijacked, the malicious app cannot use it because it does not know the |
...
additional secret. |
Open Questions
Should we implement PKCE?
Choice of a refresh token? Proposed: 256 bit random string using SecureRandom
...
Google limits this to 50 and expires the least recently used token when a new token is issued
Implications
Simplifying an interface where a user is trying to audit/revoke tokens
Limits number of jobs that can be submitted to a workflow queue
Should a user be able to see scope associated with a specific client?
Scope is associated with refresh tokens
It may be helpful to see the union of all granted scopes to a client when auditing
- The change would be adding “scope” field to the proposed OAuthClientAuthorization object