Login & logout
Login is owned by AuthenticatedSessionController, wired through two handlers that share the
auth/login path. Your app fills the LoginView seam by binding the
contract; the package owns validation, credential checks, rate limiting, event dispatch, session
regeneration, and the hand-off to the post-login pipeline and
multi-factor challenge.
Routes
Section titled “Routes”| Route name | Verb | Path | Middleware |
|---|---|---|---|
identity.login |
GET |
auth/login |
web, guest:identity |
identity.login.store |
POST |
auth/login |
web, guest:identity, throttle:5,1 |
GET identity.login renders through the bound LoginView contract. If none is bound, hitting the
route throws MissingAuthViewException.
The realm’s methods decides which of password, passkey
and social are accepted. A method left out has its routes closed — a hand-built POST gets a
404, not just a login page missing a button — and LoginPrompt::$methods tells the view which to
render. Registration and password reset hang off password: both end in a password the realm
would not otherwise accept.
The login flow (POST identity.login.store)
Section titled “The login flow (POST identity.login.store)”The store action is throttled to 5 requests per minute and runs the following steps:
- Validate. The username field (
config('oidc.login.username'), defaultemail) andpasswordare bothrequired|string. - Normalize. The username is lowercased before it is used as a credential.
- Verify credentials against the
identityguard’s user provider (retrieveByCredentials+validateCredentials). On failure the request throws aValidationExceptionwith the genericauth.failedmessage. Passwords are rehashed on login whenhashing.rehash_on_loginis enabled. - Record the primary factor. The
pwdauthentication method is recorded (it becomes part of theamrclaim — see Multi-factor). - Run the post-login pipeline. A
LoginEventis dispatched through the hooks registered onPostLoginPipeline. If a hook denies the login, the recorded factor is discarded and the request fails with the same genericauth.failedmessage. Queuedid_token/access_tokenclaims from the pipeline are stored on the session. - Branch on MFA (below).
- Branch on required actions. Before the session is established, the realm is asked whether the user still owes it anything — a confirmed address, a password inside the rotation window, an enrolled factor. If so the login parks: no session is created, and the user is sent to that action’s screen.
flowchart TD
A["POST identity.login.store"] --> B["Validate + lowercase username"]
B --> C{"Credentials valid?"}
C -- no --> F["Generic auth.failed error"]
C -- yes --> D["Record pwd factor"]
D --> E["Post-login pipeline"]
E -- "deny()" --> F
E -- ok --> G{"Challengeable factor enrolled?"}
G -- "no, but MFA required" --> L["Enroll a factor"]
G -- no --> M
G -- yes --> I["Stash pending login,<br/>redirect to two-factor challenge"]
I --> J["Verify factor (adds its amr)"]
J --> M
L --> M{"Anything the realm requires?"}
M -- yes --> N["Action screen"]
N --> M
M -- no --> H["Log in + regenerate session"]
H --> K["Redirect to intended / home"]
Deferring to a required action
Section titled “Deferring to a required action”If the realm still requires something of the user, the login is not completed: no session is created, a pending record naming the user is stored, and
- a JSON request receives
{"required_actions": ["update_password"]}. - a browser request is redirected to the first open action’s screen.
The required actions page covers the screens, the authorization-endpoint re-check, and how to add your own.
Success response
Section titled “Success response”When nothing is left to challenge or require, the user is logged in on the identity guard (honoring
the remember field), the session is regenerated, and:
- A JSON request (
wantsJson) receives an empty200response. - A browser request is redirected via
redirect()->intended(...)toconfig('oidc.login.home')(default/dashboard).
Deferring to the two-factor challenge
Section titled “Deferring to the two-factor challenge”After the primary factor succeeds, the package looks up the user’s confirmed, challengeable
enrollments, filtered by config('oidc.credentials.challenge_providers') (default ['totp']).
- If the post-login pipeline called
requireMfa()but the user has no challengeable factor, the login is denied. - If at least one challengeable enrollment exists, the login is not completed yet. The pending
user id,
rememberflag, and the first enrollment’s provider key and id are stashed on the session, and:- A JSON request receives
{"two_factor": true}. - A browser request is redirected to
identity.two-factor.login.
- A JSON request receives
The user finishes authenticating on the two-factor challenge, which performs
the actual guard->login() and session regeneration once a factor is verified.
Passkey login
Section titled “Passkey login”Passwordless login is delegated to laravel/passkeys through two guest routes:
| Route name | Verb | Path | Middleware |
|---|---|---|---|
identity.passkey.login-options |
GET |
auth/passkeys/login/options |
web, guest:identity, throttle:5,1 |
identity.passkey.login |
POST |
auth/passkeys/login |
web, guest:identity, throttle:5,1 |
The options endpoint returns the WebAuthn assertion challenge; the browser signs it and posts the
credential back to identity.passkey.login to establish the session. Passkey registration (and
its RequirePassword gate) lives on the multi-factor page.
Logout
Section titled “Logout”The auth engine deliberately ships no identity.logout route — the relying party keeps
Laravel’s conventional logout route name for itself. Log the user out of the interactive session
with the identity guard:
use Illuminate\Support\Facades\Auth;
Route::post('/logout', function (Request $request) { Auth::guard(config('oidc.auth.guard'))->logout(); $request->session()->invalidate(); $request->session()->regenerateToken();
return redirect('/');})->name('logout');Terminating the interactive session is separate from OIDC RP-initiated logout at
/oauth/logout, which relying parties use to end the OP session and any downstream sessions. That
endpoint and its CSRF threat model are documented under Logout.