Page 1 of 1

[ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Thu Aug 23, 2018 6:12 am
by rymrbh
Hello,

Since I upgraded PocessMaker from 3.2.1 to 3.2.3 I have this error :
Code: Select all
{
    "error": {
        "code": 401,
        "message": "Unauthorized"
    }
}
My request (I tested it with postman and in javascript):
Code: Select all
POST
http://PROCESSMAKER_IP/api/1.0/workflow/cases/?access_token=9a46b5eaaeb7e9de6b98bba5590294e5d40ddf8d&pro_uid=1627488305a8bf1c34f68b7055359592%26&tas_uid=2443015575a8bfe0806c0e3006365963
Is there any change in this version that can impact my requests?

Thanks for your help.
Rym.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Thu Aug 23, 2018 11:59 pm
by amosbatto
I just tried the POST /cases endpoint in PM 3.2.3 Community (manual install in Debian 8.4 with PHP 5.6.20 and MySQL 5.5.47) and I don't have any problem calling it with HttpRequester (in firefox 51) and using PHP.

What versions of PHP and MySQL do you have installed?

Here is my HttpRequester:
httpRequesterIn323.png
httpRequesterIn323.png (30.2 KiB) Viewed 1623 times
httpRequesterAuthorization.png
httpRequesterAuthorization.png (25.38 KiB) Viewed 1623 times
Please try it this same way using Authorization: Bearer XXXXXXXXXXXXXXXXXXXXXXXX

Here is my PHP code:
Code: Select all
//PM 3.2.3 Community:
$pmServer     = 'http://localhost:323';
$clientId     = 'YMLZWDATXYSIAASVTOGNPHRCYGUUAQNY';
$clientSecret = '1307993235b7f7467ca2c59050850691';
 
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   global $pmServer, $pmWorkspace;
   $postParams = array(
      'grant_type'    => 'password',
      'scope'         => '*',       //set to 'view_process' if not changing the process
      'client_id'     => $clientId,
      'client_secret' => $clientSecret,
      'username'      => $username,
      'password'      => $password
   );
   $loginUrl = "$pmServer/$pmWorkspace/oauth2/token";
 
   $ch = curl_init($loginUrl);
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
   $oToken = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($httpStatus != 200) {
      print "Error in HTTP status code: $httpStatus";
   }
   elseif (isset($oToken->error)) {
      print "Error logging into $pmServer:\n" .
         "Error:       {$oToken->error}\n" .
         "Description: {$oToken->error_description}\n";
   }
   else {
      //At this point $oToken->access_token can be used to call REST endpoints.
 
      //If planning to use the access_token later, either save the access_token
      //and refresh_token as cookies or save them to a file in a secure location.
 
      //If saving them as cookies:
      //setcookie("access_token",  $oToken->access_token,  time() + 86400);
      //setcookie("refresh_token", $oToken->refresh_token); //refresh token doesn't expire
      //setcookie("client_id",     $clientId);
      //setcookie("client_secret", $clientSecret);
 
      //If saving to a file:
      //file_put_contents("/secure/location/oauthAccess.json", json_encode($tokenData));
   }
 
   return $oToken;
}

 
/*Function to obtain a new access token, using a refresh token. If the parameters are not specified
then get them from the cookie if they exist. The new access token is set as a cookie available at $_COOKIE["access_token"]
Parameters:
  clientId:     The cliend ID.
  clientSecret: The client secret code.
  refreshToken: The refreshToken from a previous call to /oauth2/token endpoint.
Return value:
  Object returned by /oauth2/token endpoint, which either contains access token or error message.*/
function pmRestRefresh($clientId=null, $clientSecret=null, $refreshToken=null) {
   global $pmServer, $pmWorkspace;
   $clientId     = ($clientId === null and isset($_COOKIE['client_id']))         ? $_COOKIE['client_id']     : $clientId;
   $clientSecret = ($clientSecret === null and isset($_COOKIE['client_secret'])) ? $_COOKIE['client_secret'] : $clientSecret;
   $refreshToken = ($refreshToken === null and isset($_COOKIE['refresh_token'])) ? $_COOKIE['refresh_token'] : $refreshToken;
 
   $aVars = array(
      'grant_type'    => 'refresh_token',
      'client_id'     => $clientId,
      'client_secret' => $clientSecret,
      'refresh_token' => $refreshToken
   );
 
   $ch = curl_init("$pmServer/$pmWorkspace/oauth2/token");
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
   $oToken = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($httpStatus != 200) {
      print "Error in HTTP status code: $httpStatus\n";
   }
   elseif (isset($oToken->error)) {
      print "Error logging into $pmServer:\n" .
         "Error:       {$oToken->error}\n" .
         "Description: {$oToken->description}\n";
   }
   else {
      //Save access token as a cookie that expires in 86400 seconds:
      setcookie("access_token",  $oToken->access_token, time() + 86400);
 
      //If saving to a file:
      //file_put_contents("/secure/location/oauthAccess.json", json_encode($oToken));
   }
   return $oToken;
}
 
/*Function to call a ProcessMaker REST endpoint and return the HTTP status code and
response if any.
Parameters:
 $method:      HTTP method: "GET", "POST", "PUT" or "DELETE"
 $endpoint:    The PM endpoint, not including the server's address and port number.
               Ex: "/api/1.0/workflow/cases"
 $aVars:       Optional. Associative array containing the variables to use in the request
               if "POST" or "PUT" method.
 $accessToken: Optional. The access token, which comes from oauth2/token. If not defined
               then uses the access token in $_COOKIE['access_token']
 $isJson       Optional. If set to TRUE, then $aVars is treated as a JSON string, 
               rather than an array of variables. 
Return Value:
 object {
    response: Response from REST endpoint, decoded with json_decode().
    status:   HTTP status code: 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not found), etc.
 }                                                                                              */
function pmRestRequest($method, $endpoint, $aVars = null, $accessToken = null, $isJson=false) {
   global $pmServer;
 
   if (empty($accessToken) and isset($_COOKIE['access_token']))
      $accessToken = $_COOKIE['access_token'];
 
   if (empty($accessToken)) { //if the access token has expired
      //To check if the PM login session has expired: !isset($_COOKIE['PHPSESSID'])
      //header("Location: loginForm.php"); //change to match your login method
      throw new Exception("Access token is empty");
   }
 
   //add beginning / to endpoint if it doesn't exist:
   if (!empty($endpoint) and $endpoint[0] != "/")
      $endpoint = "/" . $endpoint;
 
   $ch = curl_init($pmServer . $endpoint);
   curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $method = strtoupper($method);
 
   switch ($method) {
      case "GET":
         break;
      case "DELETE":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
         break;
      case "PUT":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
      case "POST":
         curl_setopt($ch, CURLOPT_POST, 1);
         if ($isJson) {
             curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          
                    'Content-Type: application/json',                                                                                
                    'Content-Length: ' . strlen($aVars)
                )                                                                       
             );
             curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
         }
         else {
             curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars));
         }
         break;
      default:
         throw new Exception("Error: Invalid HTTP method '$method' $endpoint");
         return null;
   }
 
   $oRet = new StdClass;
   $oRet->response = json_decode(curl_exec($ch));
   $oRet->status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   /*if ($oRet->status == 401) { //if session has expired or bad login:
      throw new Exception("Bad login or login expired."); //header("Location: loginForm.php"); //change to match your login method  
   }
   else*/if ($oRet->status != 200 and $oRet->status != 201) { //if error
      if ($oRet->response and isset($oRet->response->error)) {
         print "Error in $pmServer:\nCode: {$oRet->response->error->code}\n" .
               "Message: {$oRet->response->error->message}\n";
      }
      else {
         print "Error: HTTP status code: $oRet->status\n";
      }
   }
 
   return $oRet;
}

//login and execute endpoint:
echo "<pre>";
$oToken = pmRestLogin($clientId, $clientSecret, 'admin', 'admin');

$processId = "9998859365b74f911797718085511966";
$taskId = "9483920005b74f93dba3d92097940618";
$url = "/api/1.0/workflow/cases";
$aVars = array(
		'pro_uid' => $processId,
		'tas_uid' => $taskId
);

$oRet = pmRestRequest("POST", $url, $aVars, $oToken->access_token);
var_dump($oRet);

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Wed Oct 17, 2018 5:59 am
by rymrbh
Hi,

Sorry for the delay, I was working on an another subject.

I tried using Authorization: Bearer and I have the same error (see the attachment).

I have this versions :
PHP : 5.6.38
Mariadb : 5.5.60

Thanks for your help.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Thu Nov 01, 2018 9:35 pm
by amosbatto
ProcessMaker 3.2.3 wasn't tested with MariaDB. It probably works, but nobody here has tried it.

Are you able to obtain an access token from ProcessMaker's oauth2 in Postman without any problems?
Have you tried executing other REST endpoints like GET /cases ?
POST /cases is tricky so try something easier first.

Just to verify that it truly doesn't work, can you try it in HttpRequester in Firefox? (Sorry, but I don't use Postman, so I'm not sure if your settings are correct.)

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Mon Jan 28, 2019 12:37 pm
by rymrbh
Hello Amosbatto,

Yes, I can obtain an access token from ProcessMaker.
I executed some GET requests and I have the same error.
I have the same problem in HttpRequester in Firefox.

I also removed MariaDB and installed MySQL (following the documentation) and I have the same error.

Thanks for your help.
Rym.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Mon Jan 28, 2019 10:48 pm
by amosbatto
Let's do a test. Save the following script as a file named testrest.php on your computer:
Code: Select all
//PM 3.2.3 Community:
$pmServer     = 'http://localhost:323'; //set to domain or IP address of ProcessMaker server
$clientId     = 'YMLZWDATXYSIAASVTOGNPHRCYGUUAQNY';  
$clientSecret = '1307993235b7f7467ca2c59050850691';
 
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   global $pmServer, $pmWorkspace;
   $postParams = array(
      'grant_type'    => 'password',
      'scope'         => '*',       //set to 'view_process' if not changing the process
      'client_id'     => $clientId,
      'client_secret' => $clientSecret,
      'username'      => $username,
      'password'      => $password
   );
   $loginUrl = "$pmServer/$pmWorkspace/oauth2/token";
 
   $ch = curl_init($loginUrl);
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
   $oToken = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($httpStatus != 200) {
      print "Error in HTTP status code: $httpStatus";
   }
   elseif (isset($oToken->error)) {
      print "Error logging into $pmServer:\n" .
         "Error:       {$oToken->error}\n" .
         "Description: {$oToken->error_description}\n";
   }
   else {
      //At this point $oToken->access_token can be used to call REST endpoints.
 
      //If planning to use the access_token later, either save the access_token
      //and refresh_token as cookies or save them to a file in a secure location.
 
      //If saving them as cookies:
      //setcookie("access_token",  $oToken->access_token,  time() + 86400);
      //setcookie("refresh_token", $oToken->refresh_token); //refresh token doesn't expire
      //setcookie("client_id",     $clientId);
      //setcookie("client_secret", $clientSecret);
 
      //If saving to a file:
      //file_put_contents("/secure/location/oauthAccess.json", json_encode($tokenData));
   }
 
   return $oToken;
} 
 
/*Function to call a ProcessMaker REST endpoint and return the HTTP status code and
response if any.
Parameters:
 $method:      HTTP method: "GET", "POST", "PUT" or "DELETE"
 $endpoint:    The PM endpoint, not including the server's address and port number.
               Ex: "/api/1.0/workflow/cases"
 $aVars:       Optional. Associative array containing the variables to use in the request
               if "POST" or "PUT" method.
 $accessToken: Optional. The access token, which comes from oauth2/token. If not defined
               then uses the access token in $_COOKIE['access_token']
 $isJson       Optional. If set to TRUE, then $aVars is treated as a JSON string, 
               rather than an array of variables. 
Return Value:
 object {
    response: Response from REST endpoint, decoded with json_decode().
    status:   HTTP status code: 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not found), etc.
 }                                                                                              */
function pmRestRequest($method, $endpoint, $aVars = null, $accessToken = null, $isJson=false) {
   global $pmServer;
 
   if (empty($accessToken) and isset($_COOKIE['access_token']))
      $accessToken = $_COOKIE['access_token'];
 
   if (empty($accessToken)) { //if the access token has expired
      //To check if the PM login session has expired: !isset($_COOKIE['PHPSESSID'])
      //header("Location: loginForm.php"); //change to match your login method
      throw new Exception("Access token is empty");
   }
 
   //add beginning / to endpoint if it doesn't exist:
   if (!empty($endpoint) and $endpoint[0] != "/")
      $endpoint = "/" . $endpoint;
 
   $ch = curl_init($pmServer . $endpoint);
   curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken));
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
   $method = strtoupper($method);
 
   switch ($method) {
      case "GET":
         break;
      case "DELETE":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
         break;
      case "PUT":
         curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
      case "POST":
         curl_setopt($ch, CURLOPT_POST, 1);
         if ($isJson) {
             curl_setopt($ch, CURLOPT_HTTPHEADER, array(                                                                          
                    'Content-Type: application/json',                                                                                
                    'Content-Length: ' . strlen($aVars)
                )                                                                       
             );
             curl_setopt($ch, CURLOPT_POSTFIELDS, $aVars);
         }
         else {
             curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($aVars));
         }
         break;
      default:
         throw new Exception("Error: Invalid HTTP method '$method' $endpoint");
         return null;
   }
 
   $oRet = new StdClass;
   $oRet->response = json_decode(curl_exec($ch));
   $oRet->status   = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   /*if ($oRet->status == 401) { //if session has expired or bad login:
      throw new Exception("Bad login or login expired."); //header("Location: loginForm.php"); //change to match your login method  
   }
   else*/if ($oRet->status != 200 and $oRet->status != 201) { //if error
      if ($oRet->response and isset($oRet->response->error)) {
         print "Error in $pmServer:\nCode: {$oRet->response->error->code}\n" .
               "Message: {$oRet->response->error->message}\n";
      }
      else {
         print "Error: HTTP status code: $oRet->status\n";
      }
   }
 
   return $oRet;
}

//login and execute endpoint:
echo "<pre>";
//change 'my_username' and  '[email protected]' to a username and password on your system:
$oToken = pmRestLogin($clientId, $clientSecret, 'my_username', '[email protected]');

$url = "/api/1.0/workflow/cases/";
$oRet = pmRestRequest("GET", $url, null, $oToken->access_token);
var_dump($oRet);
Change the following lines to match your system:
$pmServer = 'http://localhost:323'; //set to domain or IP address of ProcessMaker server
$clientId = 'YMLZWDATXYSIAASVTOGNPHRCYGUUAQNY';
$clientSecret = '1307993235b7f7467ca2c59050850691';
$oToken = pmRestLogin($clientId, $clientSecret, 'my_username', '[email protected]');

Then execute the script from the command line, like this:
php testrest.php

Does it work? If so, then you aren't calling the endpoints correctly in Postman for some reason. Post screenshots of what you are doing in Postman.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Mon Feb 11, 2019 7:25 am
by rymrbh
Hello amosbatto,

I tested your code and it's working.

After some tests, I found the source of my error.
The user have the permission "PM_REST_API_APPLICATIONS" as specified here https://wiki.processmaker.com/3.1/OAuth ... o_use_REST .
I added the permission "PM_CASES" and it's working.

Thanks a lot for your time and your help.
Regards,
Rym.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Thu Feb 14, 2019 10:31 pm
by amosbatto
It is always the simple things! I never even thought that you might have a user without the PM_CASES permission.

Re: [SOLVED] [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Fri Mar 01, 2019 11:25 am
by rymrbh
Yes!
The strange thing is that with other versions it was working without this permission...

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Thu Jun 13, 2019 9:45 am
by Bhupender
i am facing the same issue as mention above. when i call api through external application, gives 401 error.in postman, its showing data. i have even set the all permissions(pm_rest_application,cases) to admin but still getting issue.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Thu Jun 13, 2019 4:36 pm
by amosbatto
Bhupender wrote: Thu Jun 13, 2019 9:45 am i am facing the same issue as mention above. when i call api through external application, gives 401 error.in postman, its showing data. i have even set the all permissions(pm_rest_application,cases) to admin but still getting issue.
Bhupender, What happens if you execute testrest.php from the command line? If it works, then the problem is the parameters you are sending to Postman. Post screen shots of your login to oauth2 and your REST call in Postman.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Fri Jun 14, 2019 3:59 am
by Bhupender
Code:-
after getting auth token
Code: Select all
if (isset($oToken) and isset($oToken->access_token)) {
        $accessToken = $oToken->access_token;
        $ch1 = curl_init();
        curl_setopt($ch1, CURLOPT_URL, $pmServer."/api/1.0/wf/cases");
        curl_setopt($ch1, CURLOPT_HTTPHEADER, array("Authorization: Bearer". $accessToken));
        curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
        $aUsers = json_decode(curl_exec($ch1));
        print_r($aUsers);
        $statusCode = curl_getinfo($ch1, CURLINFO_HTTP_CODE);
        curl_close($ch1);

    foreach ($aUsers as $oUser) {
        print_r($oUser);
      if ($oUser->usr_status == "ACTIVE") {
      //   print "{$oUser->usr_firstname} {$oUser->usr_lastname} ({$oUser->usr_username})\n";
        print_r($oUser->usr_firstname);
      }
Screenshot from 2019-06-14 12-44-09.jpg
Screenshot from 2019-06-14 12-44-09.jpg (135.69 KiB) Viewed 141 times
erro2.jpg
erro2.jpg (305.05 KiB) Viewed 141 times

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Fri Jun 14, 2019 5:28 pm
by amosbatto
In Postman, add the access token value in the header like:
Bearer ACCESS_TOKEN

For example, if "5e8ff9bf55ba3508199d22e984129be6" is your access token, then use:
Bearer 5e8ff9bf55ba3508199d22e984129be6
3.1RestPostmanHeaderToken.png
3.1RestPostmanHeaderToken.png (25.3 KiB) Viewed 120 times
Is routes.php (that contains the error) your file?

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Fri Jun 14, 2019 9:42 pm
by Bhupender
There is no issue in postman while fetching. I am only getting issue while calling via external app.

Re: [ProcessMaker 3.2.3] REST API 401 Unauthorized

Posted: Mon Jun 17, 2019 6:29 pm
by amosbatto
Can you post your complete code? I don't see a problem in the little bit of PHP code that you posted.

Is routes.php your file or it is it ProcessMaker's shared/sites/{workspace}/routes.php file? I'm trying to determine where the error is occurring.