public 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.
Factory methods declared by this interface create instances of
AccessToken from different inputs:
create(CharSequence, Duration)access_token and expires_in
parameters issued by an
OAuth 2.0 authorization server
.
create(CharSequence, OffsetDateTime)access_token issued by an authorization server,
but it accepts the expiration time as an absolute value, instead of the
relative expires_in value.
createJsonWebToken(char[])createJsonWebToken(char[], PrivateKey)create(CharSequence)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.
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.
Factory methods declared by this interface can create a
Supplier that caches an instance of AccessToken until it is
about to expire.
createCache(Supplier) method can be used to cache any
AccessToken created by the static factory methods of this
interface.
createJsonWebTokenCache(Supplier) method will only cache
an AccessToken created by one of the createJsonWebToken
factory 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 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.
| Modifier and Type | Method and Description |
|---|---|
static AccessToken |
create(java.lang.CharSequence accessToken)
Creates an
AccessToken from text that Oracle JDBC attempts to parse
as a JSON Web Token (JWT), but treats as opaque if the format is not
recognized. |
static AccessToken |
create(java.lang.CharSequence accessToken,
java.time.Duration expiresIn)
Creates an
AccessToken from text that Oracle JDBC treats
as opaque. |
static AccessToken |
create(java.lang.CharSequence accessToken,
java.time.OffsetDateTime expiresAt)
Creates an
AccessToken from text that Oracle JDBC treats
as opaque. |
static java.util.function.Supplier<? extends AccessToken> |
createCache(java.util.function.Supplier<? extends AccessToken> tokenSupplier)
Returns a
Supplier that functions as a cache for access tokens
generated by a given tokenSupplier function. |
static AccessToken |
createJsonWebToken(char[] token)
Creates an
AccessToken representing a JSON Web Token (JWT). |
static AccessToken |
createJsonWebToken(char[] token,
java.security.PrivateKey privateKey)
Creates an
AccessToken representing a JSON Web Token (JWT)
that requires proof of possession (PoP) of a privateKey. |
static java.util.function.Supplier<? extends AccessToken> |
createJsonWebTokenCache(java.util.function.Supplier<? extends AccessToken> tokenSupplier)
Returns a
Supplier that caches access tokens generated
by a tokenSupplier. |
java.time.OffsetDateTime |
expiration()
Returns the expiration time of this access token, or
OffsetDateTime.MAX if the expiration time is unknown. |
java.util.Optional<java.security.PrivateKey> |
privateKey()
Returns an
Optional containing a private key required for proof of
possession (PoP), or an empty Optional if this access token does
not require PoP. |
char[] |
toCharArray()
Returns a char arrary containing the string representation of this
access token.
|
char[] toCharArray()
AccessToken.java.time.OffsetDateTime expiration()
Returns the expiration time of this access token, or
OffsetDateTime.MAX if 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.
java.util.Optional<java.security.PrivateKey> privateKey()
Optional containing a private key required for proof of
possession (PoP), or an empty Optional if this access token does
not require PoP.static AccessToken createJsonWebToken(char[] token, java.security.PrivateKey privateKey)
Creates an AccessToken representing a JSON Web Token (JWT)
that requires proof of possession (PoP) of a privateKey. Proof of
possession is specified by
RFC 7800.
The token argument 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 AccessToken retains copies of the token and
privateKey provided to this method. After this method returns,
the original token and privateKey may be mutated or
destroyed by the caller.
token - JWT encoded token. Not null.privateKey - Private key for which the token requires
proof of possession. Not null.AccessToken representing a JWT that requires proof
of possession of a private key. Not null.java.lang.NullPointerException - If the token or privateKey
are nulljava.lang.IllegalArgumentException - If the token text is malformed or
the privateKey uses an encoding that cannot be decoded.java.lang.IllegalStateException - If security providers required to decode the
privateKey are not installed.static AccessToken createJsonWebToken(char[] token)
Creates an AccessToken representing a JSON Web Token (JWT).
The token argument 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 AccessToken retains a copy of the token
provided to this method. After this method returns, the original
token may be mutated or destroyed by the caller.
token - JWT encoded token. Not null.AccessToken representing a JWT. Not null.java.lang.NullPointerException - If the token is nulljava.lang.IllegalArgumentException - If the token has an unrecognized
encoding.static AccessToken create(java.lang.CharSequence accessToken, java.time.Duration expiresIn)
Creates an AccessToken from text that Oracle JDBC treats
as opaque. Unlike the createJsonWebToken methods, 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 AccessToken retains a copy of the accessToken
provided to this method. After this method returns, the original
accessToken may be mutated or destroyed by the caller. For
example, the accessToken could be passed to this method as a
CharBuffer which is then cleared after this method returns.
accessToken - Token text. Not null.expiresIn - Duration after current time when the token expires.
Not null. Not negative or zero.AccessToken. Not null.java.lang.NullPointerException - If accessToken or expiresIn
is null.static AccessToken create(java.lang.CharSequence accessToken, java.time.OffsetDateTime expiresAt)
Creates an AccessToken from text that Oracle JDBC treats
as opaque. Unlike the createJsonWebToken methods, 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 expiresAt parameter.
The returned AccessToken retains a copy of the accessToken
provided to this method. After this method returns, the original
accessToken may be mutated or destroyed by the caller. For
example, the accessToken could be passed to this method as a
CharBuffer which is then cleared after this method returns.
accessToken - Token text. Not null.expiresAt - The time when the token expires. Not null.AccessToken. Not null.java.lang.NullPointerException - If accessToken or expiresAt
is null.static AccessToken create(java.lang.CharSequence accessToken)
Creates an AccessToken from 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 exp claim, the expiration() method will return
OffsetDateTime.MAX to signify an unknown expiration time.
The returned AccessToken retains a copy of the accessToken
provided to this method. After this method returns, the original
accessToken may be mutated or destroyed by the caller. For
example, the accessToken could be passed to this method as a
CharBuffer which is then cleared after this method returns.
accessToken - Token text. Not null.AccessToken representation of the provided text. Not
null.java.lang.NullPointerException - If accessToken is null.static java.util.function.Supplier<? extends AccessToken> createJsonWebTokenCache(java.util.function.Supplier<? extends AccessToken> tokenSupplier)
Returns a Supplier that caches access tokens generated
by a tokenSupplier.
The caching Supplier returned by this method throws
IllegalArgumentException if the tokenSupplier returns an
AccessToken not recognized as one created by
createJsonWebToken(char[]) or
createJsonWebToken(char[], PrivateKey)
The caching Supplier returned by this method is otherwise identical
in behavior to one returned by createCache(Supplier).
tokenSupplier - Supplier of AccessTokens. Not null. Retained.java.lang.NullPointerException - If tokenSupplier is null.static java.util.function.Supplier<? extends AccessToken> createCache(java.util.function.Supplier<? extends AccessToken> tokenSupplier)
Returns a Supplier that functions as a cache for access tokens
generated by a given tokenSupplier function.
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 invoking
Supplier.get() on the tokenSupplier.
The cache is initially empty. The get method of the
tokenSupplier is not invoked until a token is requested from the
cache by calling the get method of the caching Supplier
returned by this method.
It is not required for the tokenSupplier to have a thread-safe
implementation. The cache will not perform concurrent invocations of
tokenSupplier.get().
If the tokenSupplier throws an unchecked exception, the cache will
throw a CompletionException with that
unchecked exception as the initial cause.
If the tokenSupplier outputs a null value, the cache will
throw a CompletionException with a
NullPointerException as the initCause().
If the tokenSupplier outputs an AccessToken that was
not created by a static factory method of the AccessToken
interface, the cache will throw a
CompletionException with an
IllegalArgumentException as the initCause().
tokenSupplier - Supplier of AccessTokens. Not null. Retained.java.lang.NullPointerException - If tokenSupplier is null.