I am trying to resolve an azure marketplace subscription using the azure fulfilment api. I have followed the instructions on the Microsoft's SaaS fulfilment api's docs but I am not able to resolve the subscription using PHP.
I am able to get access_token and incidentally I am able to use the token and and use this together with the purchase identification token i get from azure portal when the subscriber is re-directed to the SaaS landing page, to get a successful json response when using postman.
I cannot achieve the same success when using PHP. I get a 403 error - Authorization is missing, incorrect or invalid. I am thinking that the query string bit of authorization parameter is malformed. This has nothing to do with privileges or permissions as I am able to get a successful output on Postman. Here is the code
<?php
use Microsoft\Graph\Graph;
use Microsoft\Graph\Http;
use Microsoft\Graph\Model;
use GuzzleHttp\Client;
class GraphHelper {
private static Client $tokenClient;
private static Client $tokenWebClient;
private static string $clientId = '';
private static string $tenantId = '';
private static string $clientSec = '';
private static string $graphUserScopes = '';
private static Graph $userClient;
private static string $userToken;
private static string $resolveToken;
private static string $subToken= '';
public static function initializeGraphForUserAuth(): void {
GraphHelper::$tokenClient = new Client();
GraphHelper::$clientId = $_ENV['CLIENT_ID'];
GraphHelper::$clientSec = $_ENV['CLIENT_SECRET'];
GraphHelper::$tenantId = $_ENV['TENANT_ID'];
GraphHelper::$graphUserScopes = $_ENV['GRAPH_USER_SCOPES'];
GraphHelper::$userClient = new Graph();
}
public static function getUserToken(): void {
//getting the access token
$accessCodeRequestUrl = 'https://login.microsoftonline.com/'.GraphHelper::$tenantId.'/oauth2/token';
$tokenRequestUrl = 'https://marketplaceapi.microsoft.com/api/saas/subscriptions/resolve?api-version=2018-08-31';
$subToken = $_SESSION['subToken'];
$tokenResponse = GraphHelper::$tokenClient->post($accessCodeRequestUrl, [
'form_params' => [
'client_id' => GraphHelper::$clientId,
'grant_type' => 'client_credentials',
'client_secret' => GraphHelper::$clientSec,
'resource' => '20e940b3-4c77-4b0b-9a53-9e16a1b010a7'
],
// These options are needed to enable getting
// the response body from a 4xx response
'http_errors' => false,
'curl' => [
CURLOPT_FAILONERROR => false
]
]);
if ($tokenResponse->getStatusCode() == 200) {
// Return the access_token
$responseBody = json_decode($tokenResponse->getBody()->getContents());
GraphHelper::$resolveToken = $responseBody->access_token;
$resolveAccessToken= $responseBody->access_token;
} else if ($tokenResponse->getStatusCode() == 400) {
// Check the error in the response body
$responseBody = json_decode($tokenResponse->getBody()->getContents());
if (isset($responseBody->error)) {
$error = $responseBody->error;
// authorization_pending means we should keep polling
if (strcmp($error, 'authorization_pending') != 0) {
throw new Exception('Token endpoint returned '.$error, 100);
}
}
}
//resolving the subscription
$resolveResponse = GraphHelper::$tokenClient->post($tokenRequestUrl, [
'form_params' => [
'content-type' => 'application/json',
'authorization' => 'Bearer '.$resolveAccessToken,
'x-ms-marketplace-token'=> $subToken
],
// These options are needed to enable getting
// the response body from a 4xx response
'http_errors' => false,
'curl' => [
CURLOPT_FAILONERROR => false
]
]);
//test whether there is a reponse
return $resolveResponse->getStatusCode(); // this returns a 403 - Authorization is missing, incorrect or invalid.
}
}
?>
I figured out that I needed to use cUrl for option to include authorization and other headers. Postman did this automatically hence the reason I was able to get results with postman and not with PHP. Eventually this code did it for me.
$subToken = rawurldecode($_SESSION['subToken']);
$ch = curl_init ();
curl_setopt ($ch, CURLOPT_URL, $tokenRequestUrl);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_HTTPHEADER, array ('Authorization: Bearer '.GraphHelper::$resolveToken,
'Content-type: application/json',
'X-ms-marketplace-token:'. $subToken));
curl_setopt($ch, CURLOPT_POST, true);
$results = json_decode (curl_exec ($ch), 1);
if (array_key_exists ('error', $results)){
echo ($results['error']);
die();
}
curl_close($ch);
return $results['subscriptionName'] ;
I found out that the endpoint was not accepting a get request. It threw an error of Subscription resolve not found","target":"subscriptionId","code":"EntityNotFound . However including a post option corrected that and no error was thrown after this. Again when decoding the token from the url - don't use urldecode() use rawurldecode () instead.
Related
I try to set my invision board api with OOAuth but I have always this message { "errorCode": "3S290\/B", "errorMessage": "NO_SCOPES" }"
What I insert inside the application
Client type :
Custom Confidential OAuth Client
A server-side app such as a website where the code will be written in a server-side language and stored on a server that no end-user has access to. A client secret will be issued.
Available Grant Types Required (check all the boxes for my test)
Authorization Code
The end-user will be shown a login screen and redirected back to a specified Redirection URI with an Authorization Code in the query string which you will then exchange for an Access Token.
Implicit
The end-user will be shown a login screen and redirected back to a specified Redirection URI with an Access Token in the fragment.
Resource Owner Password Credentials
The end-user will enter their username or email address and password which you will exchange for an Access Token.
Client Credentials
You will make API calls directly with the Client Identifier and Client Secret without any end-user logging in.
Require PKCE for Authorization Code grant?
Not required
Redirection URIs
https://www.example.com/oauth/callback/
*authorization Prompt
If the user has previously authorized, they will be redirected back immediately, without seeing an authorization screen.
Allow users to choose scopes? and Show in Account Settings? ==> no activated
About the scope :
key : profile
Authorized User : access GET selected
/downloads/categories : acces GET selected
Now about my script
/**
* #return mixed
*/
public function getToken()
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->communityUrl . 'oauth/token/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
'grant_type' => 'client_credentials',
'client_id' => 'xxxxxxxxxxxxx',
'client_secret' => 'xxxxxxxxxxxxx',
]));
// execute cURL
$result = curl_exec($ch);
curl_close($ch);
// decode JSON response
$response = json_decode($result);
return $response->access_token;
}
}
public function getAllCategories()
{
$token = $this->getToken();
if ($token !== null) {
$curl = curl_init($this->communityUrl . 'api' . $this->endpointCategories);
$array = [
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_USERAGENT => "MyUserAgent/1.0",
CURLOPT_HTTPHEADER => array( "Authorization: Bearer {$token}" ),
];
curl_setopt_array($curl, $array);
$response = curl_exec($curl);
$result = json_decode($response, true);
var_dump($response); // the response about the api to display the categories
exit;
return $result;
}
}
I have no idea why I have this message, I suppose there is something happen somewhere
Little help will be welcome
Than you
I want to query the google rest api endpoint to get user contacts:
public static function getContacts(string $token) {
$url = "https://www.google.com/m8/feeds/contacts/default/full?alt=json&max-results=999999";
$opts = [
"http" => [
"method" => "GET",
"header" => "Authorization: Bearer {$token}"
]
];
$response = file_get_contents($url, false, stream_context_create($opts));
$contacts = json_decode($response);
return $contacts;
}
However, the request returns 403 even thought the token is valid and the request works when sending it via Postman.
Use curl to call api. i think it will work fine there.
I have a service, that needs to authenticate via another service.
For this I setup a Middleware that extracts the Authorization header out of my initial request, and then creates a curl request to the Auth Service with the header set.
public function handle($request, Closure $next) {
$authHeader = $request->header('Authorization');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://api.user.eventmanager.app/getAccess");
curl_setopt($ch,CURLOPT_HTTPHEADER,array(
'Authorization: ' . $authHeader,
'Origin: http://api.asdf.rerere.app'
));
$result = curl_exec($ch);
if($result) {
curl_close($ch);
return $next($request);
} else {
curl_close($ch);
return response("Invalid Token or expired Token", 401);
}
}
The request returns the requested ressource as expected, but also adds in the User object in the response (the one I get via the curl request, I want to do further checking with the user object in the middleware, but I dont want it returned to the inital request).
Here is what my controller for the response I want looks like:
public function show($id)
{
$event = Event::with('timeTableEntries', 'venue', 'bands')->find($id);
if(!$event) {
return $this->respondNotFound('Event does not exist!');
}
return $this->respond([
'data' => $this->eventTransformer->transform($event)
]);
}
Somehow the User Object from the curl ends up in my respons.
Any idea why this happens?
You're not returning transfer on your curl options, which stops the response from outputting and returns the string instead.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
as per http://php.net/manual/en/function.curl-setopt.php
I am trying to authenticate a user using the php-github-api library. So far I have sent the user to Github to allow my application access and I successfully get a token back. I'm not sure what to do now. Here is my code.
The URL I send the user to Github with.
https://github.com/login/oauth/authorize?scope=repo,user&client_id=<client_id>
Then with the php-github-api I am doing this. The $token variable is the code that is sent in the $_GET array when the user is redirected to the callback.
$client = new \Github\Client();
try {
$auth = $client->authenticate($token, Github\Client::AUTH_HTTP_TOKEN);
} catch (Exception $e) {
dp($e);
}
Does anyone know if this is the correct method to authenticate a user? When I try and call a method the requires an authenicated user I get a 401 status code and an error in return.
Thanks in advance!
Thanks everyone for their suggestions. Seems like you have to feed the access_token into the authenticate method so an easy fix I implemented was a CURL request to grab the access_token then adding it to the authenticate method in the callback.
$token = $_POST['token'];
$params = [
'client_id' => self::$_clientID,
'client_secret' => self::$_clientSecret,
'redirect_uri' => 'url goes here',
'code' => $token,
];
try {
$ch = curl_init('https://github.com/login/oauth/access_token');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
$headers[] = 'Accept: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
} catch (\Exception $e) {
dp($e->getMessage());
}
Then in the call back we can call the authenticate method to and cache it somewhere, currently I am doing this in the session.
$client = self::getClient();
$_SESSION['access_token'] = $response->access_token;
try {
$client->authenticate($response->access_token, Github\Client::AUTH_HTTP_TOKEN);
} catch (\Exception $e) {
dp($e->getMessage());
}
So there we have it.
I did try using the HttpClient of the php github api library but I was having some issues so chose a more simple solution.
The problem is that you're using the code you receive after the user authenticates as a $token when you're supposed to use it to get an actual token. Make a post request to https://github.com/login/oauth/access_token with the client_id, client_secret, code (what you were using as the token), state, and redirect_uri.
You'll get back a response in this format access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&scope=user%2Cgist&token_type=bearer
There is this code in the HttpClient.php file that would make getting the token easier than cURLing
public function post($path, $body = null, array $headers = array())
{
return $this->request($path, $body, 'POST', $headers);
}
https://developer.github.com/v3/oauth/#github-redirects-back-to-your-site
I've created a custom Provider for Laravel Socialite.
The authentication part is going well until i'll try to call the user method.
Not sure what's going wrong.
Method documentation at wunderlist
My code:
/**
* {#inheritdoc}
*/
protected function getUserByToken($token)
{
$response = $this->getHttpClient()->get('https://a.wunderlist.com/api/v1/users', [
'X-Access-Token: ' . $token . ' X-Client-ID: ' . $this->clientId
]);
return json_decode($response->getBody(), true);
}
I get the following error:
InvalidArgumentException in MessageFactory.php line 202:
allow_redirects must be true, false, or array
Do i miss things in the options array?
Jos
Actually socialite is not supposed to do something like this. But instead you may use Guzzle. There is a good video at laracasts. Just search for Easy HTTP Requests. And here's the code that you may use for guzzle:
$client = new \Guzzle\Service\Client('a.wunderlist.com/api/v1/');
$response = $client->get('user')->send();
// If you want this response in array:
$user = $response->json();
Just read the docs here.
When using this with straight forward curl there is no issue.
As far as i can see the issue lies in the headers i'll parse.
The following solution is something i can live with, although it's not perfect.
$headers = array();
$headers[] = 'X-Access-Token: ' . $token;
$headers[] = 'X-Client-ID: ' . $this->clientId;
$response = $this->getHttpClient()->get('a.wunderlist.com/api/v1/user', [
'config' => [
'curl' => [
CURLOPT_POST => 0,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false
]
]
]);
return json_decode($response->getBody(), true);