NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

Balík obsahuje voliteľné JSON endpointy pre každý guard. Zaregistrujete ich cez routes.enabled = true pre guard, alebo explicitne:

// routes/api.php
use RoundlyConsulting\Auth\Facades\Authentication;

Authentication::routes('users');                                      // defaults

Authentication::routes('clients')
    ->prefix('api/clients/auth')
    ->name('clients.auth.')
    ->middleware(['api'])
    ->authenticatedMiddleware(['authentication.active'])
    ->except(['registration', 'invitations.manage']);

RouteRegistrar ponúka prefix(), name(), middleware(), authenticatedMiddleware(), only() a except(); routy zaregistruje pri deštrukcii. Predvolené: prefix {guard}/auth, názvy authentication.{guard}.*, middleware api. Dvojitá registrácia guardu vyhodí výnimku a rovnako aj registrácia guardu na výslednom prefixe či prefixe názvov rout, ktorý už obsadil iný guard (po prefix() / name(), cez routes.enabled aj ručné volanie) — Laravel by ponechal len poslednú routu pre URL; správa uvedie oba guardy. Skupiny pre only() / except(): login, challenge, tokens, registration, invitations, passwords, email, account, sessions, two-factor, passkeys, invitations.manage.

Endpointy

Každá routa má authentication.guard:{guard} a Cache-Control: no-store a existuje len vtedy, ak je jej funkcia pre guard zapnutá (vypnutá funkcia vráti 404). Tokeny vždy putujú v tele požiadavky (JSON). * = vyžaduje prihlásenie (auth:{laravel_guard}); ? = nepovinné.

MetódaURI (pod prefixom)TeloÚčel
POSTloginidentifier, passwordPrihlásenie heslom — identifier je ktorýkoľvek z identifier.columns (predvolene e-mail); pole email neexistuje.
POSTlogin/magic-linkemailVyžiadanie magic linku.
POSTlogin/magic-link/consumetokenPrihlásenie tokenom z odkazu.
POSTlogin/otpemailVyžiadanie e-mailového kódu.
POSTlogin/otp/verifyemail, codePrihlásenie kódom.
POSTlogin/passkey/options—Options pre prihlásenie passkey bez hesla.
POSTlogin/passkeycredentialPrihlásenie passkey bez hesla.
POSTchallenge/two-factorchallenge_token, code, method? (totp | recovery_code)TOTP alebo záložný kód (pod totp sa prijme oboje).
POSTchallenge/two-factor/enrolchallenge_tokenSpustenie vynúteného nastavenia TOTP (secret, QR kód, záložné kódy).
POSTchallenge/two-factor/enrol/confirmchallenge_token, codeJeho potvrdenie.
POSTchallenge/passkey/optionschallenge_tokenOptions pre passkey ako druhý faktor.
POSTchallenge/passkeychallenge_token, credentialPasskey ako druhý faktor.
POSTchallenge/passkey/enrol/optionschallenge_tokenOptions pre vynútenú registráciu passkey.
POSTchallenge/passkey/enrolchallenge_token, credential, name?Vynútená registrácia passkey.
POSTrefreshrefresh_tokenRotácia refresh tokenu (predošlý prístupový token prestane platiť).
POSTregisteremail, password (when required), attributes?Registrácia (attributes = vlastné polia z registration.rules).
POSTinvitations/previewtokenNa čo pozvánka slúži.
POSTinvitations/accepttoken, password (when required), email? (only when lock_email is off), attributes?Prijatie pozvánky.
POSTpassword/forgotemailVyžiadanie odkazu na obnovu hesla.
POSTpassword/resettoken, passwordObnova hesla.
POSTemail/verifytoken, email (with the code channel)Overenie adresy — token je token z odkazu alebo kód.
POSTemail/verification/resendemailOpätovné odoslanie overenia (bez prihlásenia).
POSTemail/change/confirmtokenPotvrdenie zmeny e-mailu (otvorené z e-mailu).
GET*me—Účet.
PATCH*localelocale?, timezone?Jazyk / časové pásmo.
POST*reauthenticatemethod + password | code | credentialOpätovné overenie — method je password, totp, recovery_code, email_otp alebo passkey.
POST*reauthenticate/passkey/options, reauthenticate/otp—Options pre passkey / odoslanie kódu na opätovné overenie.
GET*activityquery per_page?Vlastná prihlasovacia aktivita.
POST*logout, logout/others, logout/everywhere—Odhlásenia.
GET* / DELETE*sessions, sessions/{session}—Relácie zariadení.
PUT*passwordcurrent_password (when the account has one), passwordZmena hesla.
POST*email/changeemailŽiadosť o zmenu e-mailu.
POST*email/verification—Odoslanie overenia.
GET* POST* DELETE*two-factor, two-factor/recovery-codes—Stav, spustenie nastavenia, vypnutie, nové záložné kódy.
POST*two-factor/confirmcodePotvrdenie nastavenia.
GET* POST*passkeys, passkeys/optionspasskeys: credential, name?Zoznam, options na registráciu, registrácia.
PATCH* / DELETE*passkeys/{passkey}PATCH: namePremenovanie / odstránenie.
GET*invitationsquery status?, per_page?Správa pozvánok (Gate ability).
POST*invitationsemail, payload?, locale?, ttl? (seconds), send? (default true)Vytvorenie — 201 s data a odkazom v url (zobrazí sa raz; pri send: false sa nič neodošle a odkaz doručíte sami).
POST* / DELETE*invitations/{invitation}/resend, invitations/{invitation}—Opätovné odoslanie ({"status": "sent", "url": …}) / zrušenie.

Každý endpoint, ktorý prihlasuje, prijíma aj device_name? (zobrazí sa v zozname relácií); register a invitations/accept navyše timezone? (uloží sa k novému účtu). Zariadenie sa číta z hlavičky X-Device-Id (activity.new_device.header), jazyk z X-Locale / Accept-Language. credential je JSON objektu PublicKeyCredential z prehliadača s členmi v base64url, doplnený o ceremonyId options, na ktoré odpovedá.

Odpovede

// 200 — authenticated
{ "status": "authenticated", "token_type": "Bearer", "access_token": "eyJ…", "expires_in": 900,
  "expires_at": "2026-09-26T10:15:00Z", "refresh_token": "…", "refresh_expires_at": "2026-10-26T10:00:00Z",
  "session_id": "0199…" }

// 200 — challenge
{ "status": "challenge", "challenge_token": "…", "expires_at": "…", "attempts_left": 5, "method": "password",
  "completed": [], "remaining": [ { "step": "second_factor", "methods": ["totp", "recovery_code", "passkey"] } ] }

// 202 — enumeration-safe acknowledgement (magic link, email code, forgot, resend, email change)
{ "status": "sent" }

// error
{ "message": "…", "code": "invalid_credentials", "errors": { "identifier": ["…"] } }

Odpovede na zmenu prihlasovacích údajov (PUT password, POST two-factor/confirm, DELETE two-factor, POST two-factor/recovery-codes, POST passkeys, DELETE passkeys/{passkey}) obsahujú tokens alebo null. Ak nie je null, klient musí okamžite prejsť na nový pár — jeho predošlý prístupový token so zmenou zanikol.

Chyby

KódStatusKedy
invalid_credentials422Nesprávne prihlasovacie údaje (jednotná odpoveď).
invalid_token / invalid_code422Odkaz alebo kód z e-mailu je neplatný (jednotná odpoveď).
challenge_invalid / factor_failed / factor_not_allowed422Problémy s výzvou (attempts_left pri factor_failed).
invalid_invitation422Pozvánka je neplatná (jednotná odpoveď).
invitation_send_limit422Pozvánka bola odoslaná max_sends-krát — definitívne (bez Retry-After): zrušte ju a vytvorte novú.
passkey_registration_failed422Passkey sa nepodarilo zaregistrovať.
refresh_invalid401Refresh token je neplatný (jednotná odpoveď).
account_disabled / email_not_verified / enrolment_required / reauthentication_required403Stav účtu alebo pravidlá (methods pri opätovnom overení).
registration_closed / invitation_required / login_denied403Registrácia alebo riziko.
account_locked423Opätovne sa overujúci účet je uzamknutý.
too_many_attempts429Prekročený limit alebo tvrdo uzamknutý účet pri prihlásení odkazom, kódom či passkey (Retry-After).
two_factor_required / last_credential / two_factor_already_enabled / two_factor_not_enabled409Odmietnuté zmeny.
method_disabled / not_found404Funkcia vypnutá alebo neznáme id.
validačná chyba poľa password422Služba kontroly uniknutých hesiel nedostupná pri fail_closed.
misconfigured500Chyba konfigurácie (detail len pri app.debug).

Úprava chybovej odpovede

Každá výnimka balíka sa vykreslí sama — {message, code, errors?, …extra} s Cache-Control: no-store — a globálneho handlera sa nedotkne. Handler Laravelu (rovnaký v Laraveli 12 aj 13) najprv použije mapovače $exceptions->map(), potom nechá odpovedať výnimku s vlastnou metódou render() a až potom spustí callbacky $exceptions->render() / renderable(). Callback render() pre výnimku balíka sa preto nikdy nespustí. Fungujú dva háčiky:

use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Http\Request;
use RoundlyConsulting\Auth\Exceptions\AuthenticationMisconfigured;
use RoundlyConsulting\Auth\Exceptions\AuthException;
use Symfony\Component\HttpFoundation\Response;

->withExceptions(function (Exceptions $exceptions): void {
    // Reshape the rendered response; the status, Cache-Control and Retry-After stay:
    $exceptions->respond(function (Response $response, Throwable $e, Request $request): Response {
        if ($e instanceof AuthException) {
            $response->setContent((string) json_encode(['error' => ['code' => $e->errorCode(), 'message' => $e->getMessage()]]));
        }

        return $response;
    });

    // Or replace the exception before Laravel renders it (misconfiguration left alone):
    $exceptions->map(AuthException::class, fn (AuthException $e): Throwable =>
        $e instanceof AuthenticationMisconfigured ? $e : new ApiProblem($e));
});

Výnimka hostiteľa prenesie všetko, čo by poslal render() balíka:

use Illuminate\Http\JsonResponse;
use RoundlyConsulting\Auth\Exceptions\AuthException;

final class ApiProblem extends RuntimeException
{
    public function __construct(public readonly AuthException $auth)
    {
        parent::__construct($auth->getMessage(), 0, $auth);
    }

    public function render(): JsonResponse
    {
        $extra = $this->auth->extra();   // retry_after, attempts_left, methods
        $headers = ['Content-Type' => 'application/problem+json', 'Cache-Control' => 'no-store, private', 'Pragma' => 'no-cache'];

        if (isset($extra['retry_after'])) {
            $headers['Retry-After'] = (string) $extra['retry_after'];   // 423 and 429
        }

        return new JsonResponse(
            ['type' => $this->auth->errorCode(), 'title' => $this->getMessage(), 'status' => $this->auth->status(), ...$extra],
            $this->auth->status(),
            $headers,
        );
    }

    public function report(): bool
    {
        return true;   // map() also runs when Laravel reports: stay unreported, like the package exception
    }
}
  • respond() beží na každej vykreslenej odpovedi vrátane tých, ktoré sa vykreslili samy, a dostane $response, $e a $request. Vidí aj odpovede, ktoré nepochádzajú z balíka, preto sa rozhodujte podľa $e.
  • map() sa uplatní aj pri reportovaní výnimky, takže reportuje sa už namapovaná. Nechajte ju nereportovanú (report() vracia true, alebo ju uveďte v dontReport), inak sa vám nástroj na sledovanie chýb zaplní neúspešnými prihláseniami.
  • Pri map() vykreslíte všetko sami: status (status()), doplnkové členy (extra(): retry_after, attempts_left, methods), field(), ak klienti čítajú errors, a hlavičky — vždy Cache-Control: no-store, private a pri 423 a 429 Retry-After.
  • AuthenticationMisconfigured (a GuardNotConfigured) nemapujte: jej správa uvádza chybný kľúč konfigurácie, render() balíka ju ukáže len pri app.debug a je to jediná výnimka, ktorú balík chce reportovať.
  • Ak mapujete na výnimku bez vlastnej metódy render(), vaše callbacky render() ju uvidia — výnimka balíka je jej getPrevious().

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.