Interface AccessToken
An access token generated by an authorization server. This interface is intended for integrating an OAuth 2.0 client with Oracle JDBC. It is not intended as a general-purpose solution for handling access tokens in Java applications.
Creating an AccessToken
Factory methods declared by this interface create instances of
AccessToken from different inputs:
create(CharSequence, Duration)-
Accepts the values of
access_tokenandexpires_inparameters issued by an OAuth 2.0 authorization server . create(CharSequence, OffsetDateTime)-
Also accepts an
access_tokenissued by an authorization server, but it accepts the expiration time as an absolute value, instead of the relativeexpires_invalue. createJsonWebToken(char[])- Accepts the text of a JSON Web Token (JWT) and extracts its "exp" claim to get an expiration time.
createJsonWebToken(char[], PrivateKey)- Accepts the text of a JWT that requires a private key for proof of possession (PoP) , and extracts its "exp" claim to get an expiration time.
create(CharSequence)- Accepts text which may or may not be a JWT. This method can result in an unknown expiration time for non-JWT encoded tokens.
In most cases, one of the first two create methods should be used.
These methods are designed to handle tokens of any opaque format that an
authorization server may issue.
The createJsonWebToken factory methods should be used only if
the issuer of the token is guaranteed the use of the JWT format,
and is not going to use a different format in the future. OAuth 2.0
authorization servers do not usually make such a guarantee, so the
create factory methods are usually a safer choice.
Usage of create methods that accept an expiration time should be
preferred over create(CharSequence). When an expiration time is
available, Oracle JDBC can detect if a token has expired and avoid sending it
to the database. This conserves database resources that would otherwise be
spent on rejecting an expired token.
Checking the Expiration Time
The expiration() method returns the expiration time of an
AccessToken. Oracle JDBC does not send expired tokens to the
database. If an attempt is made to send a token after the expiration
time, Oracle JDBC will throw a SQLException with the ORA-25708 error
code. Applications with long-running sessions should use the
expiration() method to check and refresh an expired token before
Oracle JDBC sends it to the database. Alternatively, an application might
create a cache as described in the next section. The cache will
automatically replace an expired token with a new one.
Caching Access Tokens
Factory methods declared by this interface can create a
Supplier that caches an instance of AccessToken until it is
about to expire.
-
The
createCache(Supplier)method can be used to cache anyAccessTokencreated by the static factory methods of this interface. -
The
createJsonWebTokenCache(Supplier)method will only cache anAccessTokencreated by one of thecreateJsonWebTokenfactory methods.
In most cases, createCache should be used instead of
createJsonWebTokenCache, unless an application wants to strictly
enforce the use of JWT-encoded tokens.
The caching Supplier created by these factory methods can be used
to configure a
PoolDataSource from UCP
. The Supplier can also be passed to
OracleCommonDataSource.setTokenSupplier(java.util.function.Supplier),
and a connection pool like Hikari can use that OracleDataSource when
creating JDBC connections.
The code example below creates a cache of access tokens which are
requested using the Nimbus OAuth 2.0 SDK. A PoolDataSource is then
configured to use this cache.
void example(PoolDataSource poolDataSource) throws SQLException {
Supplier<? extends AccessToken> cachedTokenSupplier = AccessToken.createCache(() -> {
final TokenResponse response;
try {
TokenRequest tokenRequest = new TokenRequest(
new URI(System.getenv("OAUTH_TOKEN_ENDPOINT")),
new ClientSecretBasic(
new ClientID(System.getenv("OAUTH_CLIENT_ID")),
new Secret(System.getenv("OAUTH_CLIENT_SECRET"))),
new ClientCredentialsGrant(),
new Scope(System.getenv("OAUTH_SCOPE")));
HTTPResponse httpResponse = tokenRequest.toHTTPRequest().send();
response = TokenResponse.parse(httpResponse);
}
catch (Exception requestFailed) {
throw new RuntimeException(requestFailed);
}
if (!response.indicatesSuccess()) {
throw new RuntimeException(
response.toErrorResponse()
.getErrorObject()
.toJSONObject()
.toString());
}
com.nimbusds.oauth2.sdk.token.AccessToken accessToken =
response.toSuccessResponse()
.getTokens()
.getAccessToken();
return AccessToken.create(
accessToken.getValue(),
Duration.ofSeconds(accessToken.getLifetime()));
});
poolDataSource.setTokenSupplier(cachedTokenSupplier);
}
The cache is designed to execute the token request only when necessary. After requesting a token one time, it will reuse that same token until it expires. To support connection pools that open JDBC connections in parallel, the cache issues only one token request at a time and makes other threads wait for that request to complete. Once the request finishes, every waiting thread will use the same token to establish its JDBC connection.
Shortly before a cached token will expire, the cache eagerly requests a replacement on a background thread. This usually results in a new token becoming available before the current one expires, which means application threads are unlikely to block on token retrieval.
If the cache notices that a previously requested token was never consumed, then it will stop executing these eager requests. This avoids unnecessary token requests during periods in which new JDBC connections are not being created.
Access Token Service Provider
Access tokens that authorize logins to Oracle Database may be provided to
Oracle JDBC by an AccessTokenProvider. This is a service provider
interface (SPI) which allows an existing application to begin using access
tokens with Oracle JDBC without having to add new code as shown in the
previous section. Instead, an AccessTokenProvider may be
installed on the class-path or module-path of a Java application, and Oracle
JDBC can be configured to use it through a
connection properties file
or any other means of configuring a JDBC datasource that an application
supports.
Programmers may create their own
AccessTokenProvider, or use one of the open source
implementations available from the
ojdbc-extensions project.
- Since:
- 23
-
Method Summary
Modifier and TypeMethodDescriptionstatic AccessTokencreate(CharSequence accessToken) Creates anAccessTokenfrom text that Oracle JDBC attempts to parse as a JSON Web Token (JWT), but treats as opaque if the format is not recognized.static AccessTokencreate(CharSequence accessToken, Duration expiresIn) Creates anAccessTokenfrom text that Oracle JDBC treats as opaque.static AccessTokencreate(CharSequence accessToken, OffsetDateTime expiresAt) Creates anAccessTokenfrom text that Oracle JDBC treats as opaque.static Supplier<? extends AccessToken>createCache(Supplier<? extends AccessToken> tokenSupplier) Returns aSupplierthat functions as a cache for access tokens generated by a giventokenSupplierfunction.static AccessTokencreateJsonWebToken(char[] token) Creates anAccessTokenrepresenting a JSON Web Token (JWT).static AccessTokencreateJsonWebToken(char[] token, PrivateKey privateKey) Creates anAccessTokenrepresenting a JSON Web Token (JWT) that requires proof of possession (PoP) of aprivateKey.static Supplier<? extends AccessToken>createJsonWebTokenCache(Supplier<? extends AccessToken> tokenSupplier) Returns aSupplierthat caches access tokens generated by atokenSupplier.Returns the expiration time of this access token, orOffsetDateTime.MAXif the expiration time is unknown.Returns anOptionalcontaining a private key required for proof of possession (PoP), or an emptyOptionalif this access token does not require PoP.char[]Returns a char arrary containing the string representation of this access token.
-
Method Details
-
toCharArray
char[] toCharArray()Returns a char arrary containing the string representation of this access token. Mutating the contents of the char array will have no effect on thisAccessToken.- Returns:
- The text representation of this access token. Not null. Not retained.
-
expiration
OffsetDateTime expiration()Returns the expiration time of this access token, or
OffsetDateTime.MAXif the expiration time is unknown. This method can be used to check if an access token needs to be refreshed before Oracle JDBC sends it to the database.- Returns:
- The expiration time of this access token. Not null.
-
privateKey
Optional<PrivateKey> privateKey()Returns anOptionalcontaining a private key required for proof of possession (PoP), or an emptyOptionalif this access token does not require PoP.- Returns:
- Optional containing a private key for PoP, or an empty Optional if PoP is not required. Not null.
-
createJsonWebToken
Creates an
AccessTokenrepresenting a JSON Web Token (JWT) that requires proof of possession (PoP) of aprivateKey. Proof of possession is specified by RFC 7800.The
tokenargument to this method must be provided as a string of characters representing a JSON Web Token (JWT) as specified by RFC 7519. This method uses the "exp" claim of the JWT as the expiration time for the token.The returned
AccessTokenretains copies of thetokenandprivateKeyprovided to this method. After this method returns, the originaltokenandprivateKeymay be mutated or destroyed by the caller.- Parameters:
token- JWT encoded token. Notnull.privateKey- Private key for which thetokenrequires proof of possession. Notnull.- Returns:
- An
AccessTokenrepresenting a JWT that requires proof of possession of a private key. Not null. - Throws:
NullPointerException- If thetokenorprivateKeyarenullIllegalArgumentException- If thetokentext is malformed or theprivateKeyuses an encoding that cannot be decoded.IllegalStateException- If security providers required to decode theprivateKeyare not installed.
-
createJsonWebToken
Creates an
AccessTokenrepresenting a JSON Web Token (JWT).The
tokenargument to this method must be provided as a string of characters representing a JSON Web Token (JWT) as specified by RFC 7519. This method uses the "exp" claim of the JWT as the expiration time for the token.The returned
AccessTokenretains a copy of thetokenprovided to this method. After this method returns, the originaltokenmay be mutated or destroyed by the caller.- Parameters:
token- JWT encoded token. Notnull.- Returns:
- An
AccessTokenrepresenting a JWT. Not null. - Throws:
NullPointerException- If thetokenisnullIllegalArgumentException- If thetokenhas an unrecognized encoding.
-
create
Creates an
AccessTokenfrom text that Oracle JDBC treats as opaque. Unlike thecreateJsonWebTokenmethods, this method will not attempt to parse the text as a JSON Web Token (JWT).This method computes the expiration time for the token as
OffsetDateTime.now(UTC).plus(expiresIn). In order for this computation to be correct, this method must be called immediately after receiving a token from an authorization server.The returned
AccessTokenretains a copy of theaccessTokenprovided to this method. After this method returns, the originalaccessTokenmay be mutated or destroyed by the caller. For example, theaccessTokencould be passed to this method as aCharBufferwhich is then cleared after this method returns.- Parameters:
accessToken- Token text. Notnull.expiresIn- Duration after current time when the token expires. Notnull. Not negative or zero.- Returns:
- An opaque
AccessToken. Not null. - Throws:
NullPointerException- IfaccessTokenorexpiresInisnull.
-
create
Creates an
AccessTokenfrom text that Oracle JDBC treats as opaque. Unlike thecreateJsonWebTokenmethods, this method will not attempt to parse the text as a JSON Web Token (JWT).The expiration time for the token is given by the
expiresAtparameter.The returned
AccessTokenretains a copy of theaccessTokenprovided to this method. After this method returns, the originalaccessTokenmay be mutated or destroyed by the caller. For example, theaccessTokencould be passed to this method as aCharBufferwhich is then cleared after this method returns.- Parameters:
accessToken- Token text. Notnull.expiresAt- The time when the token expires. Notnull.- Returns:
- An opaque
AccessToken. Not null. - Throws:
NullPointerException- IfaccessTokenorexpiresAtisnull.
-
create
Creates an
AccessTokenfrom text that Oracle JDBC attempts to parse as a JSON Web Token (JWT), but treats as opaque if the format is not recognized.If a JWT format is recognized, this method uses the "exp" claim as the expiration time for the token. Otherwise, if the text is not recognized as a JWT, or it is a JWT without an
expclaim, theexpiration()method will returnOffsetDateTime.MAXto signify an unknown expiration time.The returned
AccessTokenretains a copy of theaccessTokenprovided to this method. After this method returns, the originalaccessTokenmay be mutated or destroyed by the caller. For example, theaccessTokencould be passed to this method as aCharBufferwhich is then cleared after this method returns.- Parameters:
accessToken- Token text. Notnull.- Returns:
- An
AccessTokenrepresentation of the provided text. Not null. - Throws:
NullPointerException- IfaccessTokenisnull.
-
createJsonWebTokenCache
static Supplier<? extends AccessToken> createJsonWebTokenCache(Supplier<? extends AccessToken> tokenSupplier) Returns a
Supplierthat caches access tokens generated by atokenSupplier.The caching
Supplierreturned by this method throwsIllegalArgumentExceptionif thetokenSupplierreturns anAccessTokennot recognized as one created bycreateJsonWebToken(char[])orcreateJsonWebToken(char[], PrivateKey)The caching
Supplierreturned by this method is otherwise identical in behavior to one returned bycreateCache(Supplier).- Parameters:
tokenSupplier- Supplier ofAccessTokens. Not null. Retained.- Returns:
- A caching token supplier. Not null.
- Throws:
NullPointerException- IftokenSupplierisnull.
-
createCache
Returns a
Supplierthat functions as a cache for access tokens generated by a giventokenSupplierfunction.The cache retains a single
AccessToken, and it will continue to output that token until it is about to expire. When the cached token is about to expire, a new token is requested by invokingSupplier.get()on thetokenSupplier.The cache is initially empty. The
getmethod of thetokenSupplieris not invoked until a token is requested from the cache by calling thegetmethod of the cachingSupplierreturned by this method.It is not required for the
tokenSupplierto have a thread-safe implementation. The cache will not perform concurrent invocations oftokenSupplier.get().If the
tokenSupplierthrows an unchecked exception, the cache will throw aCompletionExceptionwith that unchecked exception as the initial cause.If the
tokenSupplieroutputs a null value, the cache will throw aCompletionExceptionwith aNullPointerExceptionas theinitCause().If the
tokenSupplieroutputs anAccessTokenthat was not created by a static factory method of theAccessTokeninterface, the cache will throw aCompletionExceptionwith anIllegalArgumentExceptionas theinitCause().- Parameters:
tokenSupplier- Supplier ofAccessTokens. Not null. Retained.- Returns:
- A caching token supplier. Not null.
- Throws:
NullPointerException- IftokenSupplierisnull.
-