laravel calling route from a controller - php

I am writing an API at the moment in Laravel, and using passport. My client will consume it's own API, so I am using personal access in Passport.
I am not wanting to show my oauth route and grant id, or secret in the POST request so I have created a route that sits the user posts too to login, and then deals with send a POST request to the oauth/token route, like below,
protected function authenticate(Request $request) {
//return $request->input();
//return Response::json($this->client);
$email = $request->input('username');
$password = $request->input('password');
$request->request->add([
'username' => $email,
'password' => $password,
'grant_type' => 'password',
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'scope' => '*'
]);
$tokenRequest = Request::create(
env('APP_URL').'/oauth/token',
'post'
);
return Route::dispatch($tokenRequest)->getContent();
}
My problem is that my authentication returns 200 irrespective of whether the oauth login was successful. Is there a way to fire a route from a controller and return that http code for that rather than the method it was called from http response?

this should fix the problem.
$data = [
'grant_type'=> 'password',
'client_id'=> 99,
'client_secret'=> 'hgfhfhjnhnjnjnjnj',
'username'=> $request->username,
'password'=> $request->password,
'scopes'=> '[*]'
];
$request = Request::create('/oauth/token', 'POST', $data);
return app()->handle($request);

Related

Laravel\Passport\Client returns null instance

My Auth API was working but now it gives error. I can register successfully but I cant get the return of the login token because I get an error:
TypeError: Argument 1 passed to App\Http\Controllers\UserController::getTokenAndRefreshToken() must be an instance of Laravel\Passport\Client, null given, called in /var/www/laravel/app/Http/Controllers/UserController.php on line 44 in file /var/www/laravel/app/Http/Controllers/UserController.php on line 47
Like I said, it was working before, I just added another model and created one-to-many relationship with user model but I don't think that has got anything to do with Passport.
Why I get a null object from OClient::where('password_client', 1)->first();
I create user like this in UserController's register method.
$user = User::create($input);
$oClient = OClient::where('password_client', 1)->first();
return $this->getTokenAndRefreshToken($oClient, $user->email, $password);
public function getTokenAndRefreshToken(OClient $oClient, $email, $password) {
$oClient = OClient::where('password_client', 1)->first();
$http = new Client;
$response = $http->request('POST', '/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => $oClient->id,
'client_secret' => $oClient->secret,
'username' => $email,
'password' => $password,
'scope' => '*',
],
]);
$result = json_decode((string) $response->getBody(), true);
return response()->json($result, $this->successStatus);
}

Laravel Passport logout test returning 200 when it should be denied

I'm trying to write a test for the logout procedure for Laravel Passport. But every time I run it i am receiving the error expected 401 but got 200 which means that its not actually logging out the user.
The Logout functionality in the AuthController is as follows;
public function logout(Request $request): JsonResponse
{
$accessToken = $request->user()->token();
$refreshToken = DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update([
'revoked' => true
]);
$accessToken->revoke();
return response()->json(['message' => 'Successfully logged out']);
}
This works fine, but the testing is the issue.
My test is as follows;
public function testUserIsLoggedOutProperly(): void
{
$user = factory(User::class)->create();
Passport::actingAs($user);
$this->json('GET', 'api/user')->assertStatus(JsonResponse::HTTP_OK);
$this->json('GET', 'api/logout')->assertStatus(JsonResponse::HTTP_OK);
$this->json('GET', 'api/user')
->assertStatus(JsonResponse::HTTP_UNAUTHORIZED);
}
The last assert is actually returning a HTTP_OK (200)
Any help would be greatly appreciated.
It's just a quick reflexion (not tested) but you should do your test with :
get a new token, (I think you can do that without api call)
call "api/logout" with token get in 1)
check with assertDatabaseHas function
$response = $this->json('POST','oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'taylor#laravel.com',
'password' => 'my-password',
'scope' => '',
]
]);
$response->assertStatus(JsonResponse::HTTP_OK);
$token = json_decode((string) $response->getBody(), true)['access_token'];
$this->json('POST', 'api/logout')->withHeaders([
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $token
])->assertStatus(JsonResponse::HTTP_OK);
$this->assertDatabaseHas('oauth_refresh_tokens', [
'access_token_id' => $token,
'revoked' => true
]);

Laravel 5.6 Passport oAuth2 can't make request with Guzzle

I have a fresh project on Laravel 5.6, where I'm trying to study and understand API Auth with Passport. I'm trying to do that, and after that to make a Javascript application from where I'll access that API. So, API for first-party applications.
I've installed and registered all routes and setup specific to passport, and also installed Guzzle.
I looked for some tutorials and now I'm with that code :
RegisterController.php
<?php
namespace App\Http\Controllers\Api\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Laravel\Passport\Client;
use App\User;
class RegisterController extends Controller
{
use IssueTokenTrait;
private $client;
public function __construct(){
$this->client = Client::find(1); //Client 1 is a Laravel Password Grant Client token from my DB (when I wrote php artisan passport:install
}
public function register(Request $request){
$this->validate($request, [
'name' => 'required',
'email' => 'required|email|unique:users,email',
'password' => 'required|min:3',
'password_confirmation' => 'required|same:password'
]);
$user = User::create([
'name' => request('name'),
'email' => request('email'),
'password' => bcrypt(request('password'))
]);
return $this->issueToken($request, 'password');
}
}
It uses issueToken function from that Trait :
IssueTokenTrait.php
namespace App\Http\Controllers\Api\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use GuzzleHttp\Client;
trait IssueTokenTrait{
public function issueToken(Request $request, $grantType, $scope = ""){
$params = [
'grant_type' => $grantType,
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'scope' => $scope
];
$params['username'] = $request->username ?: $request->email;
$request->request->add($params);
$proxy = Request::create('oauth/token', 'POST');
return Route::dispatch($proxy);
}
}
**NOW THE PROBLEM : **
Everything works perfect. I can register, I have an access token which works on protected with auth routes, and doesn't work when I give a wrong token.
I read the documentation of Passport in Laravel 5.6 and all examples use GuzzleHttp to make requests inside controller method, and I have tried to rewrite my code using Guzzle instead of Request::dispatch.
So, I found in multiple sources, in documentation as well code with different but also same logic implementation, so my IssueTokenTrait now looks like :
<?php
namespace App\Http\Controllers\Api\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use GuzzleHttp\Client;
trait IssueTokenTrait{
public function issueToken(Request $request, $grantType, $scope = ""){
$params = [
'grant_type' => $grantType,
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'scope' => $scope
];
$params['username'] = $request->username ?: $request->email;
$url = url('/oauth/token');
$headers = ['Accept' => 'application/json'];
$http = new GuzzleHttp\Client;
$response = $http->post($url, [
'headers' => $headers,
'form_params' => [
'grant_type' => 'password',
'client_id' => $this->client->id,
'client_secret' => $this->client->secret,
'username' => $request->email,
'password' => $request->password
],
]);
return json_decode((string)$response->getBody(), true);
}
}
And there is how my app gets broken.
When I make a POST request to /api/register from POSTMAN now, it just not returns me a response, like please wait... and that's it. And if I restart my server, it returns me :
[Mon Aug 20 11:29:16 2018] Failed to listen on 127.0.0.1:8000 (reason: Address already in use).
So, it looks like it makes this request, but it not returns the response, or it goes in a infinite loop.
I get stuck for a day with that problem, and really it looks like some mystic here. Because all parameters and values are like it was with Route::dispatch, just the method of making this HTTP request changes.
There are 2 options:
Try to run another Artisan server process with different port (ex: 8001) and guzzle to it.
Using personal access token instead, using createToken to generate access token.

Laravel Passport password grant returns Invalid Credentials Exception

I am trying to setup a SPA that consumes a Laravel API protected with Passport.
I started by creating a new Laravel app specifically for this and I then followed the instructions for setting up passport and set up a password grant client.
I can successfully create a new user, save the user to the database, and log the user in. After that, I try to use the newly created user's information along with the password grant clients id and secret to create an access token. At this point I receive the exception.
I read through the log and I saw where the exception was being thrown. Inside League\OAuth2\Server\Grant\PasswordGrant the validateUser method has the following:
if ($user instanceof UserEntityInterface === false) {
$this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
throw OAuthServerException::invalidCredentials();
}
Seeing this I implemented the UserEntityInterface on my user model and implemented the getIdentifier method but I still receive the Exception. I'm really not too sure where to go from here, any help would be greatly appreciated. Below is some of my code.
Here is my Registration controller:
class RegisterController extends Controller
{
private $tokenService;
public function __construct(AccessTokenService $tokenService)
{
//$this->middleware('guest');
$this->tokenService = $tokenService;
}
public function register(Request $request)
{
$this->validateWith($this->validator($request->all()));
Log::debug('Validated');
$user = $this->create($request->all());
$this->guard()->login($user);
$this->tokenService->boot(Auth::user());
return response()->json($this->tokenService->getNewAccessToken(), 200);
}
protected function guard()
{
return Auth::guard();
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users',
'password' => 'required|min:6|confirmed',
'password_confirmation' => 'required'
]);
}
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
}
And these are the relevant portions of AccessTokenService:
public function getNewAccessToken() {
$http = new Client();
$client = \Laravel\Passport\Client::where('id', 6)->first();
Log::debug($client->getAttribute('secret'));
Log::debug($this->user->getAttribute('email'));
Log::debug($this->user->getAuthPassword());
$response = $http->post('homestead.app/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 6,
'client_secret' => $client->getAttribute('secret'),
'username' => $this->user->getAttribute('email'),
'password' => $this->user->getAuthPassword(),
'scope' => '*'
]]);
unset($client);
$status = $response->getStatusCode();
$body = $response->getBody();
Log::debug($body->getContents());
Log::debug($status);
switch($status)
{
case 200:case 201:
case 202:
$tokens = array(
"user_id" => $this->user->getAttribute('id'),
"access_token" => $body['access_token'],
"refresh_token" => $body['refresh_token']
);
$output = ["access_token" => $this->storeTokens($tokens), 'status_code' => $status];
break;
default:
$output = ["access_token" => '', 'status_code' => $status];
break;
}
return $output;
}
private function storeTokens(array $tokens) {
UserToken::create([
"user_id" => $tokens['user_id'],
"access_token" => bcrypt($tokens['access_token']),
"refresh_token" => bcrypt($tokens['refresh_token'])
]);
return $tokens['access_token'];
}
So I figured out the issue. When I was requesting the access token I was passing in the user's email and password but I was passing the hashed password when I needed to pass in the unhashed password.
My request for an access token looked like this:
$response = $http->post('homestead.app/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 6,
'client_secret' => $client->getAttribute('secret'),
'username' => $this->user->getAttribute('email'),
'password' => $this->user->getAuthPassword(), //Here is the problem
'scope' => '*'
]]);
By passing the Request to the function using the unhashed password like this solved the problem:
$response = $http->post('homestead.app/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 6,
'client_secret' => $client->getAttribute('secret'),
'username' => $request['email'],
'password' => $request['password'],
'scope' => '*'
]]);
In my case it was magic
when i changed username from email format to simple (alphanumeric only) format it works.
please tell the reason if anyone have for my case.
Thanks

JWTAuth getToken give false result when tried to call it in laravel 5

I'm new in laravel and get stuck already with JWTAuth service in laravel.
I'm developing mobile app using ionic and try to make request to generate jwt token. It turn out I was able to generate the token, but when I try another request to compare the token, I cannot get the token using JWTAuth::getToken() in the laravel.
here my script for signin (generate token)
public function signin(Request $request){
$request = [
'email' => urldecode($request->request->get('email')),
'password' => urldecode($request->request->get('password'))
];
if(Auth::attempt($request)){
$user = Auth::user();
Auth::login($user, true);
$custom = ['id' => $user->id, 'email' => $user->email, 'fullname' => $user->name];
$newToken = JWTAuth::fromUser($user,$custom);
$return = array('success' => true, 'token' => $newToken);
}else{
$return = array('success' => false,'token' => '');
};
return response()->json($return);
}
and this is another method to get the token from laravel
public function signout($token){
$user = Auth::user();
if($user){
$return = array('success' => false,'token' => JWTAuth::getToken());
}else{
$return = array('success' => false,'token' => $token);
}
return response()->json($return);
}
is there anyone experience same problem with me? or I missed something here? thanks for the answer and help!

Categories