Why am I getting "Expecting claim 'qsh' to have value 'A' but instead it has the value 'B'

I develop a connect plugin with Spring-Boot and my plugin has a configuration page with a form. On submit of this form my backend is called, but logs the above error.

Since the atlassian-connect-spring-boot documentation states:

atlassian-connect-spring-boot-starter provides the following features: 


    - Authentication of requests from iframe content back to the add-on

I’d expect that the whole JWT handling is done by the framework.

Did I miss to configure something? My iframe includes the all.js script:

<script src="https://kuespert-dev.atlassian.net/atlassian-connect/all-debug.js" type="text/javascript" data-options="sizeToParent:true;"></script>

and the atlassian-connect.json contains the following authentication entry:

"authentication": {
    "type": "jwt"

I’m using a standard form and included a hidden parameter ‘jwt’

        <form method="POST" id="configuration-form" class="aui">
            <input type="hidden" name="jwt" value="${atlassianConnectToken}">

How can I get this form to work?

I’m using atlassian-connect-spring-boot version 1.3.5.


Thanks for raising this question here, @matthias1 . I don’t immediately see what the problem would be, since the self-authentication tokens don’t even include the query-string hash claim.

Could you provide some logs from your application?

Or would you be able to provide a minimal controller + template to reproduce the issue?


thanks for looking into it. The relevant portion of the log (after pressing save) is:

018-01-31 11:13:50.842 DEBUG 50711 --- [nio-3000-exec-5] c.a.c.s.i.a.jwt.JwtAuthenticationFilter  : Retrieved JWT from request
2018-01-31 11:13:50.843 DEBUG 50711 --- [nio-3000-exec-5] c.a.c.s.i.a.j.JwtAuthenticationProvider  : Parsed JWT: JWTClaimsSet [iss=f8ef6679-1355-36c4-9b6c-14ff138bf0c8, sub=admin, aud=null, exp=Wed Jan 31 11:16:18 CET 2018, nbf=null, iat=Wed Jan 31 11:13:18 CET 2018, jti=null, typ=null, customClaims={qsh=711ed245693eeda3ce731855e4aebce21030be47117462aa87e46e45c774b397, context={"user":{"displayName":"Matthias Küspert","userKey":"admin","username":"admin"}}}]
2018-01-31 11:13:50.998 DEBUG 50711 --- [nio-3000-exec-5] c.a.c.s.i.a.j.JwtAuthenticationProvider  : Canonical request for incoming JWT: CanonicalHttpServletRequest[method=POST,relativePath=/configuration,parameterMap=[tz -> (Europe/Berlin),loc -> (en-US),user_id -> (admin),user_key -> (admin),xdm_e -> (https://kuespert-dev.atlassian.net),xdm_c -> (channel-com.xqual.jira.jira-xstudio-connect-plugin__xstudio-integration-config-page),cp -> (),xdm_deprecated_addon_key_do_not_use -> (com.xqual.jira.jira-xstudio-connect-plugin),lic -> (none),cv -> (1.3.445),jwt -> (eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInFzaCI6IjcxMWVkMjQ1NjkzZWVkYTNjZTczMTg1NWU0YWViY2UyMTAzMGJlNDcxMTc0NjJhYTg3ZTQ2ZTQ1Yzc3NGIzOTciLCJpc3MiOiJmOGVmNjY3OS0xMzU1LTM2YzQtOWI2Yy0xNGZmMTM4YmYwYzgiLCJjb250ZXh0Ijp7InVzZXIiOnsidXNlcktleSI6ImFkbWluIiwidXNlcm5hbWUiOiJhZG1pbiIsImRpc3BsYXlOYW1lIjoiTWF0dGhpYXMgS8O8c3BlcnQifX0sImV4cCI6MTUxNzM5Mzc3OCwiaWF0IjoxNTE3MzkzNTk4fQ.EciutkU3B1pcH3WbXDysmn2mdVmfGsaZk1NMPC6MKSo,eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjb20ueHF1YWwuamlyYS5qaXJhLXhzdHVkaW8tY29ubmVjdC1wbHVnaW4iLCJzdWIiOiJhZG1pbiIsImNsaWVudEtleSI6ImY4ZWY2Njc5LTEzNTUtMzZjNC05YjZjLTE0ZmYxMzhiZjBjOCIsImlzcyI6ImNvbS54cXVhbC5qaXJhLmppcmEteHN0dWRpby1jb25uZWN0LXBsdWdpbiIsImV4cCI6MTUxNzM5NDUwNiwiaWF0IjoxNTE3MzkzNjA2fQ.IfyA6-B1zLD7ScyNDjEgclXOKQnCnzrFXyf9p0mCIYg),issueTypes -> (Bug,New Feature),restUrl -> (,webappUrl -> (,username -> (admin),password -> (xxxx),showInline -> (on),save -> (Save),]]
2018-01-31 11:13:51.129 ERROR 50711 --- [nio-3000-exec-5] c.a.c.s.i.a.j.JwtAuthenticationProvider  : Expecting claim 'qsh' to have value '7af3e1dcb7647b82981d1d952b8eeb32fbd4d199e241e5e35eba4afe869914a1' but instead it has the value '711ed245693eeda3ce731855e4aebce21030be47117462aa87e46e45c774b397'

Building a showcase may last a bit, since I’m now at my main job - the plugin is just something I do by the side.

Okay, so the JWT being rejected was issued by Jira, not by your add-on.

The problem is that the form submission request contains two JWTs: one in the URL query string (/configuration?..&jwt…) and one in the request body.

When JwtAuthenticationFilter can’t find an Authorization header with a JWT, it tries to retrieve the JWT from the request parameters by calling ServletRequest#getParameter(String). And from what I can tell, that method seems to give preference to the query parameter.

So to avoid this problem, specify the action of your <form> explicitly to avoid including the iframe URL query-string.

Yes: this did the trick. Now the JWT is accepted by the backend.

Many thanks!

I am experiencing a similar problem. Successfully using JWT qsh from my plugin server making curl REST requests, BUT when Atlassian sends a request to my server, I try to match the qsh and I can’t. I have tried everything and am pulling my hair out (not much left anyway). To recap everything works fun except I fail to match the qsh on calls from Jira to my server.
Any tips most gratefully received.