All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.okta.jwt.impl.OktaJWTClaimsVerifier Maven / Gradle / Ivy

There is a newer version: 0.5.12
Show newest version
/*
 * Copyright 2017 Okta, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.okta.jwt.impl;

import com.nimbusds.jose.proc.SecurityContext;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.proc.BadJWTException;
import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;

import static com.okta.jwt.impl.NimbusJwtVerifier.NONCE_KEY;
import static com.okta.jwt.impl.NimbusJwtVerifier.TOKEN_TYPE_KEY;
import static com.okta.jwt.impl.NimbusJwtVerifier.TOKEN_TYPE_ACCESS;
import static com.okta.jwt.impl.NimbusJwtVerifier.TOKEN_TYPE_ID;

public class OktaJWTClaimsVerifier extends DefaultJWTClaimsVerifier {

    private static final String CID_CLAIM = "cid";

    private final String issuer;
    private final String audience;
    private final String clientId;

    public OktaJWTClaimsVerifier(String issuer, String audience, String clientId) {
        this.issuer = issuer;
        this.audience = audience;
        this.clientId = clientId;
    }

    @Override
    public void verify(JWTClaimsSet jwt, C context) throws BadJWTException {

        Assert.notNull(jwt, "JWTClaimsSet cannot be null");

        // validate expire / not before time
        super.verify(jwt, context);

        // access_token by default
        String tokenType = TOKEN_TYPE_ACCESS;
        String nonce = null;

        if (context instanceof Map) {
            Map contextMap = ((Map) context);

            Object value = contextMap.get(TOKEN_TYPE_KEY);
            if (value != null) {
                tokenType = value.toString();
            }

            nonce = (String) contextMap.get(NONCE_KEY);
        }

        // validate issuer
        Object claimIssuer = jwt.getClaims().get("iss");
        if (!issuer.equals(claimIssuer)) {
            throw new BadJWTException(String.format("Failed to validate jwt string, invalid issuer, " +
                    "expected '%s', found '%s'", issuer, claimIssuer));
        }

        // Access Token Validation
        if (TOKEN_TYPE_ACCESS.equals(tokenType)) {
            List resolvedAudience = jwt.getAudience();
            // the expected audience MUST be in this list
            if (CollectionUtils.isEmpty(resolvedAudience) || !resolvedAudience.contains(audience)) {
                throw new BadJWTException(String.format("Failed to validate jwt string, invalid audience " +
                        "claim 'aud', expected '%s', but found '%s'", audience, resolvedAudience));
            }

            // if an the client id is set, it must be verified
            if (StringUtils.isNotEmpty(clientId)) {
                Object resolvedClientId = jwt.getClaim(CID_CLAIM);
                if (!clientId.equals(resolvedClientId)) {
                    throw new BadJWTException(String.format("Failed to validate jwt string, invalid clientId found in " +
                        "claim 'cid', expected '%s', but found '%s'", clientId, resolvedClientId));
                }
            }
        }

        // ID Token Validation
        else if (TOKEN_TYPE_ID.equals(tokenType)) {

            Assert.notNull(clientId, "An OAuth clientId must be specified when validating ID Tokens.");

            List resolvedAudience = jwt.getAudience();
            // the expected audience MUST be in this list
            if (CollectionUtils.isEmpty(resolvedAudience) || !resolvedAudience.contains(clientId)) {
                throw new BadJWTException(String.format("Failed to validate jwt string, invalid clientId found in " +
                        "claim 'aud', expected '%s', but found '%s'", clientId, resolvedAudience));
            }

            // validate nonce
            Object resolvedNonce = jwt.getClaim("nonce");
            if ( nonce != null && !nonce.equals(resolvedNonce)) {
                throw new BadJWTException(String.format("Invalid nonce found in ID Token, expected '%s', but found '%s'", nonce, resolvedNonce));
            }

            String subject = jwt.getSubject();
            if (subject == null) {
                throw new BadJWTException("Invalid ID Token, missing subject claim ('sub')");
            }

        }

        // Unknown Token Type
        else {
            throw new BadJWTException(String.format("Unknown token type: '%s'", tokenType));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy