maxxxir's avatar

passport authorization of 3rd party app - accessing /oauth/authorize with token based user from front app

i have a website with separate fornt(vue) and backend (laravel) applications

im using passport for authentication , generating personal access token for users and storing it in front application , and sending request with Bearer authToken to backend from front app for protected routes

i have a client --personal to generate these tokens

now im trying to grant another website users to access their information in my website , so i have created a new passport client for 3rd party apps

and ask for authorization from 3rd app using that client

     $query = http_build_query([
        'client_id' => config('mywebsite.auth_client_id'),
        'redirect_uri' => route('thisapp.callback'),
        'response_type' => 'code',
        'scope' => '',
        'state' => Str::uuid()->toString() ,
    ]);
	
    return ['url' => config('mywebsite.mywebsite_url') .'/oauth/authorize?'.$query];

which generates a authorizations url

http://api.mywebsite.com/oauth/authorize?....

the problem is this will generate a backend route , which is protected by auth:web

users need to login in my backend directly which means i need a login views in my backend app , and users need to log in again in my back end directly even if they are already logged in via front app

i tried to call this route via my front app with user token , but apparently this route is protected with web/session guard and dont recognize my front token

i've tried to change the guard in config/passport to api so the route works with token/api guard but im getting this error

"message": "Laravel\Passport\Http\Controllers\AuthorizationController::__construct(): Argument #2 ($guard) must be of type Illuminate\Contracts\Auth\StatefulGuard, Laravel\Passport\Guards\TokenGuard given",

i tried to overwrite the route with auth:api middleware

Route::get('/oauth/authorize', [\Laravel\Passport\Http\Controllers\AuthorizationController::class, 'authorize'])->middleware('auth:api');

but still asking for log in when i call the route with my auth token

is there any way to call these routes with api/token logged user from front end instead of web/session in the backend ?

0 likes
6 replies
martinbean's avatar

@maxxxir Firstly, you‘re using personal access tokens wrong. They’re for a user to generate themselves from a logged-in account area. Think GitHub where they let you generate tokens for your account. They’re personal access tokens.

You should instead be using an authorization code grant with PKCE client. From https://laravel.com/docs/11.x/passport#code-grant-pkce:

The Authorization Code grant with "Proof Key for Code Exchange" (PKCE) is a secure way to authenticate single page applications or native applications to access your API.

--

users need to login in my backend directly which means i need a login views in my backend app

Well yes. How are you intending to issue an access token for a user, if the user does not authenticate?

and users need to log in again in my back end directly even if they are already logged in via front app

Not if you use Passport properly and pick the correct OAuth grant type for your situation. Using an authorization code grant with PKCE client as mentioned above means the user would log in once on your back-end, and then be redirected back to your “front end” with an OAuth token that should be used to make API requests as that user. You can’t “log in” to something running entirely on the client side in the user’s browser.

1 like
maxxxir's avatar

@martinbean thanx i've red about the oauth flow , but honestly i just dont get it

Well yes. How are you intending to issue an access token for a user, if the user does not authenticate?

user registers via front ap , after receiving user information from front app(and email verification) , i'll create the user , generate a token and pass it to front app along with user information

front app will store this token in local storage and pass it along with requests to back end

if user wants to log in , front app will send the email and password and after auth attempt i'll generate a new token and send it to the front

function register(CreateAccountRequest $request)
{
    $user = $this->create( $request->validated() , [$this , 'deleteEmailVerification']);
    return ['user' => $user , 'token' => $user->createToken('auth')->accessToken];
}


function login(LoginRequest $request)
{
    if( auth()->attempt($request->only('email' , 'password')))
    {
        return ['user' => auth()->user()  , 'token' =>  auth()->user()->createToken('auth')->accessToken ];
    }
    abort(404);
}

i understand there is a reason for oauth flow as document says and technically im not handling it the right way but i just dont see a problem with my simple flow it just works

i dont want to add vue setup/views/npm packages in my backend as it's already been done in the front app and it has a different programmer

martinbean's avatar

front app will store this token in local storage and pass it along with requests to back end

@maxxxir And then the user can tamper with that token.

You do realise Sanctum was created to solve this exact problem, right? To avoid storing things like credentials and tokens insecurely in client-side storage such as localStorage.

1 like
maxxxir's avatar

@martinbean i usually use sanctum but switched to passport to be able to authorize 3rd party apps i thought sanctum was created becuz you wouldn't need all of passport features most of the time and it was a simpler alternative but never knew it prevents token tempering (i assume it's the generated token algorithm/type that prevents manipulation , but still you would store the token in the front app ?)

thats interesting tho , maybe i can use both sanctum for front app and passport for 3rd party apps maybe i create a separate service/app with passport for 3rd party integration and the resources or some weird(and most likely failing ) solution like having 2 different user models one for sanctum traits and one with passport !

i assume they can both workk with the same user table and hashed password , since they store their tokens in different tables ... not sure about the password hash tho maybe if both apps have the same key in the env ?

thanx mr.bean i had no idea jwt tokens were vulnerable to tampering , i guess oauth flow makes sense

just what kind of tempering / danger are we talking about ? i've searched around for passport token tempering didnt find much it'd be kind of you if you can mention some example or provide a resource i thought they were encrypted and there was a mechanism to detect tampering

martinbean's avatar

@maxxxir I never mentioned tampering in my reply?

Sanctum differs from Passport because it uses cookies for authentication. You get a cookie, the cookie is stored by the browser like normal, and then your JavaScript HTTP client (i.e. Axios) automatically passes that cookie with subsequent HTTP requests. This means you’re not storing an opaque token string in client-side storage such as localStorage.

Sanctum also offers authentication via API tokens as you described to allow third parties to generate tokens and use them for authenticating.

1 like
maxxxir's avatar

@martinbean maybe i misunderstood , but you mentioned tampering it in the previous reply

@maxxxir And then the user can tamper with that token.

i guess someone can steal the token by monitoring network requests

im not a front developer so im not sure how it should be handled in the front , but our front guy always stores the token (sanctum,passport) in the local storage and pass it along with request to backend api

so basically the correct way to handle this is for user to log in directly in the backend , and handle the auth via cookie/session ? this way we never show auth token in the requests and front is just passing cookie information to backend

what about mobile apps ? they cant have cookies (i think)

Please or to participate in this conversation.