Mike
Mike

Reputation: 8877

How can I create a token for a Password Grant Client using Laravel Passport?

I am building an API and I am using Laravel Passport for authentication.

The API is being used for our mobile app so we're using the Password Grant Client.

Everything works great, and a user can login to get an access token. We have created a register endpoint which allows a user to sign up. We need the API to return an access token at this point too.

Looking through the docs there is no way to create an access token programmatically.

How can I create an access token for a Password Grant Client in my controller? I obviously don't want to do a HTTP request to my own API to get it.

I know I can use a Personal Access Grant Client and call createToken on the user model, but that means the access token is associated with a different Client. This doesn't seem right to me.

Upvotes: 12

Views: 8416

Answers (4)

Ben Dubuisson
Ben Dubuisson

Reputation: 757

Patrick has got the right idea, and this is what I ended up doing: (I don't think Sanju's answer is right because you need to make a http request)

<?php

namespace MyApp\Http\Controllers\API;

use Illuminate\Http\Request;
use Laravel\Passport\Http\Controllers\ConvertsPsrResponses;
use League\OAuth2\Server\AuthorizationServer;
use MyApp\Http\Controllers\APIController;
use Illuminate\Auth\AuthenticationException;
use Zend\Diactoros\ServerRequest;
use Zend\Diactoros\Response as Psr7Response;

class LoginController extends APIController
{

    use ConvertsPsrResponses;

    /**
     *
     * @param Request $request
     * @param AuthorizationServer $authServer
     * @return \Illuminate\Http\JsonResponse
     * @throws AuthenticationException
     * @throws \League\OAuth2\Server\Exception\OAuthServerException
     */
    public function login(Request $request, AuthorizationServer $authServer)
    {
        $token = $this->getPasswordToken($request, $authServer);
        $data = [
            "token_details" => $token,
        ];

        return $this->successResponse(
            'Successful Login',
            200,
            $data
        );

    }


    /**
     * @param $request
     * @param AuthorizationServer $authServer
     * @return mixed
     * @throws \League\OAuth2\Server\Exception\OAuthServerException
     */
    private function getPasswordToken($request, AuthorizationServer $authServer)
    {
        $parsedBody = [
            'grant_type' => 'password',
            'client_id' => config('app.client_id'),
            'client_secret' => config('app.client_secret'),
            'username' => $request->username,
            'password' => $request->password,
            'scope' => '',
        ];

        $serverRequest = new ServerRequest(
            $request->server(),
            [],
            null,
            $request->method(),
            'php://input',
            $request->header(),
            [],
            [],
            $parsedBody
        );

        $response = $this->convertResponse(
            $authServer->respondToAccessTokenRequest($serverRequest, new Psr7Response)
        );
        return json_decode($response->getContent());
    }

}

Upvotes: 1

Sanju Kaniyamattam
Sanju Kaniyamattam

Reputation: 505

Try something like this

class UserController extends Controller
{
    protected function login(Request $request)
    {

         $request->request->add([
            'grant_type'    => 'password',
            'client_id'     => '3',
            'client_secret' => '6BHCRpB4tpXnQvC1DmpT7CXCSz7ukdw7IeZofiKn',
            'scope' => '*'
        ]);

        // forward the request to the oauth token request endpoint
        $tokenRequest = Request::create('/oauth/token','post');
        return Route::dispatch($tokenRequest);
    }

}

Upvotes: 5

LeviJames
LeviJames

Reputation: 188

I've been toying with Passport for a couple of weeks now and from what I've seen in the documentation it doesn't expose many of the methods it uses for creating tokens. While you may not easily be able to "create an access token for a Password Grant Client in my controller" - what you can do is use Route::dispatch to forward the request for a token to your Passport Password Grant route.

To do this in the controller you are using to issue tokens, use the AuthenticatesUsers trait so you have access to the Password Grant route, create a request, and dispatch that request to the Password Grant route:

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class IssueTokensController extends Controller
{

    use AuthenticatesUsers;

    protected function issueApiToken(Request $request)
    {
        // forward the request to the oauth token request endpoint
        $tokenRequest = Request::create(
            '/oauth/token',
            'post'
        );
        return Route::dispatch($tokenRequest);
    }

}

This method of course requires you to have set up Passport and a Password Grant Client.

This answer is based off of another answer to a similar question by Raymond Lagonda - see https://stackoverflow.com/a/40433000/4991377

Upvotes: 4

Patrick Cunningham
Patrick Cunningham

Reputation: 88

I know I can use a Personal Access Grant Client and call createToken on the user model, but that means the access token is associated with a different Client

not sure what you mean by that, could you explain more?

Now this is not ideal but you might be able to inject \League\OAuth2\Server\Grant\PasswordGrant and use

respondToAccessTokenRequest(ServerRequestInterface $request 
                            ResponseTypeInterface $responseType,
                            \DateInterval $accessTokenTTL)

you would have to build all those objects, but this is the only public method for password that returns any token information.

Upvotes: 0

Related Questions