This guide describes OAuth2 token persistence and the possible approaches you can follow for token persistence in a production environment. The OAuth2 component in WSO2 Identity Server has two implementations that can be used to handle token persistence in the database (synchronous and asynchronous token persistence).
For more information about the properties related to persistence, see Authentication Session Persistence.
The following sections guide you through the difference between these two approaches and how to configure them.
Synchronous token persistence
The flow of synchronous token persistence is as follows:
- The client sends an access token request.
The OAuth2 component in WSO2 IS checks for an existing active access token for the given client/user/scope. It first checks the cache and if an active token is not found, it then checks the database.
- If an active access token is found, the token is returned to the client.
- Alternatively, if an existing access token is not found, the OAuth2 component creates a new access token and persists it in the database using the same thread. Once it is persisted, the new token is returned to the client.
Enabling synchronous token persistence
To enable synchronous token persistence, open the <IS_HOME>/repository/conf/identity/identity.xml
file and do the following changes under 'configs related to OAuth2 token persistence':
<TokenPersistence> <Enable>true</Enable> <PoolSize>100</PoolSize> <RetryCount>5</RetryCount> </TokenPersistence>
Asynchronous token persistence
The flow of asynchronous token persistence is as follows:
- The client sends an access token request.
The OAuth2 component in WSO2 IS checks for an existing active access token for the given client/user/scope. It first checks the cache and if an active token is not found, it then checks the database.
- If an active access token is found, the token is returned to the client.
- Alternatively, if an existing access token is not found, the OAuth2 component creates a new access token and adds it to a persisting queue.
- Once the token is added to the queue, the token is returned to the client.
- There are background threads that consume the queue, and persist the tokens in the queue to the database.
Enabling asynchronous token persistence
To enable asynchronous token persistence, open the <IS_HOME>/repository/conf/identity/identity.xml
file and do the following changes under 'configs related to OAuth2 token persistence':
<TokenPersistence> <Enable>true</Enable> <PoolSize>100</PoolSize> <RetryCount>5</RetryCount> </TokenPersistence>
The following table describes what each of the above attributes means:
Property | Description | Sample value |
---|---|---|
Enable | To enable token persistence | true |
PoolSize | The value here determines the number of threads in the thread pool that are used to consume the token persisting queue. Having PoolSize 0 means Synchronous and greater than 0 is Asynchronous. | 100 |
RetryCount | This indicates how many times to retry when storing the access token in an event of a con_app_key violation. | 5 |
The main difference between synchronous and asynchronous token persistence is that the OAuth2 component in the synchronous token persistence implementation waits for the access token to be persisted in the database before returning it to the client.
Recovery flow for token persistence
This section explains the recovery flow triggered in WSO2 Identity Server for exceptional cases that may occur in a production environment caused by the client application mishandling the CON_APP_KEY
constraint that is explained below.
CONN_APP_KEY constraint
For a given set of consumer key, user, and scope values, there can be only one ACTIVE access token. The CON_APP_KEY
constraint in the IDN_OAUTH2_ACCESS_TOKEN
table enforces this by allowing only one active access token for a given set of consumer key, user, and scope values. This constraint may be violated in a scenario where two or more identical token requests come from the same application.
The above scenario is unlikely because in practice, an application is usually designed to handle this situation using scopes, or in the case of a multithreaded client, there is usually a separate thread to acquire access tokens so that other threads can retrieve from it.
Asynchronous token persistence
The flow
For instance, if the violation mentioned above occurs with two nodes of a cluster receiving identical access token requests, the flow of the asynchronous token persistence would be as follows:
- The client sends an access token request.
The OAuth2 component in both nodes of WSO2 IS checks for an existing active access token for the given client/user/scope. Both nodes first check the cache and if an active token is not found, the database is checked.
- If an active access token is found, the token is returned to the client.
- Alternatively, if an existing access token is not found, the OAuth2 component in both nodes creates a new access token and adds it to the persisting queue.
- After adding it to the queue, the access token is returned to the client.
- However, the background threads that consume the persisting queue in both servers (nodes) attempt to persist the token to the database. One of the servers will succeed and successfully persist the access token to the database, and the other server will receive an error due to the violation of the
CON_APP_KEY
constraint. The violation is due to the fact that the same access token was already persisted by the first server in the cluster and is currently active.
The recovery flow
To handle this situation, WSO2 Identity Server has a recovery flow for token persistence that does the following:
- Since both access tokens were returned to the client, there must be a database entry for both tokens.
- Since the access token that the second node is attempting to persist is not allowed due to the violation, the recovery flow takes the latest entry in the database, which is the active access token persisted by the first node, and mark it as INACTIVE.
- The access token received from the second node is now saved as an ACTIVE access token in the database. Therefore, one of the access tokens returned to the client is an INACTIVE token.
Tip: If the client application is not designed to handle the CONN_APP_KEY
constraint violation using scopes, you can avoid the situation described above and avoid any invalid tokens by using synchronous token persistence. To do this, set the <PoolSize>
property in the <IS_HOME>/repository/conf/identity/identity.xml
file to 0.
Synchronous token persistence
The flow
The flow of the synchronous token persistence when receiving two identical access token requests is as follows:
- The client sends an access token request.
The OAuth2 component in both nodes of WSO2 IS checks for an existing active access token for the given client/user/scope. Both nodes first check the cache and if an active token is not found, the database is checked.
- Alternatively, if an existing access token is not found, the OAuth2 component in both nodes creates a new access token and persists the access token to the database using the same thread.
- One of the nodes will persist the token successfully and return it to the client but the other node will receive an error due to the violation of the
CON_APP_KEY
constraint.
The recovery flow
The process flow now moves on to the recovery flow described above in order to handle the CON_APP_KEY
constraint violation and is executed as follows:
- Since the same thread is being used, the OAuth2 component in the second node checks the database again for an ACTIVE access token.
- Since there is now an ACTIVE token, which was persisted by the first node, the second node now returns the access token persisted by the first node to the client.
- Both access token requests receive the same access token.