I'm using Xero OAuth2.0 APIs, I am refreshing token once token is expired.
Xero Documentation
I'm storing token in JSON file so i can retrive next time.
Erorr Response:
{
"error": "invalid_grant"
}
Please refer below code i've used
public function getAccessToken($code = null) {
if(file_exists($this->tokenPath) && isset($code)) {
$accessToken = $this->getAccessTokenFromAuthCode($code);
} else if (file_exists($this->tokenPath)) {
$accessToken = $this->getAccessTokenFromJSON();
try {
if (time() > $accessToken->expires) {
$accessToken = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $accessToken->refresh_token
]);
}
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
//header('Location: ' . $this->getAuthorizationUrl());
}
} else if(isset($code)){
$accessToken = $this->getAccessTokenFromAuthCode($code);
} else {
header('Location: ' . $this->getAuthorizationUrl());
}
return $accessToken;
}
public function getAccessTokenFromAuthCode($code) {
return $this->storeAccessTokenToJSON($this->provider->getAccessToken('authorization_code', ['code' => $code]));
}
public function getAccessTokenFromJSON(){
return json_decode(file_get_contents($this->tokenPath));
}
public function storeAccessTokenToJSON($accessToken){
file_put_contents($this->tokenPath, json_encode($accessToken));
return json_decode(file_get_contents($this->tokenPath));
}
The expiration for an access token is 30 minutes. And Unused refresh tokens expire after 60 days. If you don’t refresh your access token within 60 days the user will need to reauthorize your app.
If you perform a token refresh successfully you get a new refresh token with the new access token
If for whatever reason, you don't receive the response after performing the token refresh you can retry refreshing the old token for a grace period of 30 minutes
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://identity.xero.com/connect/token?=",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => array(
'XXXXXXXXXXXXX','client_secret' =>
'YYYYYYYYYYYYYYYYYYYYYYYYYYYYY'),
CURLOPT_HTTPHEADER => array(
"grant_type: refresh_token",
"Content-Type: application/json",
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
Did you specify the 'offline_access' scope when you got your initial token?
https://developer.xero.com/documentation/guides/oauth2/scopes#offline-access
Invalid_grant is the standard error response code when a refresh token has expired.
Common token lifetimes are something like:
* Access token = 60 minutes
* Refresh token = 8 hours
When the refresh token expired you have to get the user to log in again.
Related
this my method
public function postOrUpdateProductRd($payload)
{
$payload = json_encode($payload);
$access_token = $this->authenticate->result->access_token;
$this->header = [
'content-type' => 'application/json',
'Authorization' => ' Bearer ' . $access_token,
];
$response = Http::withHeaders($this->header)->post($this->urlBase . $this->endPoint, $payload);
}
How could I save the token I get there to use it until it expires. And how to check if it is expired?
it comes like this when I run the request:
^ {#46
+"token_type": "bearer"
+"access_token": "zurUe8QF386NSyljiTbkXCdcUAZ8rIal"
+"expires_in": 7200
}
I need to store the token somehow to use until it requests a new one as it has expired.
I'm a beginner at this sorry if I was reductive.
Using the authentication plugin, I'm unable to verify my credentials via json. I can use Form, Jwt and Basic(For testing it works). The error returned is 'FAILURE_CREDENTIALS_INVALID'. Here's the sample code "simplified for brevity"
public function token()
{
$result = $this->Authentication->getResult();
if ($result->isValid()) {
//new jwt token etc
$message = true;
$this->log($result->getStatus());
}else{
$message = false;
$this->log($result->getStatus());
}
$this->set([
'message' => $message,
]);
$this->viewBuilder()->setOption('serialize', ['message']);
}
My application class has the method
public function getAuthenticationService(ServerRequestInterface $request) : AuthenticationServiceInterface
{
$service = new AuthenticationService();
$service->setConfig([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect',
]);
$fields = [
'username' => 'email',
'password' => 'password'
];
// Load the authenticators, you want session first
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login'
]);
//Testing jwt
$service->loadAuthenticator('Authentication.Jwt', [
'secretKey' => Security::getSalt()]);
// Load identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));
$service->loadIdentifier('Authentication.JwtSubject');
return $service;
}
The app is serving some json well if I pass in the jwt, but somehow I can't figure out how to request a new one, when the old expires.
Here's my middlewareQueue:
//some code
$middlewareQueue
->add(new ErrorHandlerMiddleware(Configure::read('Error')))
->add(new AssetMiddleware([
'cacheTime' => Configure::read('Asset.cacheTime'),
]))
->add(new RoutingMiddleware($this))
->add($csrf)
->add(new BodyParserMiddleware())
->add(new AuthenticationMiddleware($this));
//more code
I DO NOT use basic
As mentioned in the comments, if you want to authenticate using the form authenticator on your token retrieval endpoint, then you need to make sure that you include the URL path of that endpoint in the authenticators loginUrl option.
That option accepts an array, so it should be as simple as this:
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => [
'/users/login',
'/api/users/token.json',
],
]);
The error that you were receiving was because the form authenticator simply wasn't applied on the token endpoint, and therefore the authentication service would go to the next authenticator, the JWT authenticator, which isn't bound to a specific endpoint, and therefore can run for all endpoints, and the JWT authenticator of course expects a different payload, it looks for a token, and if it can't find it, it will return the error status FAILURE_CREDENTIALS_INVALID.
I'm issuing some problems with Laravel/Passport while trying to test the auth flow of my application...
The stranger thing is that it only happens when I'm on testing env. The expects the 200 http code but instead receive a 500.
I'm using the Laravel 5.8 version, I'm also have installed Horizon and Telescope. My PHP version is 7.3.4.
My test
public function testLogin()
{
$user = factory(\App\Models\User::class)->create();
$response = $this->json('post', 'v1/login', [
'email' => $user->email,
'password' => 'secret',
]);
$response->assertStatus(Response::HTTP_OK);
}
My AuthController
public function login(AuthRequest $request)
{
try {
$credentials = $request->only(['email', 'password']);
throw_if(!auth()->attempt($credentials), UnauthorizedAccess::class, __('auth.auth_required'));
$accessToken = $this->handleAccessToken($credentials);
return response()->json($accessToken);
} catch (UnauthorizedAccess $ex) {
return response()->json([
'success' => false,
'message' => $ex->getMessage()
], Response::HTTP_UNAUTHORIZED);
}
}
private function handleAccessToken(array $credentials)
{
$user = User::where(['email' => $credentials['email']])->first();
$http = new Client();
$response = $http->post(url('oauth/token'), [
'form_params' => [
'grant_type' => 'password',
'client_id' => $user->client->id,
'client_secret' => $user->client->secret,
'username' => $credentials['email'],
'password' => $credentials['password'],
'scope' => '*',
],
]);
return json_decode((string) $response->getBody(), true);
}
This is the erro that is produced:
on terminal
1) Tests\Feature\AuthTest::testLogin
Expected status code 200 but received 500.
Failed asserting that false is true.
laravel.log
[2019-04-26 09:02:53] local.ERROR: Client authentication failed {"exception":"[object] (League\\OAuth2\\Server\\Exception\\OAuthServerException(code: 4): Client authentication failed at /home/***/workspace/***/vendor/league/oauth2-server/src/Exception/OAuthServerException.php:138)
[stacktrace]
[2019-04-26 09:02:53] testing.ERROR: Client error: `POST http://***/oauth/token` resulted in a `401 Unauthorized` response:
{"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"}
{"userId":"52b19d0d-e0c5-4924-84ae-d07700c672df","exception":"[object] (GuzzleHttp\\Exception\\ClientException(code: 401): Client error: `POST http://***/oauth/token` resulted in a `401 Unauthorized` response:
{\"error\":\"invalid_client\",\"error_description\":\"Client authentication failed\",\"message\":\"Client authentication failed\"}
at /home/***/workspace/***/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:113)
[stacktrace]
Well, the error seems to be something with Guzzle itself while in testing env. That happens because Guzzle is set for the default env.
Then, I solve it following the answer gave by #lawrencedawson, that you can see here
I use Filsh/yii2-oauth2-server,
I can use client token using $_pos to access my API.
In controller:
if (!isset($_post['token'])){
//exeption
}
else{
token = $_post('token');
}
if ((Accesstokens::isAccessTokenValid($token))) {
// do some thing.
}
in my Accesstokens model :
public static function isAccessTokenValid($token)
{
if (empty($token)) {
return false;
}
$query = (new \yii\db\Query())
->select(['access_token','expires'])
->from('oauth_access_tokens')
->where(['access_token' => $token])
// ->limit(10)
->one();
if (empty($query)) {
return false;
}
$expire = $query['expires'];
return $expire > date('Y-m-d h:i:s');
}
If I use password (user_credential) token, I can implementation bearer auth using :
public function behaviors()
{
return ArrayHelper::merge(parent::behaviors(), [
'authenticator' => [
'class' => CompositeAuth::className(),
'authMethods' => [
['class' => HttpBearerAuth::className()],
['class' => QueryParamAuth::className(), 'tokenParam' => 'accessToken'],
]
],
'exceptionFilter' => [
'class' => ErrorToExceptionFilter::className()
],
]);
}
But this method is using user table in authenticate user, not oauth_client table to authenticate client without user.
How to authenticate token base on client table only, without user table?
Request:
GET http://myapi.com/api/www/index.php/oauth2/token
grand_type = client_credentials
client_id = id1
client_secret = secret1
Response:
"access_token": "thisistheccesstoken",
"expires_in": 31104000,
"token_type": "Bearer",
"scope": "default"
Request:
GET http://myapi.com/api/www/index.php/oauth2/v1/get/frogs
HEADER Authorization: Bearer thisistheaccesstoken
Response:
all the frogs
How to use: HEADER Authorization: Bearer? Can anyone help?
New to facebook api development.. taking a crack at php api and just trying to get user logged into facebook to show up... so far unsuccessfully.. I've tried the different ways below to get a fb user authenticated to no avail. How can I get the user ID to read? Can someone post just this short section of their code to help me see how you got this working? Thanks!
<?php
require 'facebook.php';
$facebook = new Facebook(array(
'appId' => 'zzzzzz',
'secret' => 'yyyyyy',
));
// See if there is a user from a cookie
$user = $facebook->getUser();
?>
<?php
require 'facebook.php';
// Create our Application instance (replace this with your appId and secret).
$facebook = new Facebook(array(
'appId' => 'zzzzzz',
'secret' => 'xxxxxx',
'scope' => 'manage_pages,offline_access,publish_stream'
));
// Get User ID
$user = $facebook->getUser();
?>
<?php
require_once( 'lib/fb/src/facebook.php' );
$appId = 'zzzzzz';
$secret = 'yyyyyy';
$facebook = new Facebook( $appId, $secret );
// Get User ID
$user = $facebook->require_login();
?>
the sample code works from the php sdk is perfect!
<pre>
require '../src/facebook.php';
// Create our Application instance (replace this with your appId and secret).
$facebook = new Facebook(array(
'appId' => '191149314281714',
'secret' => '73b67bf1c825fa47efae70a46c18906b',
));
// Get User ID
$user = $facebook->getUser();
// We may or may not have this data based on whether the user is logged in.
//
// If we have a $user id here, it means we know the user is logged into
// Facebook, but we don't know if the access token is valid. An access
// token is invalid if the user logged out of Facebook.
if ($user) {
try {
// Proceed knowing you have a logged in user who's authenticated.
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
}
}
// Login or logout url will be needed depending on current user state.
if ($user) {
$logoutUrl = $facebook->getLogoutUrl();
} else {
$loginUrl = $facebook->getLoginUrl();
}
// This call will always work since we are fetching public data.
$naitik = $facebook->api('/naitik');
?>
</pre>
you must redirect the user to authenticate in login page of facebook.
$facebook = new Facebook(array(
'appId' => '...',
'secret' => '...',
));
$user = $facebook->getUser();
if ($user) {
//user authenticate
$logoutUrl = $facebook->getLogoutUrl();
echo 'loggout';
$friends = $facebook->api('/me/'); //you profile details..
} else {
$loginUrl = $facebook->getLoginUrl();
echo 'Login with Facebook to access this application.';
}
You can check out some complete examples in the new PHP SDK documentation; the api method in particular may be of interest.