JWT App validation via cURL (PHP) results in 401

Willem-Jelle der Nederlanden July 2, 2019

I am trying to create an application for Jira Service Desk, however, I keep getting stuck at the following point:
After successfully generating a valid JWT, I try to access the rest URL via cURL, but I keep getting 401, unauthorized.

This is the function where I call the JWT-creature function:

public function generateJWT() {
$j = new JWTModel();
$o = new ObjectModel();
$r = new RestModel();

$object = $o->getClientByUrl('https://<my-instance-for-demo>.atlassian.net');
$jwt = $j->generate(10000, $object->key, $object->clientKey, $object->sharedSecret);

print_r($r->issueData($jwt, 10000));
}

This is the function that creates the JWT:

public function generate($issue, $key, $clientKey, $sharedSecret) {
$token = [
"iss" => $key,
"iat" => time(),
"exp" => time() * 3600,
"sub" => $clientKey,
"qsh" => hash('sha256', "GET&/rest/api/latest/issue/" . $issue)
];

$jwt = JWT::encode($token, $sharedSecret);
return $jwt;
}

 

And eventually the cURL-function:

public function issueData($jwt, $issue) {
try {
$curl = new Curl();
$curl->setOpt(CURLOPT_SSL_VERIFYPEER, false);
$curl->setOpt(CURLOPT_POST, false);
$curl->setOpt(CURLOPT_HTTPHEADER, ['Authorization: JWT ' . $jwt, 'Content-type: application/json']);
$curl->post("https://<my-instance-for-demo>.atlassian.net/rest/api/latest/issue/" . $issue);

return $curl->response;
} catch (\ErrorException $e) {
return $e->getMessage();
}
}

This is my connect:

{
"name": "XXXX XXX",
"description": "XXX makes your life easier",
"key": "xxxx-app",
"baseUrl": "https://xxx.xxxx.nl",
"vendor": {
"name": "xxxx",
"url": "http://xxx.nl"
},
"links": {
"self": "https://xxx.xxx.nl/atlassian-connect.json",
"homepage": "https://xxx.nl/"
},
"authentication": {
"type": "jwt"
},
"lifecycle": {
"installed": "/installed",
"uninstalled": "/unstalled"
},
"scopes": [
"READ"
],
"apiVersion": 1,
"modules": {
"webPanels": [{
"conditions": [{
"condition": "user_is_logged_in"
}],
"key": "xxx-xxx-insert",
"name": {
"value": "xxx"
},
"url": "/canned?project={servicedesk.serviceDeskId}&issueId={issue.id}&issueKey={issue.key}",
"location": "atl.jira.view.issue.left.context",
"layout": {
"width": "100%",
"height": "100px"
},
"weight": 999
}]
}
}

Does anyone sees the point where I made a mistake?

3 answers

1 accepted

0 votes
Answer accepted
Willem-Jelle der Nederlanden July 2, 2019

Hi Willem-Jelle,

For your cURL-function, please use $curl->get() instead of $curl->post();

0 votes
Yatish Madhav
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 15, 2020

Oh and a side note, @Willem-Jelle der Nederlanden  ... I noticed in your original code, the expiry time is time() * 3600 - should that not be time() + 3600? :)

0 votes
Yatish Madhav
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 15, 2020

Hi thereI 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?

Willem-Jelle der Nederlanden June 15, 2020

@Yatish Madhav Hi, it looks like your QSH value is incorrect. It is required to put the path in the QSH. Let me know if that solves the problem!

Yatish Madhav
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
June 15, 2020

Thanks @Willem-Jelle der Nederlanden - I have resolved this an hour or two after I posted it ... So yes, I did include the path ($qshStr = $method.'&'.$path.'&'.substr($qs, 1);)

So this was the issue. The QSH was correct ... but when I was making the call, I did not include the "maxResults=100" query string. And that caused the match between the 2 to fail - hence not authorizing myself. :)

Thanks for the quick reply too ...

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events