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!
Related
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:
I want to connect Instagram Basic Display API with a website in order to display one user's post. But, when trying to authenticate the user (myself, for test purposes) I'm getting this error:
{"error_type": "OAuthException", "code": 400, "error_message": "Invalid redirect_uri"}
This is the PHP code I'm using for my request:
require_once 'ig_defines.php';
Class instagram_basic_display_api {
private $_appId = INSTAGRAM_APP_ID;
private $_appSecret = INSTAGRAM_APP_SECRET;
private $_redirectUrl = INSTAGRAM_APP_REDIRECT_URI;
private $_getCode = '';
private $_apiBaseUrl = 'https://api.instagram.com/';
public $authorizationUrl = '';
// called on class init
function __construct( $params ) {
// save instagram code
$this->_getCode = $params['get_code'];
// get an access token (code will follow)
// get authorization url
$this->_setAuthorizationUrl();
}
private function _setAuthorizationUrl() {
$getVars = array(
'app_id' => $this->_appId,
'redirect_uri' => $this->_redirectUrl,
'scope' => 'user_profile,user_media',
'response_type' => 'code'
);
// create url
$this->authorizationUrl = $this->_apiBaseUrl . 'oauth/authorize?' . http_build_query( $getVars );
}
}
private $_redirectUrl = INSTAGRAM_APP_REDIRECT_URI; is "http://google.com/" as suggested in this post. My OAuth Redirect URI in the facebook developer tools Instagram API settings is "http://google.com/" as well.
For testing I'm using my test webspace. The URL is something like http://mytestwebspace.de/instagram/news_ig_test.php. As you can see, it doesn't have SSL. The final page is going to, though. Could the lack of SSL be an issue?
EDIT: I forgot to add, I did try using http://mytestwebspace.de/instagram/news_ig_test.php as redirectUrl before, but I'm still getting the same error.
I'm not sure what the reason could be.
I can confirm, SSL is required. When using https://mytestwebspace.de/etc... , authentication works just fine. (Though it's not surprising, I didn't quite expect the solution to be that simple, thus why I opened a thread.)
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 !
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
I have offline_access and manage_pages permission but I keep getting all sorts of OAuth errors - with the code below I get
Fatal error: Uncaught OAuthException: Error validating access token:
The session has been invalidated because the user has changed the
password.
I saved both the user access token and the page access token in a database and then try to use it to update a page the user is admin of when the user is offline. I cannot seem to make this work:
$access_token = User token got when user was logged in;
$news_token = Page token got when user was logged in;
// $accounts_url = "https://graph.facebook.com/me/accounts?" . $access_token;
$page_info = $facebook->api("/$news_page?fields=access_token");
$args = array(
'access_token' => $news_token,
'message' => $u,
'link' => $news_url,
'description' => $u,
'name' => $news_title,
'picture' => $image
);
$post_id = $facebook->api("/$page_id/feed","post",$args);
echo $news_source."(Offline): ".$u."<br />\n";
The commented out line above shows another thing I tried to no avail.
Can anybody help?
offline_access is deprecated.
http://developers.facebook.com/roadmap/offline-access-removal/