2

I am using Laravel v9.2.1 + Laravel Sanctum v2.14.1

I got a route

DELETE /api/v1/auth/tokens/{token}

for example (the token is an uuid)

DELETE http://example.com/api/v1/auth/tokens/5fcfa274-81d8-4e9f-8feb-207db77531af

And I am sure it works as expected via php artisan route:list enter image description here

Before handling by the Controller, it should be validated by a FormRequest

app/Http/Controllers/V1/Auth/TokensController.php

namespace App\Http\Controllers\V1\Auth;

use App\Http\Requests\V1\Auth\Tokens\{
    DestroyRequest,
};

class TokensController extends Controller
{
    public function destroy(DestroyRequest $request) {
        $request->user()->tokens()->where('id', $request->token)->first()->delete();
        return response()->noContent();
    }
}

app/Http/Requests/V1/Auth/Tokens/DestroyRequest.php

class DestroyRequest extends FormRequest
{
    public function rules()
    {
        return [
            'token' => [
                'required',
                'string',
                'regex:/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', 
                Rule::exists('personal_access_tokens')->where(function ($query) {
                    return $query->where('tokenable_id', $this->user()->id);
                }),                         
            ]
        ];
    }
}

But what I only got is The token field is required

I had already pass the token, why the 'required' rule still working?

enter image description here


What I tried

Only if I pass the token parameter like below, it will work

DELETE /api/auth/tokens/something?token=test_regex_is_working

enter image description here

I try to dd($this->token) in app/Http/Requests/V1/Auth/Tokens/DestroyRequest.php, it works as expected.

enter image description here

1
  • 1
    use route parameter validation like this Commented Jul 20, 2022 at 10:14

3 Answers 3

5

You might need to add the following in the FormRequest class:

protected function prepareForValidation() 
    {
        $this->merge(['token' => $this->route('token')]);
    }

I believe URL parameters are not included in the request directly.

Sign up to request clarification or add additional context in comments.

Comments

2

i might try going about it differently as the token isn't really user input

In the routes file:

Route::delete('/api/v1/auth/tokens/{token}', [TokensController::class, 'destroy'])->whereUuid('token');

In the FormRequest something maybe like this:

public function authorize()
{
    return DB::table('personal_access_tokens')
        ->where('tokenable_id', Auth::id())
        ->where('token', $this->route('token'))
        ->exists()
}

2 Comments

when using ->whereUuid('token') laravel will return a 404 instead of a validation exception when the token doesn't match the giver regex
non optional route parameters are required so we don't need that rule either. we also don't really need to validate a string when we are using regex and laravel (default) doesn't cast the route params which is default a string
0

With the help of both @RawSlugs and @Aaron T, thank them a lot!

app/Http/Requests/V1/Auth/Tokens/DestroyRequest.php

protected function prepareForValidation() {
    $this->merge(['token' => $this->route('token')]);
}

public function authorize() {
    return $this->user()->tokens()->where('id', $this->token)->exists();
}

// But since the authorize() will validate the request before rules(), this will be useless
public function rules() {
    return [
        'token' => [
            'required',
            'string',
            'regex:/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i',                       
        ]
    ];
}

I'm using Laravel Sanctum.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.