Why isn't the QSH always required in a JWT authentication?

jwt

#1

Hi,

When Confluence builds the URL of an addon’s iframe, it authenticates it with a JWT token, which contains various values including the QSH (=basically a hash of the current URL). The purpose is to prevent the user from building an URL themselves.

But when we want to call REST APIs of our product, Atlassian recommends that we use AP.context.getToken(), which returns a JWT with no QSH, hence valid for any URL. They explain it on the “Cacheable iframe” doc, for example.

Why is it secure? Doesn’t it mean that user can build a fake URL to an iframe, use the getToken() to authenticate it, bypassing the QSH issue?

Thank you


#2

@aragot, the qsh JWT claim enables the recipient of a JWT-signed HTTP request to verify that data in the URL path or query string was sent by the JWT issuer.

Why is it secure?

AP.context.getToken() returns a JWT token that is not associated with any particular HTTP request, and as such does not include the qsh claim.

Doesn’t it mean that user can build a fake URL to an iframe, use the getToken() to authenticate it, bypassing the QSH issue?

No, only if the app (incorrectly) allows it. As the documentation states, Atlassian will include the qsh claim in iframe URL JWTs. Apps should require the qsh claim in JWTs used to authenticate iframes.


#3

Interesting. We should ensure developers check this.

That also means an iframe can implicitly provide information such the user’s permissions (e.g. Confluence wouldn’t sign a request for a space or an admin screen if they weren’t allowed to access it) but subsequent REST resources must be designed around the fact that the only thing the JWT token signs is the “iss” (issuer/clientKey).


#4

I’m not sure what you mean. JWT tokens obtained via AP.context.getToken() contain all available context. This is in contrast to iframe URLs where each context parameter must be requested individually. Whether inside the JWT token or in a URL context parameter, the Atlassian product will, as you say, never send a reference to an entity (such as a space) that the current user does not have access to.