YouTube oauth connection - php

I try to create a oauth connection to get data from user's channel views. I begin my request like this:
public function getAuthorizationUrl()
{
// Make redirect
$this->params = [
'client_id' => '###########&',
'redirect_uri' => '########&',
'scope' => 'https://www.googleapis.com/auth/yt-analytics.readonly&',
'response_type'=> 'code&',
'access_type' => 'offline'
];
$redirect_url = 'https://accounts.google.com/o/oauth2/auth?' . http_build_query($this->params);
return $redirect_url;
}
But sadly I fail right from the start, because I get this error:
Error: invalid_request
Invalid response_type: code&
Request Details
access_type=offline
scope=https://www.googleapis.com/auth/yt-analytics.readonly&
response_type=code&
redirect_uri=#####&
client_id=######&
Any ideas why I get this error? Any help is welcomed, thank you all for your time!

Error says you have an invalid parameter in there (response type). Have you tried removing those trailing ampersands? http_build_query should take care of that for you

Related

Azure B2C with OpenID Connect and PKCE

I'm trying to make an Azure B2C login with Laravel, I'm halfway there right now.
The Laravel part is an API, and the client is in Angular. I've planned to make the whole process on the BE. When a user clicks "Sign in with Microsoft" to be redirected to the BE server-side page and I do the magic on the BE. In the end, I want to make a redirect to some FE page and set the access token in the cookie.
I've defined two web.php (server-side) routes. The first one is for redirecting away to the Azure login and the second one is for a callback.
Here is the code:
public function redirect()
{
$length = mt_rand(43, 128);
$bytes = random_bytes($length);
$codeVerifier = rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
$state = Str::random(40);
$query = http_build_query([
'p' => 'B2C_1A_SIGNIN',
'client_id' => config('services.azureadb2c.client_id'),
'redirect_uri' => config('services.azureadb2c.redirect'),
'response_type' => 'code',
'scope' => 'openid',
'state' => $state,
'prompt' => 'login',
'code_challenge' => $this->generateCodeChallenge($codeVerifier),
'code_challenge_method' => 'S256',
]);
session(['state' => $state, 'code_verifier' => $codeVerifier]);
return redirect('https://' . config('services.azureadb2c.domain') . '.b2clogin.com/' . config('services.azureadb2c.domain') . '.onmicrosoft.com/b2c_1a_signin/oauth2/v2.0/authorize?' . $query);
}
public function callback(Request $request)
{
$client = new Client();
$response = $client->post("https://" . config('services.azureadb2c.domain') . ".b2clogin.com/" . config('services.azureadb2c.domain') . ".onmicrosoft.com/b2c_1a_signin/oauth2/v2.0/token?p=B2C_1A_SIGNIN", [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => config('services.azureadb2c.client_id'),
'client_secret' => config('services.azureadb2c.client_secret'),
'code' => $request->get('code'),
'redirect_uri' => config('services.azureadb2c.redirect'),
'code_verifier' => session('code_verifier'),
'scope' => 'openid',
],
]);
var_dump(json_decode($response->body()));
exit;
}
private function generateCodeChallenge($codeVerifier) {
$hash = hash('sha256', $codeVerifier, true);
$codeChallenge = rtrim(strtr(base64_encode($hash), '+/', '-_'), '=');
return $codeChallenge;
}
Here, I'm facing the next problem. Redirect is working well, the user is redirected properly and he can enter the credentials well and everything. At the end in the callback, I receive the authorization code, but when I make a POST request to get the access token I get the next error
`400 Bad Request` response: {"error":"invalid_grant","error_description":"AADB2C90085: The service has encountered an internal error. Please reauthe (truncated...)
Do you have any idea what can cause this error?
I tried to reproduce the same in my environment via Postman and got below results:
I registered one Azure AD B2C application by selecting SPA in redirect URIs like below:
I ran below c# code by Bac Hoang [MSFT] from this blog and got values of code_challenge and code_verifier successfully as below:
using IdentityModel;
using System.Security.Cryptography;
using System.Text;
namespace PKCEConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var random = new Random();
int cvlength = random.Next(43, 128);
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
var codeVerifier = new string (Enumerable.Repeat(chars, cvlength).Select(s => s[random.Next(s.Length)]).ToArray());
string codeChallenge;
using (var sha256 = SHA256.Create())
{
var a = Encoding.UTF8.GetBytes(codeVerifier);
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
codeChallenge = Base64Url.Encode(challengeBytes);
}
Console.WriteLine("codeVerifier " + codeVerifier + "\n");
Console.WriteLine("codeChallenge " + codeChallenge + "\n");
Console.ReadLine();
}
}
}
Response:
Now, I ran below authorization request in browser and got code successfully like this:
https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/authorize?
client_id=742978eb-ccb4-4b82-8140-3526417d4d09
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=openid
&code_challenge=l-kik2UPt2cInWJK6liasiRBhdpNm3qeOqUma_4Ih7E
&code_challenge_method=S256
Response:
When I tried to generate tokens via Postman with below parameters, I got only id_token and refresh_token without access token like below:
POST https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/token
client_id:742978eb-ccb4-4b82-8140-xxxxxxxxxx
grant_type:authorization_code
scope:openid
code: <paste code from above step>
redirect_uri: https://jwt.ms
code_verifier:hMl0zyCvyUKJxS1gjOPqFNf1LPQ~tcvekFJeWsfzFGSFMi5~QkpCAq1QHMDT3N
Response:
To get access token, add new scope by exposing an API like below:
Now, add this scope in your application that will come under Delegated permissions like below:
Make sure to grant admin consent to the above scope like below:
Now, generate code again by running below authorization request in browser like this
https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/authorize?
client_id=742978eb-ccb4-4b82-8140-xxxxxxxxxx
&response_type=code
&redirect_uri=https://jwt.ms
&response_mode=query
&scope=https://sritenantb2c.onmicrosoft.com/742978eb-ccb4-4b82-8140-xxxxxxxxxx/.default
&code_challenge=l-kik2UPt2cInWJK6liasiRBhdpNm3qeOqUma_4Ih7E
&code_challenge_method=S256
Response:
I generated access token successfully using below parameters via Postman like below:
POST https://sritenantb2c.b2clogin.com/sritenantb2c.onmicrosoft.com/B2C_1_Signin/oauth2/v2.0/token
client_id:742978eb-ccb4-4b82-8140-xxxxxxxxxx
grant_type:authorization_code
scope: https://sritenantb2c.onmicrosoft.com/742978eb-ccb4-4b82-8140-xxxxxxxxxxx/Admin.Read openid
code: <paste code from above step>
redirect_uri: https://jwt.ms
code_verifier:hMl0zyCvyUKJxS1gjOPqFNf1LPQ~tcvekFJeWsfzFGSFMi5~QkpCAq1QHMDT3N
Response:
When I decoded the above access token in jwt.ms, I got the scp claim like below:

FedEx Api: Bad Request Error, Missing or duplicate parameters. Please modify your request and try again

For some reason, I'm getting a 400 Bad Request error when I'm sending my authentication to FedEx for my API.
Here is my code:
$payload = [
'grant_type' => 'client_credentials',
'client_id' => self::$apiKey,
'client_secret' => self::$apiSecret
];
$api = new App_ApiTransaction('POST', self::$authEndpoint, $payload, App_ApiTransaction::ENCODE_JSON);
$api->addHeader( 'Content-Type', 'application/x-www-form-urlencoded');
I tried using GET, but I was getting a 405 error. Also, this is a custom header function.
What could be causing the issue?
Thank you,
Kevin
Found the solution, here is what I had to do:
$payload = ('grant_type=client_credentials&client_id='.self::$apiKey.'&client_secret='.self::$apiSecret);
Basically changed the Payload to the correct format

Outlook - OAuth 2 - Fail to retrieve access token, grant_type=password is unsupported, only authorization_code and refresh_token are

I'm currently trying to implement a way to synchronize my PHP App calendar with the Outlook calendar of my clients, using Azure API.
I use OAuth2 and the custom Microsoft provider by Steven Maguire.
I currently run in an issue where I get an error in my response :
{"error":"unsupported_grant_type","error_description":"The provided value for the input parameter 'grant_type' is not valid. Expected values are the following: 'authorization_code', 'refresh_token'."}
I'm having trouble understanding why the grant_type password is not supported, even though it says on the documentation of Azure that it is.
The request looks like this :
client_id=44bef79b-**********************&client_secret=H****************&redirect_uri=https%3A%2F%2F192.168.1.123%2Fmapeyral%2Fcalendarsync.php&grant_type=password&username=******************&password=***********&scope=openid%20profile%20offline_access%20Calendars.ReadWrite
The Authorize url used is : https://login.live.com/oauth20_token.srf
as defined in the Steven Maguire provider.
The header contains the content-type application/x-www-form-urlencoded (I've seen a lot of post where this was what caused the error).
Some of my code :
$this->provider = new Microsoft([
'clientId' => MicrosoftGraphConstants::CLIENT_ID,
'clientSecret' => MicrosoftGraphConstants::CLIENT_SECRET,
'redirectUri' => MicrosoftGraphConstants::REDIRECT_URI,
'urlAuthorize' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::AUTHORIZE_ENDPOINT,
'urlAccessToken' => MicrosoftGraphConstants::AUTHORITY_URL . MicrosoftGraphConstants::TOKEN_ENDPOINT,
'urlResourceOwnerDetails' => MicrosoftGraphConstants::RESOURCE_ID,
'scope' => MicrosoftGraphConstants::SCOPES
]);
if ($_SERVER['REQUEST_METHOD'] === 'GET' && !isset($_GET['code']))
{
// Try getting access token from Database
$workingAccount = $GLOBALS['AppUI']->getState('working_account');
if (isset($workingAccount))
{
// DB access
$DB = new DatabaseConnection();
$dbAccess = $DB->getConnection();
$contactData = DBUserUtils::getContactDataFromEmail($GLOBALS['AppUI']->getState('working_account'), $dbAccess);
// If at least one user contact found
if (!is_null($contactData))
{
// If has refresh token => fill session variables using refresh token
if (!is_null($contactData['contact_refreshToken']))
{
log_msg('debug.log', 'Has refresh token');
$GLOBALS['AppUI']->setState('preferred_username', $contactData['contact_email']);
$GLOBALS['AppUI']->setState('given_name', $contactData['contact_first_name']." ".$contactData['contact_last_name']);
// Get new tokens
$newAccessToken = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $contactData['contact_refreshToken']
]);
// Update tokens and DB
$GLOBALS['AppUI']->setState('refresh_token', $newAccessToken->getRefreshToken());
$GLOBALS['AppUI']->setState('access_token', $newAccessToken->getToken());
DBOAuthUtils::updateTokenForUser($contactData['contact_id'], $GLOBALS['AppUI']->getState('refresh_token'), $dbAccess);
$this->redirectTo($redirectURL);
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
}
else
{
$this->getAccessToken();
}
function getAccessToken(){
$accessToken = $this->provider->getAccessToken('password', [
'username' => '*************',
'password' => '********',
'scope' => MicrosoftGraphConstants::SCOPES
]);
}
During the first try it doesn't pass the if (isset($workingAccount)) condition (as expected) and go straight to the last else.
Code is a bit ugly for now but I don't think it has an impact on my problem.
Any help would be appreciated !
Thanks
Edit : added code
That helped me, the problem was that I need to use Azure Active Directory and not Azure AD 2.0.
Problem solved !

Something about Oauth2-server's JWT Access Tokens and JWT bearer

Uh..I'm not sure what's wrong with my code.
Q1.
I made reference to the oauth2-server's demo.
And using Memory storage can work But when I try Pdo storage.
I get the "500 Internal Server Error" and "Unexpected character (<) at position 1."
Server
$storage = new OAuth2\Storage\Pdo(array(
'dsn' => $dsn,
'username' => $username,
'password' => $password));
$this->server = new OAuth2\Server($storage, array(
'use_jwt_access_tokens' => true,
));
$this->server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage));
Token
public function token_post(){
$this->server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
}
Q2.
In JWT Bearer page
I can get access_token with demo,but this access_token don't work.
alway get "Failed" With resource page
resource
public function resource_get()
{
if (!$this->server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) {
exit("Failed");
}
echo json_encode(array('success' => true, 'message' => 'You accessed my APIs!'));
}
Q3.
I have no idea about what is the different between JWT Access Tokens and JWT Bearer to use?
Remark
Sorry for bad English.
I use Google'translation to help me completion of these.
So i can't use realy correct description.
Sorry again for bad English.

Facebook PHP SDK: Uncaught OAuthException: This authorization code has been used

I'm using the following sections of code to try and authenticate against Facebook using the official PHP SDK:
public function get_login_url() {
$login = $this->facebook->getLoginUrl(array('scope' => 'publish_stream, email, publish_actions','redirect_uri' => 'http://www.sociaspire.com/lib/ajax/facebook-callback.php'));
return $login;
}
public function get_access_token($auth_code) {
$token_request_params = array(
'client_id' => $this->app_id,
'redirect_uri' => "http://www.sociaspire.com/lib/ajax/facebook-callback.php",
'client_secret' => $this->app_key,
'code' => $auth_code,
);
$token_request = $this->facebook->api('oauth/access_token?','GET',$token_request_params);
}
My flow is such that I call get_login_url, navigate to that URL and I am then redirected back to my callback URL, where I should be able to exchange the code Facebook gives for a (short-lived) access token, however when I attempt to get the access token, the API throws:
OAuthException: This authorization code has been used
I'm not sure why, as I haven't made any other requests with the code.
If anybody could help I would be grateful!

Categories