Tymon\JWTAuth::toUser error: A token is required - laravel

I have a Larvel API that uses Tymon\JWTAuth to authenticate the user.
It is working fine.
For some reasons I have also a non-guarded route in web.php:
Route::get('myroute', 'MyController#mymethod');
The code of MyController#mymethod is the following:
$user = JWTAuth::toUser($request->input('token'));
// I tried also this:
// JWTAuth::setToken($request->input('token'));
// $user = JWTAuth::authenticate();
And I call the route using this url in the browser: /myroute?token=eyJ0eXAiOiJKV1QiLCJhbGci....
The problem is that I have an exception in JWT.php:
Tymon \ JWTAuth \ Exceptions \ JWTException
A token is required
JWT.php
protected function requireToken()
{
if (! $this->token) {
throw new JWTException('A token is required');
}
}
How can I decode the token that is passed as URL parameter and not in the header of the request?

If you are using jwt-auth dev, the toUser method in old version will drop the error like above, try this:
// Get the currently authenticated user
$user = auth()->user();
If the user is not then authenticated, then null will be returned.

Instead of
$user = JWTAuth::toUser($request->input('token'));
Use
$user = $this->jwt->User();

I solved it using this code:
use Namshi\JOSE\SimpleJWS;
$secret = config('jwt.secret');
$jws = SimpleJWS::load($token);
if (!$jws->isValid($secret)) {
return response()->json([], 401); // unauthorized
}
$payload = $jws->getPayload();
$account = Account::find($payload["account"]["id"]);
However I would have preferred to use directly JWTAuth

Related

How can write test for laravel api route with auth.basic middleware

My laravel project has an API route by auth.basic middleware which is used id of the authenticated user in the controller. when I call it in postman it works well and I get 401 when the username or password is incorrect, but in laravel APITest which extends from DuskTestCase, authentication does not take place so I get 500 instead of 401 when the user's informations were incorrect. However, by correct information, I have the same error because auth() is null.
it is written like below, which is wrong?
api.php route:
Route::get('/xxxxxx/xxxxxx/xxxxxxx', 'xxxxx#xxxx')->middleware('auth.basic');
APITest:
$response = $this->withHeaders(['Authorization' => 'Basic '. base64_encode("{$username}:{$password}")])->get("/xxxxxx/xxxxxx/xxxxxxx");
You can use actingAs() method for authentication in tests.
An example from docs:
public function testApplication()
{
$user = factory(App\User::class)->create();
$this->actingAs($user)
->withSession(['foo' => 'bar'])
->visit('/')
->see('Hello, '.$user->name);
}
Another example that you can use for an API:
$user = User::factory()->create();
$response = $this->actingAs($user)->json('GET', $this->uri);
$response->assertOk();
For more information: https://laravel.com/docs/5.1/testing#sessions-and-authentication

Laravel - How can I get user info based on a bearer token passed through a URL parameter?

I'm using sanctum to authenticate the API calls.
I'm loading images and videos within an app, and as I want the user to be logged in and actually be able to identify which user is requesting the image or video, I'm adding the bearer token as a parameter within the video/image URL.
i.e. <img src="https://mysite.test/private/video?e=XXXXX&tk=my_bearer_token" />
On the backend I'm then doing something like:
public function getPrivateVideo (Request $request) {
$validator = Validator::make($request->all(), [
'e' => 'required|exists:employees,id',
't' => 'required|exists:course_lesson_videos,code',
'tk' => 'nullable'
]);
if(auth()->check(){
$user = auth()->user();
}elseif($request->tk){
$user = get user by access token or fail
}else{
return abort('403');
}
Log::info([$user->id,$request->e,$request->t]);
$video_code = $request->t;
if($validator->fails() || $request->user()->client_employee->id !== $request->e || !CourseLessonVideo::join('course_lesson_questions as clq','clq.lesson_id','course_lesson_videos.lesson_id')->join('course_employee_assigned_questions as ceaq','ceaq.question_id','clq.id')->where('employee_id',$request->e)->where('code',$video_code)->first())
return abort('403');
return response()->file(storage_path('app/videos/'.$video_code));
}
I assume it must be possible somehow?
To get a user by tokens
try this code
findToken()
use Laravel\Sanctum\PersonalAccessToken;
$token = PersonalAccessToken::findToken($request->get('tk'));
$user = $token->tokenable;
Or
$token = PersonalAccessToken::where('token', $token)->first();
$user = $token->tokenable;

Laravel passport create token and refresh token

I'm using Laravel and passport on my project.
In my project users can get token in two way.
First with username and password that its OK by passport.
Second with verification code that sent with SMS that its my problem.
I tried createToken() method but it will make a personal token without refresh token and I need to create token with refresh token and specify client id in a controller (without HTTP request).
$user = App\User::find(1);
// Creating a token without scopes...
$token = $user->createToken('Token Name')->accessToken;
How can I do this?
Create a new controller AccessTokenController that extends \Laravel\Passport\Http\Controllers\AccessTokenController
<?php
namespace App\Http\Controllers;
use App\User;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Psr\Http\Message\ServerRequestInterface;
use Response;
class AccessTokenController extends \Laravel\Passport\Http\Controllers\AccessTokenController
{
public function issueToken(ServerRequestInterface $request)
{
try {
//get username (default is :email)
$username = $request->getParsedBody()['username'];
//get user
$user = User::where('email', '=', $username)->firstOrFail();
//issuetoken
$tokenResponse = parent::issueToken($request);
//convert response to json string
$content = $tokenResponse->getBody()->__toString();
//convert json to array
$data = json_decode($content, true);
if(isset($data["error"]))
throw new OAuthServerException('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
//add access token to user
$user = collect($user);
$user->put('access_token', $data['access_token']);
$user->put('expires_in', $data['expires_in']);
$user->put('refresh_token', $data['refresh_token']);
return Response::json(array($user));
}
catch (ModelNotFoundException $e) { // email notfound
//return error message
}
catch (OAuthServerException $e) { //password not correct..token not granted
//return error message
}
catch (Exception $e) {
////return error message
}
}
}
You can generate client_id by using following command
php artisan passport:client
I found a package and I'm using that
https://github.com/qiutuleng/laravel-passport-phone-verification-code-grant
It's good.

JWT laravel: check auth. Cannot check if user is authenticated even i have set the token

I'm trying make a mobile application with vue and i'm using jwt in laravel.
On first login, I can access the auth()->check() then I get false after the app is cancelled. I'm saving the token. I'm saving the token in local storage. How can I get the authenticated user.
controller:
public function JwtAuth(){
if($this->getAuthenticatedUser()){
return $this->JwtUser = $this->getAuthenticatedUser();
}
return [];
}
I want to acheive something like:
if(auth()->user()){
$user = "something";
}else{
$user = '';
}
return $user;
So sometime I will have token and sometime i dont .. how to check?

JWT::getToken() doesn't get the proper token

I'm using JWT-Auth for authentication. I have created a middleware that checks if token is expired and then it refreshes the token and update the header. But in my controller getToken() does not get the new token but returns the expired one. I have checked the value of header in my controller and it has the new token.
This is how I do it in my middleware:
$new_token = JWTAuth::refresh($token);
$request->headers->set('Authorization', 'Bearer '.$new_token);
$response = $next($request);
and this is in my controller:
$token = JWTAuth::getToken();
After looking at their code. I found a setToken() function which solved my issue. I modified my code like this:
$new_token = JWTAuth::refresh($token);
JWTAuth::setToken($new_token);
$response = $next($request);
$response->header('Authorization','Bearer '.$new_token);
return $response;
Change version of JWT package 5.12 to 5.11 in composer.json file then its work properly.
I was also stuck in same issue before few days
https://github.com/tymondesigns/jwt-auth/issues/1198

Resources