401 Unauthorized Error for some Endpoints from Connect with atlassian-jwt

Hi there,

I do want to execute requests to the Jira Cloud REST API from a Node JS server environment on behalf of a Connect app. For that I am creating a symmetric JWT token with a shared secret per instance as described here https://developer.atlassian.com/cloud/jira/platform/understanding-jwt-for-connect-apps/.
Now for most requests everything works as expected, but for this endpoint in particular, I always get a 401 Unauthorized error without any further details: https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issue-properties/#api-rest-api-3-issue-properties-multi-post.

I can ensure that the shared secret is valid and active, as I am executing another POST request shortly before, which works.

For the building the JWT token and attaching it to the Authorization header, I use the following code:

import { TenantInformation } from "./tenant-information";
import jwt, { SymmetricAlgorithm } from "atlassian-jwt";

export function getAuthHeaderForMethod(
    method: string,
    path: string,
    tenantInformation: TenantInformation,
) {
    const token = buildJwtToken(method, path, tenantInformation);
    return {
        Authorization: `JWT ${token}`,
    };
}

function buildJwtToken(
    method: string,
    relativeUri: string,
    tenantInformation: TenantInformation,
) {
    const jwtPayload = createJwtPayload({
        tenantInformation,
        method,
        path: relativeUri,
    });

    return jwt.encodeSymmetric(
        jwtPayload,
        tenantInformation.sharedSecret,
        SymmetricAlgorithm.HS256,
    );
}

interface CreateJwtPayloadParams {
    tenantInformation: TenantInformation;
    method: string;
    path: string;
}

function createJwtPayload(
    { tenantInformation, method, path }: CreateJwtPayloadParams,
) {
    const nowUNIX = Math.round(new Date().getTime() / 1000);

    return {
        iss: tenantInformation.key,
        iat: nowUNIX,
        exp: nowUNIX + 300000,
        aud: [tenantInformation.clientKey],
        qsh: jwt.createQueryStringHash(
            jwt.fromMethodAndUrl(method, path),
        ),
    };
}

The interface TenantInformation contains the url, shared secret, client key etc. for an instance my app is installed on.

Can anyone please help troubleshooting this issue? If more information is needed, please let me know.

Thanks in advance!

I found a solution, which I’ll share here for documentation purposes:
The POST request on /rest/api/3/issue/properties/multi did work, and I get a response with a status code “303: See Other” and an URL in the response header field location.
The fetch method in Node now automatically executes a GET request to that redirected location, which of course fails, as the JWT token includes route information for the previous POST request.
To omit this issue, you can disable that automatic redirect behaviour in the RequestInit object by setting the property redirect to "manual" and eventually execute the GET request manually with a fresh JWT token including the respective location.

3 Likes

Thanks for sharing the root cause and the resolution @NiklasSchloegel

For the Python code that utilizes atlassian-jwt · PyPI, add allow_redirects=False to the request header.