class OktaIdToken {

    @RestrictTo(RestrictTo.Scope.LIBRARY)
    public void validate(TokenRequest request, Clock clock) throws AuthorizationException {
        final OIDCConfig config = request.getConfig();
        ProviderConfiguration providerConfig = request.getProviderConfiguration();

        if (!"RS256".equals(mHeader.alg)) {
            throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                    AuthorizationException.TokenValidationError
                            .createNotSupportedAlgorithmException(mHeader.alg));
        }
        if (providerConfig.issuer != null) {
            if (!mClaims.iss.equals(providerConfig.issuer)) {
                throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                        AuthorizationException.TokenValidationError.ISSUER_MISMATCH);
            }

            Uri issuerUri = Uri.parse(mClaims.iss);
            if (!issuerUri.getScheme().equals("https")) {
                throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                        AuthorizationException.TokenValidationError.ISSUER_NOT_HTTPS_URL);
            }

            if (TextUtils.isEmpty(issuerUri.getHost())) {
                throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                        AuthorizationException.TokenValidationError.ISSUER_HOST_EMPTY);
            }

            if (issuerUri.getFragment() != null || issuerUri.getQueryParameterNames().size() > 0) {
                throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                        AuthorizationException.TokenValidationError
                                .ISSUER_URL_CONTAIN_OTHER_COMPONENTS);
            }
        }

        String clientId = config.getClientId();
        if (!this.mClaims.aud.contains(clientId)) {
            throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                    AuthorizationException.TokenValidationError.AUDIENCE_MISMATCH);
        }

        long nowInSeconds = clock.getCurrentTimeMillis() / MILLIS_PER_SECOND;
        if (nowInSeconds > mClaims.exp) {
            throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                    AuthorizationException.TokenValidationError.ID_TOKEN_EXPIRED);
        }

        if (Math.abs(nowInSeconds - mClaims.iat) > TEN_MINUTES_IN_SECONDS) {
            throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                    AuthorizationException.TokenValidationError.createWrongTokenIssuedTime(
                            TEN_MINUTES_IN_SECONDS.intValue() / SECONDS_IN_ONE_MINUTE));
        }

        if (GrantTypes.AUTHORIZATION_CODE.equals(request.getGrantType())) {
            String expectedNonce = request.getNonce();
            if (!TextUtils.equals(mClaims.nonce, expectedNonce)) {
                throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                        AuthorizationException.TokenValidationError.NONCE_MISMATCH);
            }
        }

        if (request.getMaxAge() != null && mClaims.auth_time <= 0) {
            throw AuthorizationException.fromTemplate(ID_TOKEN_VALIDATION_ERROR,
                    AuthorizationException.TokenValidationError.AUTH_TIME_MISSING);
        }
    }

    private  OktaIdToken(Header header, Claims claims, String signature);

}