In Laravel, when would you sign a user in with Auth::login, loginUsingId, once or attemptWhen instead of Auth::attempt?
answer
- login: identity already proven
- loginUsingId returns the user or false
- once: this request only, no session
- attemptWhen callbacks run after the hash check
- falsy callback means a failed attempt
basics
~10 sUse Auth::login($user) or loginUsingId($id) when identity is already proven, once($credentials) to authenticate one request without a session, and attemptWhen() when sign-in must also pass checks on the loaded user after the password matches.
solid answer
~50 s`Auth::attempt()` both checks credentials and signs in. The others split those jobs. `Auth::login($user, $remember)` skips any check and signs in an `Authenticatable` you already trust, such as a user just created or one matched by an OAuth callback; it rotates the session ID like any login. `Auth::loginUsingId($id, $remember)` loads the user through the provider and returns the user, or `false` if none exists. `Auth::once($credentials)` validates credentials and sets the user **for this request only**: no session entry, no cookie, so it suits stateless requests such as a kiosk terminal that sends a member number and PIN on every call; `onceUsingId($id)` is the by-key variant. `Auth::attemptWhen($credentials, $callbacks, $remember)` works like `attempt()` but, after the password is verified, runs each callback with the user and the guard; any falsy result fails the attempt, fires `Failed` and returns `false`.
code
php · 15 lines<?php
use App\Models\User;
use Illuminate\Support\Facades\Auth;
// Inside a controller action that receives Request $request.
$signedIn = Auth::attemptWhen(
['email' => $request->email, 'password' => $request->password],
fn (User $user) => $user->membership_expires_at?->isFuture() ?? false,
);
// Kiosk terminal: authenticate this request only.
if (Auth::once(['member_number' => $request->member_number, 'password' => $request->pin])) {
return Auth::user()->bookings()->upcoming()->get();
}go deeper
Know that login() signs in a user you already have, and attempt() checks an email and password first.
Explain the table of methods: which check credentials, which write the session, what loginUsingId and onceUsingId return, and when attemptWhen callbacks run.
Treat login() call sites as trust boundaries, use once() for stateless or shared-terminal flows, and pick attemptWhen over query conditions when the rule needs the model.
Standardise which sign-in entry points exist in a codebase so every path shares throttling, auditing and rotation guarantees.
## Two jobs in one call `Auth::attempt()` does two things: it **verifies credentials** and it **signs the user in** to the session. Laravel's session guard exposes methods that do only one of those jobs, or that add conditions, and choosing between them is a common interview probe. ## The methods | Method | Checks a password | Writes the session | Returns | |---|---|---|---| | `attempt($credentials, $remember)` | yes | yes | `bool` | | `attemptWhen($credentials, $callbacks, $remember)` | yes, then callbacks | yes | `bool` | | `login($user, $remember)` | no | yes | nothing | | `loginUsingId($id, $remember)` | no | yes | the user, or `false` | | `once($credentials)` | yes | no | `bool` | | `onceUsingId($id)` | no | no | the user, or `false` | | `validate($credentials)` | yes | no, and sets no user | `bool` | ## `login()` and `loginUsingId()` Use these when **identity is already established** by something other than a password form: - right after a registration action creates the user; - after a social login callback has matched a local account; - after a magic-link or signed URL has been verified. They go through the same `login()` internals as `attempt()`: the session ID is regenerated, the password-hash marker is stored, the remember-me cookie is queued if requested, and `Login` fires. Because nothing checks a secret, **every call site is an authentication bypass if the preceding verification is wrong**. `loginUsingId()` returns `false` rather than throwing when the ID does not exist. ## `once()` and `onceUsingId()` `once()` validates credentials inside the same timebox as `attempt()`, then calls `setUser()` so `Auth::user()` works **for the rest of this request**. Nothing is written to the session and no cookie is queued. The next request is a guest again. In the kiosk scenario, a gym's check-in terminal might post a member number and PIN with every tap instead of holding a session between members: - no session exists to leak to the next person at the screen; - each request is authenticated independently; - `onceUsingId()` fits a trusted badge reader that has already identified the member. HTTP Basic's stateless variant, `Auth::onceBasic()`, is built on the same idea. ## `attemptWhen()` `attempt()` can already narrow the query with extra keys (`'active' => 1`) or a closure. That fails **before** the password check, and a mismatch looks exactly like a wrong password. `attemptWhen()` adds checks that run **after** the password has been verified, against the loaded model: 1. The provider looks the user up and verifies the password. 2. Each callback is called as `$callback($user, $guard)`. 3. If any returns a falsy value, the guard fires `Failed` and returns `false`. 4. Otherwise it signs in exactly like `attempt()`. Typical callbacks: `fn (User $user) => ! $user->isBanned()`, or a check that the member's subscription is current. It returns only `false`, so if the UI must say *why* sign-in was refused, check the condition yourself after a `validate()` call instead. ## Choosing - Form with email and password: `attempt()`. - Same, plus a rule about the loaded user: `attemptWhen()`. - Identity proven elsewhere: `login()` or `loginUsingId()`. - No session wanted: `once()` or `onceUsingId()`.
- Why is every Auth::login() call site worth a security review?`login()` signs in whatever `Authenticatable` it receives without checking any secret. If the code before it matched the wrong account, for example by trusting an unverified email from a social provider, the result is a sign-in as someone else. The verification before the call is the entire security boundary.
- How does attemptWhen differ from adding 'active' => 1 to the credentials array?Extra credential keys become `where` clauses, so an inactive user is simply not found, before any password check. `attemptWhen()` callbacks run after the password is verified and receive the loaded model, so they can use relationships, methods or dates. Both return a plain `false` on failure.
saying these in an interview costs you the question
- Auth::login() checks the password hash before signing the user in.
- Auth::once() writes the user into the session for later requests.
- loginUsingId() throws a ModelNotFoundException for an unknown ID.
- attemptWhen callbacks run before the password is checked.
- A failed attemptWhen callback throws an exception explaining the reason.