Yahoo DSP API Authentication Error: Access Token - oauth-2.0

I have been following the guide to obtain an Access Token for Yahoo DSP API through:
https://developer.yahooinc.com/dsp/api/docs/authentication/vmdn-auth-overview.html
I get to the part Generate a JWT Access Token, and request an access token (with all the headers and paramenters).
When posting a request, I get an error: 'Internal Server error', which in the error codes in the documents says: Try Again Later (without further explanations). I am assuming the request went through and there is something wrong on their side.
Yahoo has no user help suppport. If anyone could please shine some light other than "Try Again Later".
Thank you
#flurry

Unfortunately, Yahoo DSP API docs isn't the most intuitive and straightforward docs there is and it requires a little effort to find and do the right thing.
Although, this collection helped me out when trying to obtain an Access Token from Yahoo DSP API (check the pre-request script):
https://www.postman.com/postman/workspace/postman-team-collections/request/4630964-df7c0fff-babc-420d-ad45-e9e731d5c50f
Not sure in which programming language are you doing the integration for Yahoo DSP API, but if you need a PHP code sample, here's what I used:
$response = $this->httpClient->request(
'POST',
'https://id.b2b.yahooinc.com/identity/oauth2/access_token',
[
'form_params' => [
'grant_type' => 'client_credentials',
'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
'client_assertion' => $this->prepareSignedJWT(),
'scope' => 'dsp-api-access',
'realm' => 'dsp'
],
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded',
]
]
);
Where prepareSignedJWT being:
private function prepareSignedJWT()
{
$header = [
'typ' => 'JWT',
'alg' => 'HS256'
];
$body = [
'aud' => 'https://id.b2b.yahooinc.com/identity/oauth2/access_token?realm=dsp',
'iss' => $this->config->getClientId(),
'sub' => $this->config->getClientId(),
'iat' => time(),
'exp' => time() + 600, // 10 min from time of creation
];
$encodedHeader = base64_encode(json_encode($header));
$encodedBody = base64_encode(str_replace('\/', "/", json_encode($body)));
$token = $encodedHeader . '.' . $encodedBody;
$signature = hash_hmac('sha256', $token, $this->config->getClientSecret(), true);
$encodedSignature = base64_encode($signature);
return $token . '.' . $encodedSignature;
}
And $this->config is just an config object I use in the code.
Hope you find this answer useful, Cheers.

Related

How to fix the 'invalid_grant' error when using Google Photos API

I'm trying to use the Google Photos API (quite a newbie on this). I've managed to go through the authentication/consent process. I stored the authorization code that was returned by Google. On a later moment, I'm trying to use this authorization code to use the Google Photos API. Below a code snippet.
// $clientId and $clientSecret are read from my .json file
// $state was randomly generated, used in the registration process and stored to/read from the database
// $code was stored to the database at the end of te registration process and read from the database to pass in subjoined call
// $redirectUrl and $scope are hard coded for now
$oauth = new OAuth2( [
'clientId' => $clientId,
'clientSecret' => $clientSecret,
'authorizationUri' => 'https://accounts.google.com/o/oauth2/v2/auth',
'state' => $state,
'redirectUri' => $redirectUrl,
'tokenCredentialUri' => 'https://www.googleapis.com/oauth2/v4/token',
'scope' => $scope,
] );
$oauth->setCode( $code );
$credentials = new UserRefreshCredentials(
$this->getScope(),
[
'client_id' => $oauth->getClientId(),
'client_secret' => $oauth->getClientSecret(),
'refresh_token' => $oauth->getRefreshToken()
]
);
$client = new PhotosLibraryClient( [ 'credentials' => $credentials ] );
For the refresh_token, I've tried both $oauth->fetchToken()['access_token'] as well as $oauth->getRefreshToken().
Unfortunately, I get an exception:
guzzlehttp/guzzle/src/Exception/RequestException.php # 113 : Client error: `POST https://www.googleapis.com/oauth2/v4/token` resulted in a `400 Bad Request` response: { "error": "invalid_grant", "error_description": "Bad Request" }
Anyone any idea what could be wrong here?

How to fix getFederationToken returns 403 not authorized error after upgrading from SDK version 1 to 3

We have existing code that uses AWS PHP SDK version 1 AmazonSTS()->get_federation_token(). After upgrading to SDK version 3, the same call using the same credentials, resource and policy returns a 403 not authorized error.
Version and region appear to be the same. The policy json is the same. The user credentials used to make the call are the same (and if I switch back to the SDK v1 they still work). I have the debug option set but it doesn't appear to provide any additional information as to why the same user it not authorized to perform the same function getFederationToken on the same federated user.
Old code that works:
$client = new AmazonSTS();
$policy = new stdClass();
$policy->Statement = [
'Sid' => 'randomstatementid' . time(),
'Action' => ['s3:*'],
'Effect' => 'Allow',
'Resource' => 'aws:s3:::' . $AWS_BUCKET . '*'
];
// Fetch the session credentials.
$response = $client->get_federation_token('User1',array(
'Policy' => json_encode($policy),
'DurationSeconds' => $NUMSECS
));
New code that returns 403 error:
$client = new Aws\Sts\StsClient([
'region' => 'us-east-1',
'version' => '2011-06-15',
]);
$policy = new stdClass();
$policy->Statement = [
'Sid' => 'randomstatementid' . time(),
'Action' => ['s3:*'],
'Effect' => 'Allow',
'Resource' => 'aws:s3:::' . $AWS_BUCKET . '*'
];
try {
$response = $client->getFederationToken([
'Name' => 'User1',
'Policy' => json_encode($policy),
'DurationSeconds' => $NUMSECS,
]);
} catch (Exception $e) {
var_dump($e);
die();
}
The first example returns temporary credentials for the federated user User1.
The second example returns 403 forbidden error (I'm hiding the actual account id):
<Error>
<Type>Sender</Type>
<Code>AccessDenied</Code>
<Message>User: arn:aws:iam::[account id]:user/portal is not authorized to perform: sts:GetFederationToken on resource: arn:aws:sts::[account id]:federated-user/User1</Message>
</Error>
Turns out I was looking at the wrong credentials. I found the correct credentials hard-coded in the script :(

Service now oauth grant flow error with oauth_token.do

I follow the article OAuth authorization code grant flow to get tokens
Initially I made request:
dev234.service-now.com/oauth_auth.do?response_type=code&client_id=****534e4e81b7f
and the response after allowing access to:
http://callback-url?code=Z2YYGhgfh1tMoFPDO7Dr0nZuPnhQPs53qwkm_Sw99gpUf92gU3x_OOuoOqdYBvlPFF01pOfgZg9VoXpCruSRYQ
after that to get token:
dev234.service-now.com/oauth_token.do?grant_type=authorization_code&code=<***>&client_id=<***>&client_secret=<***>
When I did request this, throwing error
{"error_description": "access_denied","error": "server_error"}
Can't I get access_token and refresh_token in json format?
At last worked,
after getting code from earlier steps,i made a php request looks like::
$client = new Client();
$post_data = [
'grant_type' => 'authorization_code',
'code' => 'your code',
'redirect_uri' => '<callback_url>',
'scope' => 'useraccount'
];
$auth = base64_encode('<client_id>:<client_secret>');
$res = $client->request('POST', 'https://myinstance.service-now.com/oauth_token.do', [
'headers' => [
'Authorization' => 'Basic ' . $auth,
'Content-Type' => 'application/x-www-form-urlencoded'
],
'form_params' => $post_data
]);
dd(json_decode($res->getBody(), true));
The response contains accesstoken and refresh token.
Check step two
https://myinstance.servicenow.com/oauth_auth.do?grant_type=code&code={the auth code}&redirect_uri={the_same_redirect_url}&client_id={the_same_client_identifier}
you are using
grant_type=authorization_code

How to make a Guzzle post using query string parameters

In a Google Oauth2 implementation I'm trying to exchange an authorization code for tokens using a guzzle call.
The following guzzle call works fine and returns the expected values:
$result = $this->client->post(
'https://www.googleapis.com/oauth2/v3/token?code=<authorization_code>&redirect_uri=<redirect_uri>&client_id=<client_id>&client_secret=<client_secret>&grant_type=authorization_code')
->getBody()->getContents();
However this seems a dirty way to mount the post request.
I've tried the following way in order make it cleaner:
$result = $this->client->post(
'https://www.googleapis.com/oauth2/v3/token',
[
'query' =>
[
'code' => <authorization_code>,
'redirect_uri' => <redirect_uri>,
'client_id' => <client_id>,
'client_secret' => <client_secret>
'grant_type' => 'authorization_code',
]
]
)->getBody()->getContents();
However this second call generates a Malformed Json error message.
Any idea what I might be doing wrong or how can I debug what final url is being generated in the example above?
I tried without code parameter and it worked.
$client = new \GuzzleHttp\Client();
$response = $client->post('https://www.googleapis.com/oauth2/v3/token', [
'query' => [
'client_id' => '...apps.googleusercontent.com',
'client_secret' => 'secret',
'refresh_token' => 'token',
'grant_type' => 'refresh_token'
]
]);
$token = $response->getBody()->getContents()
Have you tried using arrays and http://php.net/json_encode

Failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request - OAuth 2.0 POST

I am working with YouTube APIs for my college project, and I keep getting an error. Here I send them to the authorisation page to log in, when they allow access it sends the $_GET['code'] string back. Then I send this along with some other data and it should send back a JSON object. Instead I am just getting
Warning: file_get_contents(https://accounts.google.com/o/oauth2/token)
[function.file-get-contents]: failed to open stream: HTTP request
failed! HTTP/1.0 400 Bad Request in http://www.example.net/callback.php on line 27
I have replaced my domain with example.net just for security
urlencode($_GET['code']),
'client_id' => urlencode('111522767640.apps.googleusercontent.com '),
'client_secret' => urlencode('secret'),
'redirect_uri' => urlencode('http://example.net/callback.php'),
'grant_type' => urlencode('authorization_code')
)
);
$params =
array('http' =>
array(
'method' => 'POST /o/oauth2/token HTTP/1.1',
'header' => 'Host: accounts.google.com\r\n'.
'Content-Type: application/x-www-form-urlencoded',
'content' => $postdata
)
);
$context = stream_context_create($params);
$result = file_get_contents('https://accounts.google.com/o/oauth2/token', false,$context);
var_dump($_SESSION);
var_dump($result);
}
else //If code isnt set, user must have come here erroniously or has denied access to this program
{
//header( 'Location: www.example.net/error.php' ) ;
}
?>
file_get_contents is going to make a GET request to the url specified, but oauth2/token needs a POST request.
See reference Google OAuth2, PHP HTTP.
if you are using oauth2, goto libraries/oauth2/provider.php and uncomment the code line 182 shows
$ci = get_instance();
$ci->load->spark('curl/1.2.1');
$ci->curl
->create($url)
->post($params, array('failonerror' => false));
$response = $ci->curl->execute();
Here's how to do the Google oAuth properly:
$config = (object) array(
'CLIENT_ID' => 'AAAAA',
'CLIENT_SECRET' => 'BBBBB',
'REFRESH_TOKEN' => 'CCCCC',
);
$sJSON = file_get_contents('https://www.googleapis.com/oauth2/v4/token',FALSE,
stream_context_create(array('http'=>array(
'ignore_errors' => TRUE, // see errors in response instead of empty on error
'method' => 'POST',
'header' => array(
'Content-Type: application/x-www-form-urlencoded'
),
'content' => http_build_query(array(
'grant_type' => 'refresh_token',
'client_id' => $config->CLIENT_ID,
'client_secret' => $config->CLIENT_SECRET,
'refresh_token' => $config->REFRESH_TOKEN
))
)))
);
You can then use json_decode() to parse $sJSON into an object and then retrieve the access_token property.
For those who are wondering how to get the CLIENT_ID, CLIENT_SECRET, and REFRESH_TOKEN, watch this video. It's not easy. In my case, I needed to do this for Google Adwords API. So, I had to get my Developer Token and Login Customer ID from https://ads.google.com/home/tools/manager-accounts. Then, I had to go to https://console.developers.google.com/apis/credentials with this guide to generate a Client ID and Client Secret. Then, I followed this guide to learn how to get my Refresh Token.

Resources