Yii2 oauth2 client_credential token authentication - authentication

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?

Related

Laravel 8: after successful log in Auth session destroying on its own whenever I'm trying to redirect it to another route

web.php
Route::get('/', [AdminLoginController::class, 'index'])->name('admin.login');
Route::post('/login', [AdminLoginController::class, 'login'])->name('admin.login.submit');
Route::group(['middleware' => 'admin.middle' ] , function() {
Route::get('/dashboard', [AdminDashboardController::class, 'index'])->name('admin.dashboard');
});
AdminLoginController.php
public function login(Request $request)
{
$validator = Validator::make($request->all(),[
'email' => 'required|email:rfc,dns|exists:admins,email',
'password' => 'required',
],[
'email.required' => "Email is required",
'email.email' => "Email is invlaid",
'email.exists' => "Email does not exist",
'password.required' => "Password is required"
]);
if($validator->fails())
{
$this->sendResponse(400,$validator->errors()->first(),[]);
}
else
{
if (Auth::guard('admin')->attempt(["email" => $request->email , "password" => $request->password])) {
$this->sendResponse(
200,
"Successfully Logged In",
[
'location' => route('admin.dashboard')
]);
}
else {
$this->sendResponse(
500,
"Email or Password is incorrect",
[]);
}
}
}
AdminAuthenticate.php
class AdminAuthentication
{
public function handle(Request $request, Closure $next)
{
if (Auth::guard('admin')->check())
{
if (Auth::guard('admin')->user()){
return $next($request);
}
}
return redirect('/admin');
}
}
Maybe your sendResponse is not set corresponding headers (Set-cookie)? It looks like you mixing api responses with responses for browser.

Laravel HTTP Client Retrieve REST API Access Token

Trying to retrieve an access token from MS Azure
something like this:
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\Response;
class HttpController extends Controller
{
public function index()
{
$url = "https://login.microsoftonline.com/[tenantId]/oauth2/token";
$response = HTTP::post($url,
[
'grant_type' => 'client_credentials',
'client_Id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'client_secret' => '***************************',
'resource' => 'https://management.azure.com',
]);
dd($response);
}
}
get the following error:
"error": "invalid_request",
"error_description": "AADSTS900144: The request body must contain the following parameter: 'grant_type'
$response = HTTP::asForm()->post($url,
[
'grant_type' => 'client_credentials',
'client_Id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'client_secret' => '***************************',
'resource' => 'https://management.azure.com',
]
);

Cakephp authentication results invalid only on stateless verification

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.

Invaild Grant issue in Xero OAuth2.0 Refresh token

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.

Error trying to test laravel/passport auth cicle

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