Laravel API TOKEN authentication not working - authentication

I am trying to authenticate user with api authentication token. But even after using correct token its saying unauthorized.
I am using laravel auth and socialite for social authentication
so my api.php route is like this
Route::group(['middleware'=>'auth:api'], function(){
Route::get('hello','ApiTestControler#index');
});
And i m trying to access this with this url
http://localhost:8000/api/hello
and in the header
token: TOKEN HERE
Content-Type: application/json
Accept: application/json
I was expecting it to log me in and show the ApiTestController index methord
But its throwing an error 401 unauthorized
How do i fix this issue and get user authenticate using the API token?
My controller
class ApiTestController extends Controller
{
public function index(){
return json_encode ("Welcome REST API");
}
}
User migration table
$table->increments('id');
$table->string('name')->unique();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->string('email')->unique()->nullable();
$table->string('password');
$table->rememberToken();
$table->boolean('activated')->default(false);
$table->string('token');
$table->ipAddress('signup_ip_address')->nullable();
$table->ipAddress('signup_confirmation_ip_address')->nullable();
$table->ipAddress('signup_sm_ip_address')->nullable();
$table->ipAddress('admin_ip_address')->nullable();
$table->ipAddress('updated_ip_address')->nullable();
$table->ipAddress('deleted_ip_address')->nullable();
$table->timestamps();
$table->softDeletes();
And the auth configuration in config\auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
]

The only thing that i found it can cause the problem is the name of the token column in the database, it sould be api_token, so change the migration to this :
$table->increments('id');
$table->string('name')->unique();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->string('email')->unique()->nullable();
$table->string('password');
$table->rememberToken();
$table->boolean('activated')->default(false);
$table->string('api_token', 60)->unique(); //<-- this one here
$table->ipAddress('signup_ip_address')->nullable();
$table->ipAddress('signup_confirmation_ip_address')->nullable();
$table->ipAddress('signup_sm_ip_address')->nullable();
$table->ipAddress('admin_ip_address')->nullable();
$table->ipAddress('updated_ip_address')->nullable();
$table->ipAddress('deleted_ip_address')->nullable();
$table->timestamps();
$table->softDeletes();
Do not forget to refresh the database, and one more thing to get the authenticated user you have to use :
Auth::guard('api')->user()
Instead of :
Auth::user()

Related

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.

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

Method Illuminate\Auth\RequestGuard::attempt does not exist

I am new to both laravel and lumen.
I was creating a login api with oauth2.0 in lumen 5.6, i have installed passport and generated token.
Below is my login controller function and it is working fine. It returns token.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Route;
//use Illuminate\Support\Facades\DB;
use App\User;
use Auth;
public function login(Request $request)
{
global $app;
$proxy = Request::create(
'/oauth/token',
'post',
[
'grant_type' => env('API_GRAND_TYPE'),
'client_id' => env('API_CLIENT_ID'),
'client_secret' => env('API_CLIENT_SECRET'),
'username' => $request->username,
'password' => $request->password,
]
);
return $app->dispatch($proxy);
}
Since i have to check user status apart from username and password, i need to check the user credential first. so i do like this.
public function login(Request $request)
{
$credentials = $request->only('username', 'password');
if (Auth::attempt($credentials)) {
return ['result' => 'ok'];
}
return ['result' => 'not ok'];
}
Here i am getting this error.
Method Illuminate\Auth\RequestGuard::attempt does not exist.
So i tried Auth::check instead of Auth::attempt.
Now there is no error but it always return false even though the credentials are valid.
I searched a lot for a solution but i didn't get.
The function guard is only available for routes with web middleware
public function login() {
if(Auth::guard('web')->attempt(['email' => $email, 'password' => $password], false, false)) {requests
// good
} else {
// invalid credentials, act accordingly
}
}
Changing default guard to "web" fixed my problem.
config/auth.php:
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
using jwt it's worked for me
1-Auth::attempt($credentials)
just replace line 1 to line 2
2-$token = Auth::guard('api')->attempt($credentials)

How to use API Routes in Laravel 5.3

In Laravel 5.3 API routes were moved into the api.php file. But how can I call a route in api.php file? I tried to create a route like this:
Route::get('/test',function(){
return "ok";
});
I tried the following URLs but both returned the NotFoundHttpException exception:
http://localhost:8080/test/public/test
http://localhost:8080/test/public/api/test
How can I call this API route?
You call it by
http://localhost:8080/api/test
^^^
If you look in app/Providers/RouteServiceProvider.php you'd see that by default it sets the api prefix for API routes, which you can change of course if you want to.
protected function mapApiRoutes()
{
Route::group([
'middleware' => 'api',
'namespace' => $this->namespace,
'prefix' => 'api',
], function ($router) {
require base_path('routes/api.php');
});
}
routes/api.php
Route::get('/test', function () {
return response('Test API', 200)
->header('Content-Type', 'application/json');
});
Mapping is defined in service provider App\Providers\RouteServiceProvider
protected function mapApiRoutes(){
Route::group([
'middleware' => ['api', 'auth:api'],
'namespace' => $this->namespace,
'prefix' => 'api',
], function ($router) {
require base_path('routes/api.php');
});
}

Yii2 oauth2 client_credential token 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?