Get new token on client side?

I have an add-on which is a general page and supposed to be a single-page-application.
On SPA the user is meant to stay there for hours without having to navigate elsewhere.

The JWT that is generated by atlassian has expiry time in minutes. How am I supposed to refresh this token without forcing the user to refresh the page?

2 Likes

Although it doesn’t mention it in the documentation, Atlassian connect actually automatically refreshes the JWT token before it expires. I’ve created an issue for amending the documentation. Unfortunately I don’t have the link at hand :slight_smile:

@remie thaks for a swift reply. How do I get this JWT token from javascript so I can pass it on as a parameter to my applications REST endpoint?

There is no javascript or api endpoint to retrieve the token. It is passed as a query string parameter (called jwt) whenever a module URL is loaded in the iframe.

BTW, the issue for amending the documentation can be found here: https://ecosystem.atlassian.net/browse/ACJS-503. It refers to https://ecosystem.atlassian.net/browse/AC-1500, https://ecosystem.atlassian.net/browse/AC-1567 and https://ecosystem.atlassian.net/browse/AC-2205 in which the JWT token refresh functionality is discussed.

@remie but when the user stays on the page (iframe) for 1 hour without refreshing or navigating, the JWT will have expired already. And that is the problem, I cannot send REST calls to my service with the same JWT token because it has expired.

I know, I have the same problem. The Atlassian JWT is designed to be used for calling the REST API from the host product. Atlassian will make sure that the JWT token remains valid as long as the user is signed in.

The general idea is that you provide your own session authentication (being JWT or http-only cookies) for the (subsequent) calls to your REST service. You can use the Atlassian JWT token for the initial communication with your own service to identify the user. After you have established the validity of the user, you can replace the Atlassian JWT with your own.

2 Likes

@remie ahh, that solution you describe is exactly the backup-solution I had in mind. Good to know there are others who have been in same situation and solved it this way.

Again thanks for the help, Remie. This issue can now be closed.

1 Like

I just wanted to add another solution which may not be approved by the Atlassian team:

Extend the JWT verification method to add 1 day to the expiration time check.

Obviously you use this only for REST JWT checks and keep the old 15 minutes IAT for everything else.

@jeevan is correct that Atlassian wouldn’t approve the extending exp solution. Such an approach exposes your add-on to replay attacks. The short time window is meant to prevent that kind of attack without burdening your add-on with the heavy burden of remembering jti claims as nonces.

I’m using authbeat (like heart beat) to periodically refresh the token as long as user stays on add-on page.

how do you refresh the token via REST?

@azhdanov: can you share the BitBucket / GitHub / NPM / Composer / url for that module?

@jeevan, @remie please see ACE + React (create-react-app)

I am using atlassian-connect-spring-boot on the backend and react on the client side. I handled it by adding a rest end point for heartbeat which returns a new fresh token. On the client side before the expiration of token I trigger the /heartbeat and refresh the token.

Spring Controller

    @GetMapping({"/heartbeat"})
    @ResponseBody
    public Map<String, String> refreshJWT(Model model){
      return Collections.singletonMap("token", ""+model.getAttribute("atlassianConnectToken"));
    }

On Client Side

    const refreshJWT = () => {
      return fetch('/heartbeat',
        {
          headers: {Authorization:'JWT ' + Utils.getMetadata('token') }
        })
        .then(res => {
          if (res.status === 200) {
            res.json().then(json => {
              const token = json['token'];
              Utils.setJWTToken(token);
            });
          };
        });
    }
    setInterval(refreshJWT, 30000);
2 Likes

You don’t need to set up a heartbeat endpoint to get a token, you can use

AP.context.getToken(function(token) { ....})

on the client. See https://developer.atlassian.com/cloud/confluence/jsapi/context/ and https://developer.atlassian.com/cloud/confluence/cacheable-app-iframes/#getting-context

3 Likes