API setup and example

seems to be not only NGINX issue.
See issue 8251 on Github

Edit:
I have the same problem, didnā€™t find solution so far.

Edit2:
Here is nginxā€™s log:

2020/01/12 20:50:01 [error] 27020#27020: *23 open() "/srv/http/example/www/crm/Api/index.php/access_token" failed (20: Not a directory), client: 71.124.78.10, server: example.com, request: "GET /crm/Api/access_token HTTP/2.0", host: "example.com"

Looks weird to have /access_token as a path after index.php. but donā€™t know PHP and its specs :thinking:

Sorry, just seen this - I did so.
Can someone merge this please?

@murray_greig what is your Github user name? Iā€™m guessing you made the change and Github created the commit in your forked repo, instead of on the main one. So you would still need to create a PR. I can help you but if you tell me where I can go looking for it, that would be helpful. Thanks.

Finally Iā€™ve gotten it to work with Nginx or Apache :slight_smile:

@ coccoinomane
For SCRM 7.11.10 and Nginx web-server try this configuration:

(if it is installed in subdir)

location = /subdir/Api/access_token {    
    try_files $uri $uri/ /subdir/Api/index.php;                            
}            
                                     
location ~ /subdir/Api/V8/(.*?)$ {
   try_files $uri $uri/ /subdir/Api/index.php?$args;
} 

If SCRM installed in root (/) just remove subdir and use root path in the configs above.


There are also considerations to be mention regarding Apache web-server. SCRMā€™s docs donā€™t mention requirements to check whether ā€˜mod_rewriteā€™ module is installed and activated. So one should check it and enable if needed.
Also, AllowOverride directive in Directory directive for the crmā€™s path should changed from None to All.


Some notes re Getting Available Resources path from docs

GET {{suitecrm.url}}/Api/V8/meta/swagger.json

This path is incorrect since PHP scripts do not set up router to handle this path. See comment on Github. The correct path is Api/docs/swagger/swagger.json.

1 Like

Cool :sunglasses: , thanks for that infoā€¦

Can I ask you to please update our API Documentation? Everybody complains that it is inaccurate or incomplete (it is), but then when they solve their problems they donā€™t update itā€¦ itā€™s a wiki. And we are a Community maintained product :wink:

https://docs.suitecrm.com/community/contributing-to-docs/simple-edit/

Thanks!

Ok, I will :wink:

@pgr

Everybody complains that it is inaccurate or incomplete (it is), but then when they solve their problems they donā€™t update itā€¦ itā€™s a wiki.

You should definitely charge them somehow :partying_face:

Edit:
@pgr updated wiki/docs. Pull requests from jt0in3e.

1 Like

After whole night struggling with this same issue I found working solution. Using version 7.11.13
Here is an example:

$url = 'https://your_suite_crm/Api/access_token';
$ch = curl_init($url);
$headers = [
	'Accept: application/vnd.api+json',
	'Content-Type: application/vnd.api+json',
	'cache-control: no-cache'
];
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_HEADER,true);
$post = array(
	"grant_type" => 'client_credentials',
	"client_id" => "yor_client_id",
	"client_secret" => "secret"
);

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post));
$response = curl_exec($ch);

$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);

curl_close($ch);
print_r($response);
3 Likes

Hi All here,

I am new to suiteCRM here. I am trying to get access to API V8 using postman where I can disable ssl.
Now I can use my localhost url http://localhost/newCRM in the curl url.
Rest everything same. But still I am unable to generate the tokenā€¦Here is my code

<?php 

$url = 'http://localhost/newCRM/Api/access_token';
$ch = curl_init($url);

$headers = [
    'Accept: application/vnd.api+json',
    'Content-Type: application/vnd.api+json',
    'cache-control: no-cache'
];

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_HEADER,true);

$post = array(
    "grant_type" => 'client_credentials',
    "client_id" => "1cf78634-0fd2-1ca6-432f-5f352d2b3c2b",
    "client_secret" => "Admin@55"
);

curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post));
$response = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$body = substr($response, $header_size);

curl_close($ch);
print_r($response);

I had this working last December and finally got some free time to come back to developing API integration with one of our Drupal based sites. Iā€™m able to pull an access token but the reply is longer than I recall and the token does not seem to be recognized by the server in subsequent requests (mainly trying the refresh call first before diving into CRUD operations).

This is reply Iā€™m getting to pulling a new token:

string(834) "{"token_type":"Bearer","expires_in":3600,"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjZkNTViZTg0YTk0ZmNlMTZlMjA5MDEzMjJkMjg2MTVlZWVjOTQxMzA5NzUyY2NmYzYxZjhlMGFmMWFkNmNlYjkyNTlhYzM5MTNkN2RkY2VhIn0.eyJhdWQiOiJkNDM1MWI4Mi1kOTJjLTVlZTMtMzAwOC01ZGUyZThhN2YwZjYiLCJqdGkiOiI2ZDU1YmU4NGE5NGZjZTE2ZTIwOTAxMzIyZDI4NjE1ZWVlYzk0MTMwOTc1MmNjZmM2MWY4ZTBhZjFhZDZjZWI5MjU5YWMzOTEzZDdkZGNlYSIsImlhdCI6MTU5NzU1MDE0NywibmJmIjoxNTk3NTUwMTQ3LCJleHAiOjE1OTc1NTM3NDcsInN1YiI6IiIsInNjb3BlcyI6W119.xCYuZ9D-w_esshb_D7e3Kh5mL4ZCutrJCnJEte45p6Kfeffjg8fXxuwVGC0rmZiSnz_t1s_9dBDDSvbr4TSbxb3bPvF9GvK4AOpyD1FMqGp4RGSYiUrOu3VlWrjFW2weFiuSow_t6rsixkOZJMG-Ye-SLpktGM_XOmUFRrQzaAi-kN391luv6gGNoFtjrifmN_8Cc-DdmASsJyyNY7WoJxaQZwVSR_NyIDG7yG6_FQa7NOacubH7Zxb5kl7iMXYTd44nxCg_UgCgmxHxQNTwMAl76-_mY07YP00U2_TTJ8UrZKIehTFyz54kyhJ04lHM71lKAzGn8fwvKq27bScqhg"}"

And then when I try and use that to pass through to refresh I get this error:

string(111) "{"error":"invalid_request","message":"The refresh token is invalid.","hint":"Cannot decrypt the refresh token"}"

Any hints or ideas would be much appreciated (in that Iā€™ll document and publish my API example code!)

-dvd

A little more progress if I base64_decode that response I get another json object with a token that i can see in the database ā€“ but there appears to be extra garbage at the end:

	$token = json_decode($output);
	print_r($token);

	$access = base64_decode($token->access_token);
	print_r($access);
{"typ":"JWT","alg":"RS256","jti":"66c32674e5bc941feb415b71799fc8623ae701bb0e2e6f5a8a21c83a33dbb32f2cc204d96c97b0ca"}Ș]???
?LX?
    ?YL??MYYL?L?

Will try and extract that jti element and see if I can refresh it

-dvd

Progress! Looks like you need to split out the three fields in there separated by dot (ā€™.ā€™) THEN you can base64 decode to get the field:

Explode access_token
Array
(
    [0] => eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjA2YjBmMjUyYjM0ZWI2ZmYyZTc5MGM0MTUwYTk0MjY0MDM5MGQzYjE3YjU1YzY0NGE2MGFiODNjOWQzMjI3N2U4M2E4ODU4YzI5M2Y2ZjhkIn0
    [1] => eyJhdWQiOiJkNDM1MWI4Mi1kOTJjLTVlZTMtMzAwOC01ZGUyZThhN2YwZjYiLCJqdGkiOiIwNmIwZjI1MmIzNGViNmZmMmU3OTBjNDE1MGE5NDI2NDAzOTBkM2IxN2I1NWM2NDRhNjBhYjgzYzlkMzIyNzdlODNhODg1OGMyOTNmNmY4ZCIsImlhdCI6MTU5NzU5MjI1OCwibmJmIjoxNTk3NTkyMjU4LCJleHAiOjE1OTc1OTU4NTgsInN1YiI6IiIsInNjb3BlcyI6W119
    [2] => BxzLJEqdPVJgYpwIi8HmainFZ3xtmJLEfmiFDvqa_XIVXHoSRFd2xJLGqWGqrdBmqlwLSWkAW1Y5ewe9PVNdVwPp_UiYU0msnKTHMX2Egchd0XFgF0KU7-OUtp-L7itEs4lHI_ya5B2ZKIzn4xfE3d-EfKEo1HpTp8__PMMT88l_s0aaGDmdUFqpK1DQxRiTOdKXw7NjYTegF2eH6sxecj0tbRj3XUr921JmhjxqPu9piN5bg02ylsOLzO3C5ERZfUl1HjweDY8wgycvperpx6igBX2cKB_32WEk2DsWbrRZcuqK5ERdQjYOffRKHHI8v23hs-E6B1o1SkFQFMaPxw
)
base64_decode
{"typ":"JWT","alg":"RS256","jti":"06b0f252b34eb6ff2e790c4150a942640390d3b17b55c644a60ab83c9d32277e83a8858c293f6f8d"}Decoding bearer
stdClass Object
(
    [typ] => JWT
    [alg] => RS256
    [jti] => 06b0f252b34eb6ff2e790c4150a942640390d3b17b55c644a60ab83c9d32277e83a8858c293f6f8d
)
JTI = 06b0f252b34eb6ff2e790c4150a942640390d3b17b55c644a60ab83c9d32277e83a8858c293f6f8d

NOTE: still unable to decrypt refresh token ā€“ not sure what I should be passing in ā€“ tried both the base64 version and the jti

Thoughts?

-dvd

PS: found this site that can decode the entire response https://jwt.io/ and it verifies the signature using the public key so i know the server is sending a valid token

If you want to refresh token you get, than you should use grant_type password.
When getting the token with grant_type client_credentials, you get only API token, without refresh token.

I am using this code in Codeigniter library to get refreshable token:

		$url = $this->CI->config->item('crmapi_url')."Api/access_token";
		$ch = curl_init($url);
		$headers = [
			'Accept: application/vnd.api+json',
			'Content-Type: multipart/form-data',
			'cache-control: no-cache'
		];
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_VERBOSE, true);
		curl_setopt($ch, CURLOPT_HEADER,true);
		$post = array(
			"grant_type" => 'password',
			"client_id" => $this->CI->config->item('crmapi_client_id'),
			"client_secret" => $this->CI->config->item('crmapi_oauth_secret'),
			"username" => $this->CI->config->item('crmapi_username'),
			"password" => $this->CI->config->item('crmapi_password')
		);

		curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
		$response = curl_exec($ch);

		$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
		$header = substr($response, 0, $header_size);
		$body = substr($response, $header_size);

		curl_close($ch);

		$res_arr = json_decode($body);
		$this->save_token($res_arr);

		return $res_arr->access_token;

Thanks for the hint! I donā€™t really understand why username/password is required in the first place ā€“ literally every other API I use can work with simple API key + secret.

I personally like this approach, because it allows people to use third party apps (mobile applications/browser extensions and such) without having specific/new passwords.

What are you getting as a response?
Did you tried to set up a local domain and using this domain in url of your request instead of ā€œlocalhost/newCRMā€?
Did you set up a domain in your suitecrm while installation?

Iā€™m getting both keys with the username/password pull and then can use refresh on itā€™s own after that with just the client_id version so itā€™s all good.

(I just cloned the virtual machine of our production instance and spun up a new VM to test against)

I like the approach of giving tools only api keys without having first class user account access to my systems. Like I said, this is probably the first API Iā€™ve encountered that required getting a refreshable key from a set of user credentials versus just being able to use an api-key/secret to manage the access.

In a perfect world your api-keys might have ā€œread-onlyā€ access for some cases where you donā€™t want to allow writes to happenā€¦

Just thinking outloud really ā€“ appreciate you guys jumping in!

-dvd

Hi Everyone Here,

I have worked on the issue. If anybody is facing similar kind of issue Please check this link for the solution.

Thank You

Why the API configuration is so much difficult for SuiteCRM? I worked with so many APIs, but this looks like not an easy task.
Is anyone having step-by-step configuration with screenshots on Linux Environment? I want to use Postman to get the APIs information.

In the documentation youā€™ll find a link to a Postman configuration file. It has everything you need and works right out of the box after you import it into Postman. V8 API was like the first API I ever did and it was pretty straight forward with the config file already done.