I can't get JWT to work with PHP Rest Client

I can’t get JWT to work with PHP Rest Client.

Here is some source code:

$uri = "https://some-url-to-instance.atlassian.net/rest/api/2/project.json?expand=lead&jwt=$jwt";

$client = new Zend_Http_Client($uri);
// set some parameters
//$client->setAuth($username, $password, Zend_Http_Client::AUTH_BASIC);
// POST request
$client->setMethod(Zend_Http_Client::GET);
$response = $client->request();

$body = $response->getBody();

It always go to Unauthorized (401) page.

Code below prints empty JSON string:

$uri = "https://your-dev-instance.atlassian.net/rest/api/2/project?expand=lead&jwt=".hash_hmac('sha256', $jwt, $hashKey);
//echo $uri;
$client = new Zend_Http_Client($uri);
// set some parameters
//$client->setAuth($username, $password, Zend_Http_Client::AUTH_BASIC);
// POST request
$client->setMethod(Zend_Http_Client::GET);
$response = $client->request();
//echo $response;
$body = $response->getBody();

When I change the & char to different in URL then Unauthorized (401) page not come.

JWT Decoder giving this:

Screenshot-2018-3-1 JWT Decoder

Looks like you’re missing the qsh (see: https://developer.atlassian.com/cloud/jira/platform/understanding-jwt/#a-name-qsh-a-creating-a-query-string-hash)

Can you send over the repo URL of the Jira PHP library you’re using? (there’s a few of them out there)

Here: GitHub - firebase/php-jwt: PHP package for JWT

I have code like this:

$qsh = hash('sha256', "GET&/rest/api/2/project.json&expand=lead");

$iat = (integer) time();
$exp = (integer) time() + 3600;

$token = array(
		"iss" => $client,
		"iat" => $iat,
		"exp" => $exp,
		"qsh" => $qsh,
		"sub" => $sub
);
$jwt = JWT::encode($token, $secret);

And QHS match with JWT Decoder at: http://jwt-decoder.herokuapp.com/jwt/decode but I still get a 401 Unauhorized page.

With this code below I got everything to work:

$qsh = hash('sha256', "GET&/rest/api/2/project&expand=lead");

$iat = (integer) time();
$exp = (integer) time() * 3600;

$token = array(
		"iss" => "com.i4ware.plugin.timesheet.timesheet",
		"iat" => $iat,
		"exp" => $exp,
		"qsh" => $qsh
);
$jwt = JWT::encode($token, $secret);

ISS must be app key.

2 Likes

Hi there
I am trying something similar … Also my first time working on Connect Apps. Here is a sample code I am using. I am running this locally and on my Test server … and both returns a 401.

<?php

require_once('vendor/autoload.php');

use \Firebase\JWT\JWT;

$key = 'test-key-used-in-app-desc';
$iat = (int) time();
$exp = $iat + 3600;
$sec = 'URiDszs6dEQZeTrBRc5H1FwIbdoVnvYmVlgsSIAqduji5NUndVFwvtin0XawuJWa6wLcOoBbUvbinkJCqMTChe';
$method = 'GET';
$baseUrl = 'https://xxx.atlassian.net';
$path = '/rest/api/3/search';
$qs = str_replace('?', '&', '?maxResults=100');
$qshStr = $method.'&'.$path.'&'.substr($qs, 1);
$qsh = hash('sha256', $qshStr);
$claims = array
(
	"iss" => $key,
	"exp" => $exp,
	"iat" => $iat,
	"qsh" => $qsh
);

$jwtToken = JWT::encode($claims, $sec);
$apiUrl = $baseUrl.$path.'?jwt='.$jwtToken;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_HTTPGET, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Accept: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$curl_response = curl_exec($ch);
echo '<pre>';print_r(json_decode($curl_response, true));echo'</pre>';
curl_close($ch);

Please advise where I am going wrong?

I did everything with Zend Framework 1.12 with its REST Client. Do you want source code?

Thanks for the quick reply, @matti.kiviharju. No worries.

I spent a bit more time playing with this and found the issue … And the exact reason QSH is in place :slightly_smiling_face:

In my curl request - I only included the jwt query string where as in my qsh. I hash the maxResults item. Hence it was failing the match between the QSH and the actual query being made …

Hope this helps others if at all.

Thanks for offering the assistance again.

No problem! Well done!

1 Like