Since few days, I'm unable to get a token from Microsoft Bot Framework Web Chat API.
I do a GET request to https://webchat.botframework.com/api/tokens with PHP. I set the header Authorization to BotConnector MY_SECRET :
$options = array('http' => array(
'method' => 'GET',
'header' => 'Authorization: BotConnector ' . $secret
));
$context = stream_context_create($options);
$token = file_get_contents('https://webchat.botframework.com/api/tokens', false, $context);
The server answer is: "HTTP request failed! HTTP/1.1 405 Method Not Allowed".
My secret key is valid, I try also with a POST request but the server answers the same result.
If I call the Web Chat iFrame with my Secret Key, all works great but it's not secure.
This was a temporary bug/regression, I reported it and it's now fixed. The service should work as documented.
https://github.com/Microsoft/BotBuilder/issues/1556#issuecomment-257333517
Related
I'm trying to write a custom web app that utilizes the Microsoft Identity Platform to authenticate and authorize users. I'm able to successfully authenticate when calling the /authorize endpoint, and I have access to the "code" token that is returned.
I am now trying to retrieve my access token so that I can make calls to the APIs. Whenever I submit a POST request to the /token endpoint, the server returns a 400 Bad Request error. The header information that is provided contains no valuable information for troubleshooting and there is no JSON response returned so I have no idea where or what the issue is.
I'm making my call as follows:
$clientId = '00000000-0000-0000....'; // Omitted
$tenantId = '00000000-0000-0000....'; // Omitted
$grantType = 'authorization_code';
$scope = urlencode('User.Read');
$code = '......' // Obtained from authentication
$redirect_uri = 'http://localhost/smp/auth/handle';
$clientSecret = '...' // Omitted, set up in Azure App registrations under Certificates and secrets
$resource = 'api://00000000-0000-0000....'; // Omitted, set up in Azure App registrations under Overview -> App ID URI
$url = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token";
$parameters = [
'client_id' => $clientId,
'grant_type' => $grantType,
'scope' => $scope,
'code' => $code,
'redirect_uri' => $redirectUri,
'client_secret' => $clientSecret,
'resource' => $resource
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($parameters)
]
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if (!$result) {
exit('an error has occured');
}
PHP returns a warning that reads the following: (tenant id has been omitted):
Warning: file_get_contents(https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/oauth2/v2.0/token): Failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in C:\xampp\htdocs\smp\application\models\user-model.php on line 261
I've verified everything I can possibly think of.
The client and tenant ids are working (based on the successful authentication request).
The "code" is correctly retrieved from the authentication request.
Redirect Uri is the same as the one used for the authentication request.
I've tried with and without the client_secret variable. It is my understanding that this is actually required in my case.
I've tried with and without the resource variable, which is setup using the default Azure naming convention of "api://".
Please assist! I know I must be missing something but cannot figure it out. Perhaps permissions or additional setup within Azure? I'm not really sure what's wrong with my code/approach but Microsoft Identity Platform/OAuth isn't returning anything for me to work with and/or troubleshoot.
I've figured this out.
Firstly, I modified by $options variable to include the following:
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($parameters),
'ignore_errors' => true
]
];
Adding ignore_errors allowed me to see the returned JSON.
Next, it became apparent that my parameters were not being accepted because I was url-encoding all of them. My client secret, redirect uri, and client ids were all url encoded (this detail was hidden in my original post because it was just a small snippet of a much larger system). By undoing this encoding, my parameters all ended up being accepted. I suppose it makes sense because these values weren't being appended to a url but rather passed as POST values.
Lastly, the "resource" variable was not accepted (indeed, it wasn't required). Not sure if any of this is going to help anyone else but just in case, this was my fix.
I tried using the library from krizalys for an implementation to read and write files from OneDrive. It should work for business accounts but would be nice if it could also work for personal accounts.
Since I read that the Live SDK used in krizalys example will be offline soon (as mentioned here), I tried implementing Microsoft Graph instead.
I implemented two ways to get an access token at the moment, one with grant type password (getAccessToken Method from this sample used) and one with client_credentials (Like in the krizalys lib). Both seem to work and return an access_token and refresh_token, but when I try to make a request I get the message:
"InvalidAuthenticationToken [message] => Access token is empty"
The code for my request:
$data = array("name" => "test");
$url = "https://graph.microsoft.com/v1.0/me/drive/root";
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', $url, [
'headers' => [
'Authorization: Bearer ' . $this->_state->token->data->access_token,
'Content-Type: application/json',
'Content-Length: ' .strlen(json_encode($data))
],
'body' => json_encode($data),
]);
I also tried it with the GET method and added the Host: graph.microsoft.com to ensure that this is not the problem:
$url = "https://graph.microsoft.com/v1.0/me";
$client = new \GuzzleHttp\Client();
$response = $client->request('GET', $url, [
'headers' => [
'Authorization: Bearer ' . $this->_state->token->data->access_token,
'Host: graph.microsoft.com'
],
]);
The token response payload looks like this:
The application is configured at https://apps.dev.microsoft.com and the permissions are set. Is there anything wrong with my request? I have no idea why I always get the InvalidAuthenticationToken message. Thanks.
You've registered your application in the v2 Endpoint (apps.dev.microsoft.com) but the sample code you're using is for the v1 Endpoint. These are not interchangeable. Also, password isn't a valid OAuth Grant for the v2 Endpoint (v2 supports authorization_code, implicit, and client_credentials)
You need to obtain your token from the v2 Endpoint. You might find these articles helpful:
Microsoft v2 Endpoint Primer.
Azure AD v2.0 Overview
I'm sending a request to my API like so:
$context = stream_context_create(
array(
'ssl' => array('verify_peer' => false, 'allow_self_signed' => true),
'http' => array('method' => 'GET', 'header' => "Authorization:Basic " . base64_encode($token.':'))
)
);
$resp = file_get_contents('https://api.site.com/test', false, $context);
if(!preg_match("/200 OK/", $http_response_header[0])) http_response_code(400);
else echo $resp;
However, I am trying to let api.site.com to know what my HTTP_USER_AGENT is that's making the request.
What's the best way to accomplish this?
Add the User-Agent header along side your Authorization:Basic in the stream context options under the http key. See http://php.net/manual/en/context.http.php for details
Edit: Google App engine information
Headers identifying request source
The following headers indicate the app ID of the requesting app:
User-Agent. This header can be modified but App Engine will append an identifier string to allow servers to identify App Engine requests. The appended string has the format "AppEngine-Google; (+http://code.google.com/appengine; appid: APPID)", where APPID is your app's identifier.
X-Appengine-Inbound-Appid. This header cannot be modified, and is added automatically if the request is sent via the URL Fetch service when the follow redirects parameter is set to False.
How to send a POST request with Basic Authentication from Appengine in PHP?
I already checked Issue FORM POST Request From PHP using HTTP Basic Authentication but solution is not working in Appengine environment.
Please suggest any workaround. Thanks.
The solution you posted uses sockets, which will only work if you have billing enabled (See https://developers.google.com/appengine/docs/php/sockets/).
Alternatively, you could use file_get_contents with the "Authorization" header set in the stream context (https://developers.google.com/appengine/docs/php/urlfetch/), e.g.
$context =
array("http"=>
array(
"method" => "post",
"header" => "Authorization: Basic " . base64_encode($username.':'.$password) . "\r\n",
"content" => $data
)
);
$context = stream_context_create($context);
$result = file_get_contents(url, false, $context);
I try to connect to google API and it returns:
failed to open stream: HTTP request failed! HTTP/1.0 401 Unauthorized
I requested for access token and it returned me xxx, after that I connect to Google API by following PHP code:
$opts = array('http' =>
array(
'method' => 'GET',
'header' => "Authorization: OAuth $access_token\r\nContent-Type: application/json\r\n",
)
);
$context = stream_context_create($opts);
$result = file_get_contents('https://www.googleapis.com/userinfo/email?alt=json',false,$context);
Where is mistake did I write wrongly headers, or something else?
Update: $access_token is a value which I got in json by requesting it.
You don't need the content type header for a GET request.
You need to query this URL to get the User Info: https://www.googleapis.com/oauth2/v2/userinfo
Make sure that the $access_token value contains an correctly authorized access token, for that you need your user to go through an OAUth 2.0 flow.
All of this is all documented there: https://developers.google.com/accounts/docs/OAuth2Login
Check how to do it in php, but when logging your client to Google you must set the RequestPermission parameter so you can get info from user's profile
requestPermissions: 'https://www.googleapis.com/auth/userinfo.profile'