Interface AccessToken
-
public interface AccessTokenAn 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
AccessTokenfrom 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
createmethods should be used. These methods are designed to handle tokens of any opaque format that an authorization server may issue.The
createJsonWebTokenfactory 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 thecreatefactory methods are usually a safer choice.Usage of
createmethods that accept an expiration time should be preferred overcreate(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 anAccessToken. 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 aSQLExceptionwith the ORA-25708 error code. Applications with long-running sessions should use theexpiration()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
Supplierthat caches an instance ofAccessTokenuntil 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,
createCacheshould be used instead ofcreateJsonWebTokenCache, unless an application wants to strictly enforce the use of JWT-encoded tokens.The caching
Suppliercreated by these factory methods can be used to configure a PoolDataSource from UCP . TheSuppliercan also be passed toOracleCommonDataSource.setTokenSupplier(java.util.function.Supplier), and a connection pool like Hikari can use thatOracleDataSourcewhen creating JDBC connections.The code example below creates a cache of access tokens which are requested using the Nimbus OAuth 2.0 SDK. A
PoolDataSourceis 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, anAccessTokenProvidermay 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
All Methods Static Methods Instance Methods Abstract Methods Modifier and Type Method Description static AccessTokencreate(java.lang.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(java.lang.CharSequence accessToken, java.time.Duration expiresIn)Creates anAccessTokenfrom text that Oracle JDBC treats as opaque.static AccessTokencreate(java.lang.CharSequence accessToken, java.time.OffsetDateTime expiresAt)Creates anAccessTokenfrom text that Oracle JDBC treats as opaque.static java.util.function.Supplier<? extends AccessToken>createCache(java.util.function.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, java.security.PrivateKey privateKey)Creates anAccessTokenrepresenting a JSON Web Token (JWT) that requires proof of possession (PoP) of aprivateKey.static java.util.function.Supplier<? extends AccessToken>createJsonWebTokenCache(java.util.function.Supplier<? extends AccessToken> tokenSupplier)Returns aSupplierthat caches access tokens generated by atokenSupplier.java.time.OffsetDateTimeexpiration()Returns the expiration time of this access token, orOffsetDateTime.MAXif the expiration time is unknown.java.util.Optional<java.security.PrivateKey>privateKey()Returns anOptionalcontaining a private key required for proof of possession (PoP), or an emptyOptionalif this access token does not require PoP.char[]toCharArray()Returns a char arrary containing the string representation of this access token.
-
-
-
Method Detail
-
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
java.time.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
java.util.Optional<java.security.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
static AccessToken createJsonWebToken(char[] token, java.security.PrivateKey privateKey)
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:
java.lang.NullPointerException- If thetokenorprivateKeyarenulljava.lang.IllegalArgumentException- If thetokentext is malformed or theprivateKeyuses an encoding that cannot be decoded.java.lang.IllegalStateException- If security providers required to decode theprivateKeyare not installed.
-
createJsonWebToken
static AccessToken createJsonWebToken(char[] token)
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:
java.lang.NullPointerException- If thetokenisnulljava.lang.IllegalArgumentException- If thetokenhas an unrecognized encoding.
-
create
static AccessToken create(java.lang.CharSequence accessToken, java.time.Duration expiresIn)
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:
java.lang.NullPointerException- IfaccessTokenorexpiresInisnull.
-
create
static AccessToken create(java.lang.CharSequence accessToken, java.time.OffsetDateTime expiresAt)
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:
java.lang.NullPointerException- IfaccessTokenorexpiresAtisnull.
-
create
static AccessToken create(java.lang.CharSequence accessToken)
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:
java.lang.NullPointerException- IfaccessTokenisnull.
-
createJsonWebTokenCache
static java.util.function.Supplier<? extends AccessToken> createJsonWebTokenCache(java.util.function.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:
java.lang.NullPointerException- IftokenSupplierisnull.
-
createCache
static java.util.function.Supplier<? extends AccessToken> createCache(java.util.function.Supplier<? extends AccessToken> tokenSupplier)
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:
java.lang.NullPointerException- IftokenSupplierisnull.
-
-