Security Tip: Be Careful of Auth Helpers!

[Tip#20] Laravel's helpers are great, but make sure you know everything they do before you use them.

Security Tip: Be Careful of Auth Helpers!

🤓 Learn to Think Like a Hacker with my hands-on practical security course: Practical Laravel Security! 🕵️

⚠️ Need a security audit but don't have the budget for a full penetration test? Book in a Laravel Security Review! 🕵️


Be Careful of Auth Helpers

(There is a TL;DR at the bottom - I don’t want to ruin the suspense, but scroll down if you’re busy.)

Laravel’s Authentication system is incredibly powerful and coupled with the Auth Facade, it makes it trivial to access the logged in user where you need to. However, you also need to be careful - this power and ease also opens up some huge risks you need to be aware of.

Within the normal login request flow, you’ll authenticate the user once and they’ll still be logged in to each subsequent request, allowing you to access the user model easily via the Auth Facade. But what if you have a special public or private URL that provides access to something within the user context for a single request, but isn’t accessed by the user? You still need to access the user model easily but you don’t want their session persisted into the subsequent requests.

Consider a draft post URL1 that the author can provide for unauthenticated users to view the draft. It’s tempting to reuse code which calls the Auth Facade, but then you’ll need to effectively log the user to load the Auth Facade. So you may find yourself doing something like this:

public function view(Post $post) 
{
    Auth::loginUsingId($post->user_id);

    return view('posts.preview', [
        'post' => (new PostEditor($post))->readOnly(),
    ]);
}

It seems simple enough - you’re temporarily logging the user in so the post can be loaded in the user context, so you can reuse the same code.

Makes sense, right?

Nope!

The problem is `Auth::loginUsingId()` logs the user in and initiates a session. The visitor is now logged in and will have full access to the user account on subsequent requests.

You never want to do this. Don’t even consider doing it and then immediately logging out2! Just don’t do it! Please!

I would highly recommend not using the Auth Facade in this situation at all, instead, you should pass the User model around where you need it. It’s much safer as you’ll know there is no chance of anything from the user persisting.

public function view(Post $post) 
{
    $user = $post->user;

    return view('posts.preview', [
        'user' => $user,
        'post' => (new PostEditor($post, $user))->readOnly(),
    ]);
}
If you do need to use the Auth Facade to load the user within these special requests, you can safely use the `Auth::onceUsingId($userId)` function. It loads the specified model as the current user for the current request only.

TL;DR → Don’t use `Auth::loginUsingId()` on guest URLs, it sets up a full authentication session and you’ll be logging everyone in as that user.


  1. For example, the draft post URL for this post is: https://securinglaravel.com/7652881d-0ca7-47a8-8253-f275837ab1ed

  2. Session info and cookies may somehow be persisted, so this is a terrible idea.