JwtInvalidClaimException

77 views
Skip to first unread message

Bhushan Nagaraj

unread,
Oct 6, 2014, 4:20:13 AM10/6/14
to atlassian-...@googlegroups.com
I am creating the JWT token as per the documentation available at https://developer.atlassian.com/static/connect/docs/concepts/understanding-jwt.html#create

However, I keep getting the below exception

com.atlassian.jwt.exception.JwtInvalidClaimException: Expecting claim 'qsh' to have value '3024447c781e253bb3254bd3843fb9aa000dc9911538d83636714320d1ab0d6c' but instead it has the value 'b94fa879d60dd97531770506b3b2a42a813197888a7ed6658509e01df122bb6b'

I tried using the JWT decoder and below is the link to the same

https://jwt-decoder.herokuapp.com/jwt/decode?requestUri=http%3A%2F%2Fbhushan-mac%3A2990%2Fjira%2Frest%2Fapi%2Flatest%2Fproject%2F%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0MTI1ODI5MjYsImlzcyI6ImNvbS5qaXJhZGV2LnByb2dyYW0tc3RhdGlzdGljcyIsInFzaCI6ImI5NGZhODc5ZDYwZGQ5NzUzMTc3MDUwNmIzYjJhNDJhODEzMTk3ODg4YTdlZDY2NTg1MDllMDFkZjEyMmJiNmIiLCJpYXQiOjE0MTI1ODI3NDZ9.sRpW-JK02E40GT2IE6CvN9MFsO5rB_rWRy6WPfWINGA&contextPath=%2Fjira&httpMethod=GET

Here is my code to create the jwt token

long issuedAt = System.currentTimeMillis() / 1000L;
long expiresAt = issuedAt + 180L;
JwtJsonBuilder jwtBuilder = new JsonSmartJwtJsonBuilder()
                .issuedAt(issuedAt)
                .expirationTime(expiresAt)
                .issuer(my addon key;
CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(requestType,
                    "http://bhushan-mac:2990/jira", "/jira", new HashMap());
JwtClaimsBuilder.appendHttpRequestClaims(jwtBuilder, canonical);
JwtWriterFactory jwtWriterFactory = new NimbusJwtWriterFactory();
String jwtbuilt = jwtBuilder.build();
String jwtToken = jwtWriterFactory.macSigningWriter(SigningAlgorithm.HS256,
            "a4d68e96-f881-4cf0-acd8-7e25071ec253").jsonToJwt(jwtbuilt);
String apiUrl = client.baseUrl + apiPath + "?jwt=" + jwtToken;

Can anyone help me and advise where I am going wrong?

Cheers
Bhushan

Yves Berquin

unread,
Oct 6, 2014, 4:39:54 AM10/6/14
to atlassian-...@googlegroups.com
Ah the qsh ... made me sweat also.
Here's what I'm using: it's actually the only place where I had to use the Atlassian lib:

    import com.atlassian.jwt.CanonicalHttpRequest;
    import com.atlassian.jwt.core.HttpRequestCanonicalizer;

    public static String buildQshAtlassian (String httpMethod, String urlEnd, HashMap<String, String[]> params) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        CanonicalHttpRequest req = createRequest(httpMethod, urlEnd, params);
        String s = HttpRequestCanonicalizer.canonicalize(req);
        
        // step 6
        byte[] b = s.getBytes("UTF-8");
        
        // step 7
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(b); 
        byte[] digest = md.digest();        
        
        // step 8
        String hex = bytesToHex (digest);
        return hex;
    }
    
    /**
     * Simple byte array to hex string (lower case letters) converter
     */
    final protected static char[] hexArray = "0123456789abcdef".toCharArray();
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }   

I'm passing in endUrl the path starting with /rest, without query strings.
A big gotcha I had in the process was that I was using a bytes-to-hex converter that generated uppercase letters. That's not working with qsh.

Hope this helps

Yves

Peter Brownlow

unread,
Oct 6, 2014, 8:26:30 PM10/6/14
to atlassian-...@googlegroups.com
Hi Bhushan,

The second parameter that you are sending to CanonicalHttpUriRequest() is wrong: it should be the _path_ component of the URL, not the full URL (e.g. "/jira/rest/api/latest/project", not "http://bhushan-mac:2990/jira/rest/api/latest/project") and not the URL up to the end of the context path (e.g. not "http://bhushan-mac:2990/jira" as in your example code). (Also, as an aside, if you have no parameters then you can optionally use the overload that does not take a parameters argument).

CanonicalHttpUriRequest canonical = new CanonicalHttpUriRequest(requestType, "/jira/rest/api/latest/project", "/jira");

Here is a jwt-decoder link:
https://jwt-decoder.herokuapp.com/jwt/decode?requestUri=http%3A%2F%2Fbhushan-mac%3A2990%2Fjira%2Frest%2Fapi%2Flatest%2Fproject%3Fjwt%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjb20uamlyYWRldi5wcm9ncmFtLXN0YXRpc3RpY3MiLAogImV4cCI6MTQxMjU4MjkyNiwgImlhdCI6MTQxMjU4Mjc0NiwgInFzaCI6IjllNWRkODk0ODZlYjkwMjM3ZDRlZDAzMWFmMjg1MDk5NzVhYjYyZTdjOTNiNmUyODA5YWZkMzM4ODU3ZmZiY2EifQ.Ye2JddQNokn7uJixl37D_tiUr5lQR8bgGjCr7eStE7o&contextPath=%2Fjira&httpMethod=GET

I've used the same "iss", "iat" and "exp" claim values as in your link. The "qsh" claim value is different.

-Peter
Reply all
Reply to author
Forward
0 new messages