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
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 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.
I've got an app which works with Digits as authentication.
Client-side works perfectly, but I'm not able to make the server user authentication through oAuth.
My server is developed with Laravel, so it's PHP.
My endpoint is under https, so everything should be ready to make the call.
I solved by myself!
Here's the code that makes correctly the authentication through Digits O-Auth.
The function that makes authentication is inside an AuthManager class and I call in this way:
$obj = AuthManager::verifyUser($request->header('X-Auth-Service-Provider'),$request->header("X-Verify-Credentials-Authorization"));
And here's the function that makes the magic:
public static function verifyUser ($xAuthServiceProvider, $xVerifyCredentialsAuthorization)
{
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL, $xAuthServiceProvider);
curl_setopt($curl,CURLOPT_HTTPHEADER, array(
'Content-length: 0',
'Content-type: application/json',
'Authorization: '.$xVerifyCredentialsAuthorization,
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$content = curl_exec($curl);
$info = curl_getinfo($curl);
curl_close($curl);
$obj = json_decode($content, true);
return $obj;
}
If you have any problem, don't hesitate to write here!
EDIT WITH EXAMPLE FUNCTION ABOUT HOW TO GET DATA FROM O-AUTH
public function authenticate (Request $request)
{
$obj = AuthManager::verifyUser($request->header('X-Auth-Service-Provider'),$request->header("X-Verify-Credentials-Authorization"));
if(isset($obj["errors"]))
{
return "error!";
}
$digits_token = $obj["access_token"]["token"];
$digitsId = $obj["id"];
/*
the variables above are returned by O-auth server-server authentication
*/
}
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
The manual is unclear as to how to implement this (it assumes you already know what exactly you're doing and in some cases feels like an afterthought), and I've been scratching my head for a fair while trying to figure it out.
The problem: authentication via HTTP auth headers for all API requests
As far as I've been able to test, I can use Basic auth and the normal form based login in CakePHP, but only by first hitting up the login action I define in the Auth component. This is fine when I'm accessing the site directly, and works as expected (with the exception of Digest, which appears to be utterly buggered). Via cURL, though, I've had no luck unless I'm already logged in.
Obviously, for an API, this is far from ideal. I don't want to post a request to /login before doing what I want to do, and I can't expect a user to log in manually so Cake has a cookie to read. It needs to be stateless.
Any attempt to supply authentication credentials along with each request I make (via cURL) is ignored and I get a 403 error in return. Neither the login method or any of the Auth classes are touched.
What do I need to do to make Cake behave like an actual API and allow me to authorise statelessly on a per request basis? Am I going to have to roll my own solution?
I have a centralized API that allows for user authentication via HTTP Digest and requires users to login for many user related functions. The way CakePHP forces a login is by checking if the action requires login, redirecting to your login action (defaults to /users/login), then you can redirect back.
I created my API by doing the following:
//Config/routes.php
///////////////////////////
/**
* Users Controller routes for REST API
*/
Router::mapResources('users');
/**
* Parses extensions for data serialization
*/
Router::parseExtensions();
//Controller/UserController.php
////////////////////////////////
<?php
App::uses('DigestAuthenticate', 'Controller/Component/Auth/');
class UsersController extends AppController {
var $name = 'Users';
//Login callback
function login() {
//dont render for login, just a call back for auth
$this->autoRender = false;
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
}
}
//GET /users.[xml|json]
//this is the basic call that tests user authentication
//basically a login then echo
function index() {
if ($this->Auth->login()) {
$user = $this->Auth->user();
$this->User->id = $user['id'];
$this->User->saveField('last_login', date('Y-m-d H:i:s'));
$this->set('response', array(
'response' => array(
'code' => 'users_auth_success',
'message' => 'User has passed authentication',
'data' => $user
)
));
//will serialize to xml or json based on extension
$this->set('_serialize', 'response');
}
}
}
?>
You can then use this API in something like:
$c = curl_init($uri . '.' . $this->_format);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_USERPWD, $login['user'] . ':' . $login['pass']);
curl_setopt($c, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($c);
$info = curl_getinfo($c);
curl_close($c);
if($info['http_code'] == $this->_http_codes['OK']) {
//success
if($this->_format == 'xml')
$response = Xml::toArray(Xml::build($response));
else//JSON
$response = json_decode($response);
return $response['response']['data'];
} else if($info['http_code'] == $this->_http_codes['Unauthorized']) {
return false;
} else {
return null;
}