Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

OliverHH's avatar

Authenticate with a sanctum Bearer Token in a JWT token in the URL

In an API endpoint I want Users to authenticate with a sanctum Bearer Token in a JWT token in the URL and not in the request header. In the JWT should also be a model ID wich should be resolved and injected into to controller method. Here is a token payload example

$payload = [
    'uuid'  => '7c6a4170-a13d-4506-bbfd-5f7d7ea64a3b',
    'token' => 'sanctum access token'
];

The requested URL with the bearer token and the uuid could be: /hook/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1dWlkIjoiN2M2YTQxNzAtYTEzZC00NTA2LWJiZmQtNWY3ZDdlYTY0YTNiIiwidG9rZW4iOiJzYW5jdHVtIGFjY2VzcyB0b2tlbiIsImlhdCI6MTUxNjIzOTAyMn0.2ZkbXPDn6f7harIS-OeR0Q4YKgHe8aggzmfX5r_66Y0

This is my example route:

Route::post('/hook/{jwt}', function (Persona $persona, CustomRequest $request) {
    // Expect the persona is automatically resolved from the JWT in the middleware
    // and injected into the route handler.

    // Currently I can access the persona like this (when I remove the attribute "Persona $persona" from the function signature):
    // dd($request->route('persona'));
    // otherwise I get an error "Argument #1 ($persona) must be of type Persona, string given"

    echo 1;
})
->middleware([
    // TokenFromJwt::class, // does not work here, has to be set in global middleware
    'auth:sanctum',
]);

This is my current middleware:

// TokenFromJwt Middleware

public function handle(Request $request, \Closure $next): Response
{
    // Extract the JWT from the route parameter
    $jwt = $request->route('jwt');

    // Decode the JWT
    $token = JWT::decode( $jwt, new Key(config('app.key'), 'HS256') );

    // Set the Authorization header with the Bearer token
    $request->headers->set('Authorization', 'Bearer '.$token->token, false);

    $route = $request->route();
    // Resolve the Persona model using the UUID from the token
    $route->setParameter('persona', $persona = Persona::where('uuid', $token->uuid)->first());

    return $next($request);
}

Why do I have to set the middleware in the global middleware stack and not in the route definition? How can I make it work in the route definition?

How can I inject the resolved Persona model correctly into the controller method?

Thanks for your help Oliver

0 likes
2 replies
OliverHH's avatar

Thank you for your suggestion. I know it is more secure to add the authorization code in the header than in the url. The authorization would only be for this hook. Not everyone who will access this hook will be able to add a custom header. I think it is more secure to protect this route with a potentially unsecure method (authorization code in the url) than no protection. The access token can be revoked.

Please or to participate in this conversation.