Token Validation
Why do we validate tokens? When your web application checks credentials directly, it verifies that the username and password that are presented correspond to what you maintain. When using claims-based identity, you're outsourcing that job to an identity provider.
The responsibility shifts from verifying raw credentials to verifying that the requestor went through your preferred identity provider and successfully authenticated. The identity provider represents successful authentication by issuing a token. Before you can use the information or rely on it as an assertion that the user has authenticated, you must validate it.
OpenID Discovery Document
The OpenID Connect 1.0 protocol is a simple identity layer on top of the OAuth 2.0 protocol that requires the use of multiple endpoints for authenticating users and for requesting resources that include user information, tokens, and public keys. To help with discovering what these endpoints are that you need to use, OpenID Connect allows you to use a discovery document, which is a JSON document found at a well-known location. This discovery document contains key/value pairs that provide details about the OpenID Connect provider's configuration, including the URIs of the authorization, token, userinfo, and public keys endpoints. You can retrieve the discovery document for an IAM identity domain's OpenID Connect service from: https://<domainURL>/.well-known/openid-configuration.
See the Oracle Identity Cloud Service OpenID Discovery docs.
Validating Identity Tokens
An Identity (ID) Token is an integrity-secured, self-contained token (in JSON Web Token format) that contains claims about the end user. It represents an authenticated user's session. Therefore, the token must be validated before an application can trust the contents of the ID Token. For example, if a malicious attacker replayed a user's ID Token that they had captured earlier, the application should detect that the token has been replayed or was used after it had expired and deny the authentication.
-
Verify that the value of the audience (
aud
) claim contains the application'sclient_id
value. Theaud
(audience) claim may contain an array with more than one element. The ID Token must be rejected if the ID token doesn't list the client as a valid audience, or if it contains additional audiences that aren't trusted by the client. -
Verify that the current time is before the time represented by the expiry time (
exp
) claim. -
Verify that the ID Token is properly signed by the issuer. IAM identity domain-issued tokens are signed using one of the certificates found at the URI specified in the
jwks_uri
field of the discovery document.-
Retrieve the tenant's public certificate from the
SigningCert/jwk
endpoint (for example,https://acme.identity.oraclecloud.com/admin/v1/SigningCert/jwk
).Note
Because identity domains change public keys infrequently, you can cache the public keys and, in the vast majority of cases, efficiently perform local validation. This requires retrieving and parsing certificates and making the appropriate crypto calls to check the signature: -
Use any JWT libraries available to validate, for example, Connect2id's Nimbus JWT Library for Java. See JWT for a list of available libraries.
Note
In case of signature validation failure, to prevent constant re-fetches in case of attacks with bogus tokens, the re-fetching/re-caching of the public key should be based on a time interval, such as 60 minutes, so that re-fetches only happen every 60 minutes.
Example
package sample; import java.net.MalformedURLException; import java.net.URL; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.jwk.source.RemoteJWKSet; import com.nimbusds.jose.proc.JWSKeySelector; import com.nimbusds.jose.proc.JWSVerificationKeySelector; import com.nimbusds.jose.proc.SecurityContext; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; import com.nimbusds.jwt.proc.DefaultJWTProcessor; public class TokenValidation { public static void main(String[] args) { try { String tokenValue = "eyJ4NXQjUzI1....W9J4oQ"; ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor(); // change t JWKSource keySource = new RemoteJWKSet(new URL("https://<domainURL>/admin/v1/SigningCert/jwk")); // The expected JWS algorithm of the token (agreed out-of-band) JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256; // Configure the JWT processor with a key selector to feed matching public // RSA keys sourced from the JWK set URL JWSKeySelector keySelector = new JWSVerificationKeySelector(expectedJWSAlg, keySource); jwtProcessor.setJWSKeySelector(keySelector); // Process the token SecurityContext ctx = null; // optional context parameter, not required here JWTClaimsSet claimsSet = jwtProcessor.process(tokenValue, ctx); // Print out the token claims set System.out.println(claimsSet.toJSONObject()); } catch (Exception e) { e.printStackTrace(); } } }
-
-
Verify that the value of the Issuer Identifier (
iss
) claim exactly matches the value of theiss
(issuer) claim:https://<domainURL>/
Validating Access Tokens
-
Verify that the access token is properly signed by the issuer.
-
Retrieve the tenant's public certificate from the
SigningCert/jwk
endpoint (for example, https://acme.identity.oraclecloud.com/admin/v1/SigningCert/jwk).Note
Because identity domains change public keys infrequently, you can cache the public keys and, in the vast majority of cases, efficiently perform local validation. This requires retrieving and parsing certificates and making the appropriate crypto calls to check the signature: -
Use any JWT libraries available to validate, for example, Connect2id's Nimbus JWT Library for Java. See JWT for a list of available libraries.
-
Pass the certificate to the respective library's API, for example, using Nimbus SignedJWT API:
PublicKey = x509Certificate.getPublicKey(); // verify the signature. JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) (publicKey)); boolean isTokenValid = signedJWT.verify(verifier);
Note
In case of signature validation failure, to prevent constant re-fetches in case of attacks with bogus tokens, the re-fetching/re-caching of the public key should be based on a time interval, such as 60 minutes, so that re-fetches only happen every 60 minutes.
-
-
Verify that the value of the Issuer Identifier (
iss
) claim exactly matches the value of theiss
(issuer) claim:https://<domainURL>/
-
Verify that the access token has the audience (
aud
) claim as requested by the client. The value of theaud
claim changes from scope to scope. Theaud
claim is an array if there are multiple audiences and is a string if there's only one audience.The
aud
claim is the primary audience of the IAM identity domain App's resource server. If there are any secondary audiences defined in the IAM identity domain App, then they're also added as part of theaud
claim. As part of the access token validation, the server must allow access if one of the values in theaud
array makes sense to the resource server. -
Verify that the current time is before the time represented by the expiry time (
exp
) claim. -
Verify that the access token is authorized to perform the operation based on the contents of the scope claim. The scope claim in the access token is a space-separated list of strings.