본문 바로가기

Fortify

업데이트됨

번역일: 2026년 9월 17일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 9월 17일
번역 갱신
2026년 9월 17일

Fortify

소개

Fortify란?

Laravel Fortify는 프론트엔드에 구애받지 않는(frontend-agnostic) Laravel 인증 백엔드 구현체입니다. Fortify는 로그인, 회원가입, 비밀번호 재설정, 이메일 인증 등 Laravel이 지원하는 모든 인증 기능을 구현하는 라우트와 컨트롤러를 등록해줍니다. Fortify를 설치한다고 해서 화면에 UI가 생기는 것은 아니며, 각 라우트에 대응하는 뷰를 여러분이 직접 만들어 연결해야 합니다.

NOTE

Fortify는 어디까지나 Laravel의 인증 기능을 구현하는 데 도움을 주는 패키지입니다. Fortify를 사용하지 않아도 인증, 비밀번호 재설정, 이메일 인증 문서를 참고해 직접 Laravel의 인증 기능을 사용할 수 있습니다.

Laravel을 처음 접한다면, Laravel Breeze 스타터 키트를 먼저 살펴보는 것을 권장합니다. Laravel Breeze는 Tailwind CSS로 만들어진 UI를 포함한 인증 스캐폴딩을 제공합니다. Fortify와 달리 Breeze는 라우트와 컨트롤러를 여러분의 애플리케이션에 직접 퍼블리시(publish)하기 때문에, 코드를 직접 살펴보고 학습한 뒤 Laravel의 인증 기능이 어떻게 동작하는지 이해하며 원하는 대로 자유롭게 수정할 수 있습니다.

Fortify는 사실 Laravel Breeze의 라우트와 컨트롤러를 별도 패키지로 분리한 것으로, 프론트엔드의 특정한 형태에 얽매이지 않습니다. 즉, Breeze처럼 뷰까지 함께 제공하지 않고도 애플리케이션의 인증 백엔드를 빠르게 구축하고 싶은 경우에 적합합니다. 예를 들어 Fortify를 사용하면 HTTP 요청을 특정 URL로 보내 사용자를 인증하는 절차는 그대로 활용하면서, 로그인 화면은 Inertia로 직접 작성한 UI로 대체하는 식의 구성이 가능합니다.

Fortify는 언제 사용해야 할까?

Laravel Fortify를 언제 사용하는 것이 적합한지 궁금할 수 있습니다. 먼저 Laravel의 스타터 키트를 사용하는 경우와 비교해서 생각해보면 이해하기 쉽습니다.

가장 먼저 고려할 점은, 이미 Laravel 스타터 키트를 사용 중이라면 별도로 Laravel Fortify를 설치할 필요가 없다는 것입니다. Laravel의 모든 스타터 키트는 이미 완전한 인증 구현을 제공하기 때문입니다.

스타터 키트를 사용하지 않고 애플리케이션에 인증 기능이 필요한 경우에는 두 가지 선택지가 있습니다. 인증 기능을 직접 처음부터 구현하거나, Laravel Fortify를 설치해 백엔드 구현을 맡기는 방법입니다.

Fortify를 설치하기로 했다면, 뷰는 이 문서에서 설명하는 Fortify의 인증 라우트를 참조하도록 직접 작성하게 됩니다.

반면 Laravel Fortify를 전혀 사용하지 않는 방법도 있습니다. 이 경우 인증, 비밀번호 재설정, 이메일 인증 문서를 참고하여 Laravel의 인증 서비스를 직접 다뤄야 합니다. 이 방법 역시 충분히 가능합니다. 필요한 도구는 이미 프레임워크 자체에 포함되어 있기 때문입니다.

Fortify와 Laravel Sanctum의 차이

일부 개발자는 Laravel Sanctum과 Laravel Fortify의 차이를 혼동하곤 합니다. 두 패키지는 서로 다른, 그러나 연관된 문제를 해결하기 때문에 Fortify와 Sanctum은 서로 경쟁 관계에 있는 패키지가 아니며 상호 배타적인 패키지도 아닙니다.

Laravel Sanctum은 API 토큰 관리와 세션 쿠키 또는 토큰을 이용한 기존 사용자 인증만을 다룹니다. Sanctum은 사용자 등록, 비밀번호 재설정 등을 처리하는 라우트를 전혀 제공하지 않습니다.

API를 제공하는 애플리케이션이나 SPA(싱글 페이지 애플리케이션)의 백엔드 역할을 하는 애플리케이션에서 인증 기능을 직접 구현하려는 경우, Laravel Fortify(회원가입, 비밀번호 재설정 등 사용자 인증을 위한 라우트 제공)와 Laravel Sanctum(API 토큰 관리, 세션 인증 처리)을 함께 사용하는 것도 충분히 가능합니다.

설치

먼저 Composer 패키지 관리자를 이용해 Fortify를 설치합니다.

composer require laravel/fortify

다음으로, vendor:publish 명령어를 사용해 Fortify의 리소스를 퍼블리시합니다.

php artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"

이 명령어를 실행하면 Fortify의 액션들이 app/Actions 디렉터리에 퍼블리시됩니다(해당 디렉터리가 없다면 새로 생성됩니다). 또한 FortifyServiceProvider, 설정 파일, 필요한 모든 데이터베이스 마이그레이션 파일도 함께 퍼블리시됩니다.

그다음 데이터베이스 마이그레이션을 실행합니다.

php artisan migrate

Fortify 기능

fortify 설정 파일에는 features 설정 배열이 있습니다. 이 배열은 Fortify가 기본적으로 노출하는 백엔드 라우트/기능 중 어떤 것을 활성화할지 정의합니다. Fortify를 Laravel Jetstream과 조합하지 않고 단독으로 사용하는 경우, 대부분의 Laravel 애플리케이션에서 제공하는 기본 인증 기능(로그인, 회원가입, 비밀번호 재설정 등)만 활성화하는 것을 권장합니다.

'features' => [ Features::registration(), Features::resetPasswords(), Features::emailVerification(), ],

뷰 비활성화하기

기본적으로 Fortify는 로그인 화면이나 회원가입 화면 같은 뷰를 반환하는 라우트를 정의합니다. 하지만 자바스크립트 기반 SPA를 구축하는 경우라면 이러한 라우트가 필요 없을 수 있습니다. 이럴 때는 애플리케이션의 config/fortify.php 설정 파일에서 views 설정 값을 false로 지정하여 해당 라우트들을 완전히 비활성화할 수 있습니다.

'views' => false,

뷰 비활성화와 비밀번호 재설정

Fortify의 뷰를 비활성화하면서 동시에 애플리케이션에서 비밀번호 재설정 기능을 구현하려는 경우, 비밀번호 재설정 화면을 보여주는 역할은 여전히 password.reset이라는 이름을 가진 라우트가 담당해야 합니다. 이는 Laravel의 Illuminate\Auth\Notifications\ResetPassword 알림이 비밀번호 재설정 URL을 password.reset 이름의 라우트를 통해 생성하기 때문입니다.

인증

먼저 Fortify에게 "로그인" 뷰를 어떻게 반환할지 알려주어야 합니다. Fortify는 헤드리스(headless) 인증 라이브러리라는 점을 기억하세요. 이미 완성된 프론트엔드 구현이 포함된 Laravel 인증 프론트엔드가 필요하다면 애플리케이션 스타터 키트를 사용하는 것이 좋습니다.

인증 뷰를 렌더링하는 로직은 모두 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 지정할 수 있습니다. 일반적으로 이 메서드는 애플리케이션의 App\Providers\FortifyServiceProvider 클래스의 boot 메서드에서 호출합니다. Fortify가 이 뷰를 표시하는 라우트를 자동으로 정의해줍니다.

use Laravel\Fortify\Fortify; /** * 모든 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::loginView(function () { return view('auth.login'); }); // ... }

Fortify는 resources/views/auth/login.blade.php에 위치한 로그인 템플릿을 포함해서 로그인 라우트를 정의해줍니다.

로그인 화면 템플릿에는 /login으로 POST 요청을 보내는 폼이 있어야 합니다. /login 엔드포인트는 문자열 형태의 email/username과 password를 기대합니다. 이메일/username 필드의 이름은 config/fortify.php 설정 파일에 있는 username 값과 일치해야 합니다. 또한 사용자가 "로그인 상태 유지" 기능을 선택할 수 있도록 불리언 형태의 remember 필드도 지정할 수 있습니다.

로그인 시도가 성공하면 Fortify는 fortify 설정 파일의 home 설정 값에 지정된 URI로 리다이렉트합니다. 로그인 요청이 XHR 요청이었다면 200 HTTP 응답이 반환됩니다.

요청이 실패하면 사용자는 다시 로그인 화면으로 리다이렉트되며, $errors 공유 뷰 변수를 통해 검증 에러를 확인할 수 있습니다. XHR 요청인 경우에는 422 HTTP 응답과 함께 검증 에러가 반환됩니다.

사용자 인증 커스터마이징

Fortify는 제공된 자격 증명과 애플리케이션에 설정된 인증 가드를 기반으로 자동으로 사용자를 조회하고 인증합니다. 그러나 로그인 자격 증명을 검증하고 사용자를 조회하는 방식을 완전히 커스터마이징하고 싶은 경우가 있습니다. 다행히 Fortify는 Fortify::authenticateUsing 메서드를 통해 쉽게 이를 처리할 수 있도록 지원합니다.

이 메서드는 클로저를 인수로 받으며, 이 클로저는 들어오는 HTTP 요청을 받아 로그인 자격 증명을 검증하고, 그에 해당하는 사용자 인스턴스를 반환해야 합니다. 자격 증명이 유효하지 않거나 일치하는 사용자를 찾을 수 없는 경우에는 null 또는 false를 반환해야 합니다. 이 메서드는 보통 FortifyServiceProvider의 boot 메서드에서 호출합니다.

use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Laravel\Fortify\Fortify; /** * 모든 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::authenticateUsing(function (Request $request) { $user = User::where('email', $request->email)->first(); if ($user && Hash::check($request->password, $user->password)) { return $user; } }); // ... }

인증 가드

애플리케이션의 fortify 설정 파일에서 Fortify가 사용할 인증 가드를 커스터마이징할 수 있습니다. 다만, 커스터마이징한 가드가 Illuminate\Contracts\Auth\StatefulGuard의 구현체인지 확인해야 합니다. SPA 인증을 위해 Laravel Fortify를 사용하려는 경우, 기본 web 가드와 Laravel Sanctum을 함께 사용하는 것이 좋습니다.

인증 파이프라인 커스터마이징

Laravel Fortify는 로그인 요청을 여러 개의 인보커블(invokable) 클래스로 구성된 파이프라인을 통해 인증합니다. 원한다면 로그인 요청이 통과해야 하는 커스텀 파이프라인 클래스를 직접 정의할 수도 있습니다. 각 클래스에는 Illuminate\Http\Request 인스턴스와, 파이프라인의 다음 클래스로 요청을 전달하는 역할을 하는 $next 변수를 받는 __invoke 메서드가 있어야 합니다.

커스텀 파이프라인을 정의하려면 Fortify::authenticateThrough 메서드를 사용합니다. 이 메서드는 로그인 요청이 통과할 클래스 배열을 반환하는 클로저를 인수로 받습니다. 보통 이 메서드는 App\Providers\FortifyServiceProvider 클래스의 boot 메서드에서 호출합니다.

아래는 커스터마이징할 때 참고할 수 있는 기본 파이프라인 정의입니다.

use Laravel\Fortify\Actions\AttemptToAuthenticate; use Laravel\Fortify\Actions\CanonicalizeUsername; use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled; use Laravel\Fortify\Actions\PrepareAuthenticatedSession; use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable; use Laravel\Fortify\Fortify; use Illuminate\Http\Request; Fortify::authenticateThrough(function (Request $request) { return array_filter([ config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class, Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null, CanonicalizeUsername::class, AttemptToAuthenticate::class, PrepareAuthenticatedSession::class, ]); });

인증 스로틀링

기본적으로 Fortify는 EnsureLoginIsNotThrottled 미들웨어를 이용해 인증 시도를 스로틀링합니다. 이 미들웨어는 사용자명과 IP 주소의 조합에 대해 스로틀링을 적용합니다.

일부 애플리케이션은 IP 주소별로만 제한을 적용하는 등 인증 시도 스로틀링에 대해 다른 방식을 요구할 수도 있습니다. 이를 위해 Fortify는 fortify.limiters.login 설정 옵션을 통해 자체 레이트 리미터를 지정할 수 있도록 지원합니다. 이 설정은 애플리케이션의 config/fortify.php 설정 파일에서 확인할 수 있습니다.

NOTE

스로틀링과 Laravel Fail2Ban 같은 솔루션을 조합하는 방식은 악의적인 사용자가 실제 방화벽 수준에서 완전히 차단당하는, 더욱 강력한 방어 계층을 제공합니다.

리다이렉트 커스터마이징

로그인 시도가 성공하면 Fortify는 fortify 설정 파일의 home 설정 값에 지정된 URI로 리다이렉트합니다. 로그인 요청이 XHR 요청이었다면 200 HTTP 응답이 반환됩니다. 사용자가 로그아웃한 후에는 / URI로 리다이렉트됩니다.

이러한 동작을 더 세밀하게 커스터마이징해야 한다면, Laravel\Fortify\Contracts\LoginResponse 및 Laravel\Fortify\Contracts\LogoutResponse 계약(contract)의 구현체를 Laravel 서비스 컨테이너에 바인딩하면 됩니다. 보통 이 작업은 애플리케이션의 App\Providers\FortifyServiceProvider 클래스의 register 메서드에서 수행합니다.

use Laravel\Fortify\Contracts\LogoutResponse; /** * 모든 애플리케이션 서비스를 등록합니다. */ public function register(): void { $this->app->instance(LogoutResponse::class, new class implements LogoutResponse { public function toResponse($request) { return redirect('/'); } }); }

소개

Laravel Fortify는 프론트엔드에 종속되지 않는 Laravel 인증 백엔드 구현체입니다. Fortify는 로그인, 회원가입, 비밀번호 재설정, 이메일 인증 등 Laravel의 모든 인증 기능을 구현하는 데 필요한 라우트와 컨트롤러를 등록해줍니다. Fortify를 설치한 후 route:list Artisan 명령어를 실행해보면 Fortify가 등록한 라우트들을 확인할 수 있습니다.

Fortify는 자체적인 사용자 인터페이스(UI)를 제공하지 않습니다. 대신 여러분이 직접 만든 UI에서 Fortify가 등록한 라우트로 요청을 보내는 방식으로 사용하도록 설계되었습니다. 이 문서의 나머지 부분에서는 이러한 라우트에 요청을 보내는 구체적인 방법을 다룹니다.

NOTE

Fortify는 Laravel의 인증 기능 구현을 빠르게 시작할 수 있도록 도와주는 패키지일 뿐입니다. 반드시 사용해야 하는 것은 아닙니다. 언제든지 인증, 비밀번호 재설정, 이메일 인증 문서를 참고하여 Laravel의 인증 서비스를 직접 다룰 수 있습니다.

Fortify란 무엇인가?

앞서 설명한 것처럼, Laravel Fortify는 프론트엔드에 종속되지 않는 Laravel 인증 백엔드 구현체입니다. 로그인, 회원가입, 비밀번호 재설정, 이메일 인증 등 Laravel의 모든 인증 기능을 구현하는 데 필요한 라우트와 컨트롤러를 등록해줍니다.

Laravel의 인증 기능을 사용하기 위해 반드시 Fortify를 사용해야 하는 것은 아닙니다. 언제든지 인증, 비밀번호 재설정, 이메일 인증 문서를 참고하여 Laravel의 인증 서비스를 직접 다룰 수 있습니다.

Laravel을 처음 접하는 개발자라면 먼저 애플리케이션 스타터 키트를 살펴보는 것을 추천합니다. Laravel의 애플리케이션 스타터 키트는 내부적으로 Fortify를 사용하며, Tailwind CSS로 만들어진 UI를 포함한 인증 스캐폴딩을 제공합니다. 이를 통해 Laravel의 인증 기능을 직접 살펴보고 익숙해질 수 있습니다.

간단히 말해, Laravel Fortify는 애플리케이션 스타터 키트에 포함된 라우트와 컨트롤러를 UI 없이 패키지 형태로 분리해 제공하는 것입니다. 덕분에 특정 프론트엔드 방식에 얽매이지 않고도 애플리케이션의 인증 계층 백엔드 구현을 빠르게 만들어낼 수 있습니다.

Fortify는 언제 사용해야 할까?

"그래서 Fortify는 언제 사용하는 게 맞을까?"라는 의문이 들 수 있습니다. 먼저, Laravel의 애플리케이션 스타터 키트 중 하나를 사용하고 있다면 Laravel Fortify를 별도로 설치할 필요가 없습니다. 모든 애플리케이션 스타터 키트는 이미 Fortify를 내부적으로 사용하고 있고, 완전한 인증 구현을 함께 제공하기 때문입니다.

스타터 키트를 사용하지 않는데 애플리케이션에 인증 기능이 필요하다면 두 가지 선택지가 있습니다. 인증 기능을 직접 구현하거나, Laravel Fortify를 사용해 백엔드 구현을 맡기는 것입니다.

Fortify를 설치하기로 했다면, 여러분의 UI는 이 문서에서 설명하는 Fortify의 인증 라우트로 요청을 보내 사용자를 인증하고 등록하게 됩니다.

반대로 Fortify를 사용하지 않고 Laravel의 인증 서비스를 직접 다루고 싶다면, 인증, 비밀번호 재설정, 이메일 인증 문서를 참고하면 됩니다.

Laravel Fortify와 Laravel Sanctum

Laravel Sanctum과 Laravel Fortify의 차이를 헷갈려 하는 개발자들이 종종 있습니다. 두 패키지는 서로 다르지만 연관된 문제를 해결하기 때문에, Fortify와 Sanctum은 상호 배타적이거나 경쟁 관계에 있는 패키지가 아닙니다.

Laravel Sanctum은 오직 API 토큰 관리와, 세션 쿠키 또는 토큰을 이용한 기존 사용자 인증만을 담당합니다. 회원가입이나 비밀번호 재설정 같은 라우트는 제공하지 않습니다.

만약 API를 제공하거나 SPA(싱글 페이지 애플리케이션)의 백엔드 역할을 하는 애플리케이션의 인증 계층을 직접 구축하려 한다면, 회원가입·비밀번호 재설정 등에는 Laravel Fortify를, API 토큰 관리·세션 인증에는 Laravel Sanctum을 함께 사용하게 될 가능성이 높습니다.

설치

먼저 Composer로 Fortify 패키지를 설치합니다:

composer require laravel/fortify

그다음 fortify:install Artisan 명령어로 Fortify의 리소스를 퍼블리시합니다:

php artisan fortify:install

이 명령어를 실행하면 app/Actions 디렉터리(존재하지 않으면 새로 생성됩니다)에 Fortify의 액션 클래스들이 퍼블리시됩니다. 또한 FortifyServiceProvider, 설정 파일, 그리고 필요한 데이터베이스 마이그레이션 파일들도 함께 퍼블리시됩니다.

이어서 마이그레이션을 실행해 데이터베이스를 반영합니다:

php artisan migrate

Fortify 기능

fortify 설정 파일에는 features 설정 배열이 있습니다. 이 배열은 Fortify가 기본적으로 노출할 백엔드 라우트/기능을 정의합니다. 대부분의 Laravel 애플리케이션에서 기본적으로 사용하는 인증 기능인 다음 항목들만 활성화하는 것을 권장합니다:

'features' => [ Features::registration(), Features::resetPasswords(), Features::emailVerification(), ],

NOTE

features 배열에 나열되지 않은 기능(예: 2단계 인증)은 필요할 때 언제든 추가로 활성화할 수 있습니다. 처음에는 꼭 필요한 기능만 켜두고, 애플리케이션이 성장함에 따라 점진적으로 늘려가는 방식을 권장합니다.

뷰 비활성화하기

Fortify는 기본적으로 로그인 화면이나 회원가입 화면처럼 뷰를 반환하는 라우트를 함께 정의합니다. 하지만 Vue, React 등으로 만든 자바스크립트 기반 SPA(싱글 페이지 애플리케이션)를 구축하는 경우에는 이러한 뷰 라우트가 필요하지 않을 수 있습니다. 이런 경우 애플리케이션의 config/fortify.php 설정 파일에서 views 설정 값을 false로 지정하여 뷰 관련 라우트를 완전히 비활성화할 수 있습니다:

'views' => false,

뷰 비활성화와 비밀번호 재설정

Fortify의 뷰를 비활성화하면서 비밀번호 재설정 기능은 그대로 구현하려는 경우, password.reset이라는 이름의 라우트는 별도로 직접 정의해야 합니다. 이 라우트는 애플리케이션의 "비밀번호 재설정" 화면을 보여주는 역할을 합니다. Laravel의 Illuminate\Auth\Notifications\ResetPassword 알림 클래스가 비밀번호 재설정 URL을 생성할 때 바로 이 password.reset이라는 이름의 라우트를 참조하기 때문에, 이름이 정확히 일치해야 합니다.

인증

가장 먼저 해야 할 일은 Fortify에게 "로그인" 뷰를 어떻게 반환할지 알려주는 것입니다. Fortify는 프론트엔드가 없는 헤드리스(headless) 인증 라이브러리라는 점을 기억해 두세요. 이미 완성된 형태의 프론트엔드 인증 화면이 필요하다면, 처음부터 Fortify를 직접 다루기보다는 애플리케이션 스타터 키트를 사용하는 편이 훨씬 편합니다.

인증 관련 뷰를 렌더링하는 로직은 모두 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 원하는 대로 커스터마이징할 수 있습니다. 보통 이런 설정은 애플리케이션의 App\Providers\FortifyServiceProvider 클래스에 있는 boot 메서드 안에서 호출합니다. 아래처럼 설정해두면 Fortify가 /login 라우트를 알아서 정의하고, 요청이 들어오면 지정한 뷰를 반환해줍니다:

use Laravel\Fortify\Fortify; /** * Bootstrap any application services. */ public function boot(): void { Fortify::loginView(function () { return view('auth.login'); }); // ... }

로그인 템플릿에는 /login으로 POST 요청을 보내는 폼이 있어야 합니다. /login 엔드포인트는 문자열 타입의 email (또는 username)과 password를 기대합니다. 이메일/사용자명 필드의 이름은 config/fortify.php 설정 파일에 정의된 username 값과 일치해야 합니다. 여기에 더해, "로그인 유지" 기능을 사용하고 싶다면 boolean 타입의 remember 필드를 함께 전달하면 됩니다.

로그인이 성공하면 Fortify는 애플리케이션의 fortify 설정 파일에 정의된 home 설정 값으로 지정된 URI로 리다이렉트합니다. 만약 로그인 요청이 XHR 요청이었다면 200 HTTP 응답이 반환됩니다.

반대로 로그인에 실패하면 사용자는 로그인 화면으로 다시 리다이렉트되며, 유효성 검사 오류는 공유 변수인 $errors Blade 템플릿 변수를 통해 확인할 수 있습니다. XHR 요청의 경우에는 유효성 검사 오류가 422 HTTP 응답과 함께 반환됩니다.

사용자 인증 방식 커스터마이징하기

기본적으로 Fortify는 전달받은 자격 증명과 애플리케이션에 설정된 인증 가드를 기준으로 사용자를 조회하고 인증합니다. 하지만 로그인 자격 증명을 검증하고 사용자를 조회하는 과정을 완전히 직접 제어하고 싶을 때도 있을 겁니다. 이런 경우 Fortify::authenticateUsing 메서드를 사용하면 쉽게 원하는 방식으로 구현할 수 있습니다.

이 메서드는 들어오는 HTTP 요청을 인자로 받는 클로저를 인수로 받습니다. 이 클로저 안에서 요청에 담긴 로그인 자격 증명을 검증하고, 검증에 성공하면 해당 사용자 인스턴스를 반환해야 합니다. 자격 증명이 유효하지 않거나 사용자를 찾을 수 없다면 null 또는 false를 반환하면 됩니다. 이 메서드도 보통 FortifyServiceProvider의 boot 메서드 안에서 호출합니다:

use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Laravel\Fortify\Fortify; /** * Bootstrap any application services. */ public function boot(): void { Fortify::authenticateUsing(function (Request $request) { $user = User::where('email', $request->email)->first(); if ($user && Hash::check($request->password, $user->password)) { return $user; } }); // ... }

인증 가드

Fortify가 사용하는 인증 가드는 애플리케이션의 fortify 설정 파일에서 원하는 대로 바꿀 수 있습니다. 다만 설정하는 가드는 반드시 Illuminate\Contracts\Auth\StatefulGuard 인터페이스를 구현하고 있어야 합니다. 만약 Laravel Fortify로 SPA를 인증하려 한다면, Laravel의 기본 web 가드를 Laravel Sanctum과 함께 사용하는 것을 권장합니다.

인증 파이프라인 커스터마이징하기

Laravel Fortify는 로그인 요청을 호출 가능한(invokable) 클래스들로 구성된 파이프라인을 통해 처리하며 인증을 수행합니다. 원한다면 로그인 요청이 거쳐 가는 이 파이프라인을 여러분만의 클래스로 직접 정의할 수도 있습니다. 파이프라인에 포함되는 각 클래스는 __invoke 메서드를 가지고 있어야 하며, 이 메서드는 들어오는 Illuminate\Http\Request 인스턴스와, 미들웨어에서처럼 파이프라인의 다음 클래스로 요청을 넘겨주는 역할을 하는 $next 변수를 인자로 받습니다.

커스텀 파이프라인을 정의하려면 Fortify::authenticateThrough 메서드를 사용하면 됩니다. 이 메서드는 로그인 요청이 거쳐 갈 클래스들의 배열을 반환하는 클로저를 인수로 받습니다. 이 메서드 역시 보통 App\Providers\FortifyServiceProvider 클래스의 boot 메서드에서 호출합니다.

아래 예제는 Fortify의 기본 파이프라인 정의를 보여줍니다. 직접 파이프라인을 수정할 때 시작점으로 참고하기 좋습니다:

use Laravel\Fortify\Actions\AttemptToAuthenticate; use Laravel\Fortify\Actions\CanonicalizeUsername; use Laravel\Fortify\Actions\EnsureLoginIsNotThrottled; use Laravel\Fortify\Actions\PrepareAuthenticatedSession; use Laravel\Fortify\Actions\RedirectIfTwoFactorAuthenticatable; use Laravel\Fortify\Features; use Laravel\Fortify\Fortify; use Illuminate\Http\Request; Fortify::authenticateThrough(function (Request $request) { return array_filter([ config('fortify.limiters.login') ? null : EnsureLoginIsNotThrottled::class, config('fortify.lowercase_usernames') ? CanonicalizeUsername::class : null, Features::enabled(Features::twoFactorAuthentication()) ? RedirectIfTwoFactorAuthenticatable::class : null, AttemptToAuthenticate::class, PrepareAuthenticatedSession::class, ]); });

이 파이프라인이 어떻게 동작하는지 그림으로 표현하면 다음과 같습니다:

인증 시도 제한 (Throttling)

기본적으로 Fortify는 EnsureLoginIsNotThrottled 미들웨어를 사용해 인증 시도 횟수를 제한합니다. 이 미들웨어는 사용자명과 IP 주소의 조합을 기준으로 시도 횟수를 제한합니다.

애플리케이션에 따라서는 IP 주소만을 기준으로 제한하는 등, 다른 방식의 제한 로직이 필요할 수도 있습니다. 이런 경우 config/fortify.php 설정 파일의 fortify.limiters.login 옵션을 통해 원하는 속도 제한기(rate limiter)를 직접 지정할 수 있습니다.

NOTE

시도 횟수 제한, 2단계 인증, 그리고 외부 웹 애플리케이션 방화벽(WAF)을 함께 사용하면 실제 서비스 사용자들을 가장 안전하게 보호할 수 있습니다.

리다이렉트 커스터마이징하기

로그인이 성공하면 Fortify는 애플리케이션의 fortify 설정 파일에 정의된 home 설정 값이 가리키는 URI로 리다이렉트합니다. 로그인 요청이 XHR 요청이었다면 200 HTTP 응답이 반환됩니다. 사용자가 로그아웃하면 / URI로 리다이렉트됩니다.

이러한 동작을 더 세밀하게 커스터마이징하고 싶다면, LoginResponse와 LogoutResponse 계약(contract)의 구현체를 Laravel 서비스 컨테이너에 바인딩하면 됩니다. 보통 이 작업은 애플리케이션의 App\Providers\FortifyServiceProvider 클래스에 있는 register 메서드 안에서 수행합니다:

use Laravel\Fortify\Contracts\LogoutResponse; /** * Register any application services. */ public function register(): void { $this->app->instance(LogoutResponse::class, new class implements LogoutResponse { public function toResponse($request) { return redirect('/'); } }); }

2단계 인증

Fortify의 2단계 인증 기능을 활성화하면, 사용자는 인증 과정에서 6자리 숫자 토큰을 입력해야 합니다. 이 토큰은 TOTP(Time-based One-Time Password) 방식으로 생성되며, Google Authenticator와 같은 TOTP 호환 모바일 인증 앱에서 확인할 수 있습니다.

시작하기 전에, 애플리케이션의 App\Models\User 모델이 Laravel\Fortify\TwoFactorAuthenticatable 트레이트를 사용하고 있는지 먼저 확인하세요:

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Fortify\TwoFactorAuthenticatable; class User extends Authenticatable { use Notifiable, TwoFactorAuthenticatable; }

그다음, 사용자가 2단계 인증 설정을 관리할 수 있는 화면을 애플리케이션에 구현해야 합니다. 이 화면에서는 2단계 인증을 활성화·비활성화하고, 복구 코드를 재생성할 수 있어야 합니다.

NOTE

기본적으로 fortify 설정 파일의 features 배열은 2단계 인증 설정을 변경하기 전에 비밀번호 확인을 요구하도록 지정되어 있습니다. 따라서 이 기능을 구현하기 전에 먼저 Fortify의 비밀번호 확인 기능을 애플리케이션에 구현해두어야 합니다.

2단계 인증 활성화하기

2단계 인증을 활성화하려면, 애플리케이션에서 Fortify가 정의한 /user/two-factor-authentication 엔드포인트로 POST 요청을 보내야 합니다. 요청이 성공하면 사용자는 이전 URL로 리다이렉트되며, 세션 변수 status에 two-factor-authentication-enabled 값이 설정됩니다. 템플릿에서 이 status 세션 변수를 확인하여 적절한 성공 메시지를 표시할 수 있습니다. XHR 요청인 경우에는 200 HTTP 응답이 반환됩니다.

사용자가 2단계 인증 활성화를 선택한 뒤에도, 유효한 2단계 인증 코드를 입력하여 설정을 "확인(confirm)"하는 절차가 남아 있습니다. 따라서 성공 메시지에는 아직 확인 절차가 남아 있다는 안내를 포함해야 합니다:

@if (session('status') == 'two-factor-authentication-enabled') <div class="mb-4 font-medium text-sm"> 아래에서 2단계 인증 설정을 마저 완료해주세요. </div> @endif

이어서 사용자가 인증 앱으로 스캔할 수 있도록 2단계 인증 QR 코드를 화면에 표시해야 합니다. Blade로 프런트엔드를 렌더링하는 경우, 사용자 인스턴스의 twoFactorQrCodeSvg 메서드를 사용해 QR 코드 SVG를 가져올 수 있습니다:

$request->user()->twoFactorQrCodeSvg();

자바스크립트 기반 프런트엔드를 구축하는 경우에는 /user/two-factor-qr-code 엔드포인트로 XHR GET 요청을 보내 QR 코드를 가져올 수 있습니다. 이 엔드포인트는 svg 키를 담은 JSON 객체를 반환합니다.

QR 코드를 표시하는 것 외에도, 사용자가 인증 앱에서 생성된 유효한 인증 코드를 입력하여 2단계 인증 설정을 "확인"할 수 있도록 텍스트 입력란을 제공해야 합니다. 이 코드는 Fortify가 정의한 /user/confirmed-two-factor-authentication 엔드포인트로 POST 요청을 보내 전달합니다.

요청이 성공하면 사용자는 이전 URL로 리다이렉트되며, 세션 변수 status에 two-factor-authentication-confirmed 값이 설정됩니다:

@if (session('status') == 'two-factor-authentication-confirmed') <div class="mb-4 font-medium text-sm"> 2단계 인증이 확인되어 성공적으로 활성화되었습니다. </div> @endif

이 확인 엔드포인트에 대한 요청이 XHR 방식으로 이루어진 경우에는 200 HTTP 응답이 반환됩니다.

사용자의 2단계 인증 복구 코드도 함께 표시해야 합니다. 이 복구 코드는 사용자가 모바일 기기를 분실했을 때 인증할 수 있도록 해줍니다. Blade로 프런트엔드를 렌더링하는 경우, 인증된 사용자 인스턴스를 통해 복구 코드에 접근할 수 있습니다:

(array) $request->user()->recoveryCodes();

자바스크립트 기반 프런트엔드에서는 /user/two-factor-recovery-codes 엔드포인트로 XHR GET 요청을 보내면 됩니다. 이 엔드포인트는 사용자의 복구 코드 목록을 담은 JSON 배열을 반환합니다.

복구 코드를 재생성하려면 /user/two-factor-recovery-codes 엔드포인트로 POST 요청을 보내야 합니다.

2단계 인증으로 로그인하기

인증 과정에서 Fortify는 자동으로 사용자를 애플리케이션의 2단계 인증 챌린지 화면으로 리다이렉트합니다. 다만 XHR 방식으로 로그인을 요청하는 경우, 인증에 성공한 뒤 반환되는 JSON 응답에는 two_factor라는 불리언(boolean) 속성이 포함됩니다. 이 값을 확인하여 2단계 인증 챌린지 화면으로 리다이렉트해야 하는지 판단할 수 있습니다.

2단계 인증 기능을 구현하려면 먼저 Fortify에게 2단계 인증 챌린지 뷰를 어떻게 반환할지 알려줘야 합니다. Fortify의 모든 인증 뷰 렌더링 로직은 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 커스터마이징할 수 있습니다. 일반적으로 이 메서드는 App\Providers\FortifyServiceProvider 클래스의 boot 메서드에서 호출합니다:

use Laravel\Fortify\Fortify; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::twoFactorChallengeView(function () { return view('auth.two-factor-challenge'); }); // ... }

Fortify는 이 뷰를 반환하는 /two-factor-challenge 라우트를 알아서 정의해줍니다. two-factor-challenge 템플릿에는 /two-factor-challenge 엔드포인트로 POST 요청을 보내는 폼이 포함되어야 합니다. 이 액션은 유효한 TOTP 토큰이 담긴 code 필드나, 사용자의 복구 코드 중 하나가 담긴 recovery_code 필드를 요구합니다.

로그인 시도가 성공하면, Fortify는 애플리케이션의 fortify 설정 파일에 있는 home 설정 값으로 지정된 URI로 사용자를 리다이렉트합니다. 로그인 요청이 XHR 요청이었다면 204 HTTP 응답이 반환됩니다.

요청이 실패한 경우, 사용자는 다시 2단계 인증 챌린지 화면으로 리다이렉트되며, 공유된 $errors Blade 템플릿 변수를 통해 유효성 검증 오류를 확인할 수 있습니다. XHR 요청의 경우에는 422 HTTP 응답과 함께 유효성 검증 오류가 반환됩니다.

2단계 인증 비활성화하기

2단계 인증을 비활성화하려면 /user/two-factor-authentication 엔드포인트로 DELETE 요청을 보내야 합니다. Fortify의 2단계 인증 관련 엔드포인트는 호출 전에 비밀번호 확인을 요구한다는 점을 기억해두세요.

패스키(Passkeys)

Fortify는 WebAuthn을 사용한 패스키 인증을 지원합니다. 패스키를 사용하면 사용자는 비밀번호 없이 Face ID, Touch ID, Windows Hello 또는 하드웨어 보안 키와 같은 플랫폼 인증 수단으로 로그인할 수 있습니다.

NOTE

패스키는 지문이나 얼굴 인식처럼 기기에 저장된 생체 인증 정보를 활용하기 때문에, 사용자가 별도로 비밀번호를 기억할 필요가 없습니다. 특히 모바일 환경에서 로그인 경험을 크게 개선할 수 있는 기능입니다.

패스키 활성화하기

먼저 애플리케이션의 fortify 설정 파일에서 passkeys 기능이 활성화되어 있는지 확인하세요.

use Laravel\Fortify\Features; 'features' => [ // ... Features::passkeys([ 'confirmPassword' => true, ]), ],

confirmPassword 옵션은 패스키를 등록하거나 삭제하기 전에 Fortify가 비밀번호 확인을 요구할지 여부를 결정합니다.

다음으로, 애플리케이션의 App\Models\User 모델이 Laravel\Fortify\Contracts\PasskeyUser 계약(contract)을 구현하고 Laravel\Fortify\PasskeyAuthenticatable 트레이트를 사용하도록 설정합니다.

<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Fortify\Contracts\PasskeyUser; use Laravel\Fortify\PasskeyAuthenticatable; class User extends Authenticatable implements PasskeyUser { use Notifiable, PasskeyAuthenticatable; }

Fortify의 패스키 설정 옵션은 애플리케이션의 config/fortify.php 파일 안에 있는 passkeys 설정 배열을 통해 커스터마이징할 수 있습니다.

'passkeys' => [ 'relying_party_id' => parse_url(config('app.url'), PHP_URL_HOST), 'allowed_origins' => [config('app.url')], 'user_handle_secret' => config('app.key'), 'timeout' => 60000, ],

NOTE

Fortify는 내부적으로 laravel/passkeys Composer 패키지를 감싸서 자동으로 설정해 줍니다. Fortify의 패스키 기능을 사용하는 경우, 패스키 설정은 애플리케이션의 config/fortify.php 파일에서 관리해야 합니다. laravel/passkeys 패키지의 설정 파일을 별도로 배포(publish)할 필요는 없으며, 해당 파일에 값을 정의하더라도 Fortify의 설정값으로 덮어써집니다.

relying_party_id는 애플리케이션의 도메인과 일치해야 합니다. allowed_origins 배열에는 패스키 등록 및 인증을 완료할 수 있는 브라우저 출처(origin) 목록을 지정합니다. user_handle_secret은 동일한 사용자가 여러 패스키 등록에 걸쳐 일관되게 식별될 수 있도록 불투명한(opaque) 사용자 식별자를 생성하는 데 사용됩니다. timeout 옵션은 패스키 등록 및 인증 작업이 유효 상태로 유지되는 시간(밀리초)을 제어합니다.

Fortify는 패스키 로그인, 확인(confirmation), 등록 라우트에 전용 패스키 속도 제한기(rate limiter)를 적용합니다. 필요한 경우 fortify.limiters.passkeys 설정 옵션과 그에 대응하는 RateLimiter::for(...) 정의를 통해 이를 커스터마이징할 수 있습니다.

Blade 애플리케이션에 브라우저 스크립트를 추가하는 방식이든, 완전히 별도의 프런트엔드를 구축하는 방식이든, 커스텀 프런트엔드를 만들고 있다면 공식 @laravel/passkeys 패키지를 사용할 수 있습니다. 이 패키지는 브라우저의 WebAuthn 절차를 처리하고 Fortify의 패스키 엔드포인트로 요청을 전송해 줍니다.

npm으로 패키지를 설치합니다.

npm install @laravel/passkeys

이제 프런트엔드에서 패스키 등록과 인증을 시작할 수 있습니다.

import { Passkeys } from "@laravel/passkeys"; await Passkeys.register({ name: "MacBook Pro" }); await Passkeys.verify();

애플리케이션에서 커스텀 패스키 엔드포인트 URI를 사용하는 경우, 호출마다 라우트를 재정의할 수 있습니다.

await Passkeys.verify({ routes: { options: "/passkeys/confirm/options", submit: "/passkeys/confirm", }, }); await Passkeys.register({ name: "MacBook Pro", routes: { options: "/user/passkeys/options", submit: "/user/passkeys", }, });

이 패키지는 @laravel/passkeys/react, @laravel/passkeys/vue, @laravel/passkeys/svelte를 통해 React, Vue, Svelte용 헬퍼도 함께 제공합니다.

패스키로 인증하기

패스키로 사용자를 인증하려면, 애플리케이션은 먼저 /passkeys/login/options 엔드포인트에 GET 요청을 보내야 합니다. 이 엔드포인트는 프런트엔드가 navigator.credentials.get(...)에 전달해야 할 WebAuthn 챌린지 옵션을 반환합니다.

브라우저가 자격 증명(credential)을 반환하면, 애플리케이션은 해당 자격 증명 페이로드와 함께 /passkeys/login에 POST 요청을 보내야 합니다. 이때 boolean 값인 remember 필드도 함께 포함할 수 있습니다.

요청이 성공하면 Fortify는 설정된 가드에 사용자를 로그인시키고 다음 중 하나를 반환합니다.

  • 일반 요청의 경우, 원래 목적지(intended destination)로의 리다이렉트 응답
  • XHR 요청의 경우, redirect 키를 포함한 JSON 페이로드와 함께 200 HTTP 응답

패스키로 비밀번호 확인하기

인증된 세션에 대해, Fortify는 현재 세션에서 Laravel의 비밀번호 확인 요구사항을 충족시켜 주는 패스키 확인(confirmation) 엔드포인트를 제공합니다.

패스키로 확인하려면, 애플리케이션은 먼저 /passkeys/confirm/options에 GET 요청을 보내야 합니다. 이 엔드포인트는 프런트엔드가 navigator.credentials.get(...)에 전달해야 할 WebAuthn 챌린지 옵션을 반환합니다.

브라우저가 자격 증명을 반환하면, 애플리케이션은 해당 자격 증명 페이로드와 함께 /passkeys/confirm에 POST 요청을 보내야 합니다.

요청이 성공하면 Fortify는 현재 세션을 비밀번호 확인 완료 상태로 표시하고 다음 중 하나를 반환합니다.

  • 일반 요청의 경우, 원래 목적지로의 리다이렉트 응답
  • XHR 요청의 경우, redirect 키를 포함한 JSON 페이로드와 함께 200 HTTP 응답

패스키 등록하기

인증된 사용자를 위해 패스키를 등록하려면, 애플리케이션은 먼저 /user/passkeys/options에 GET 요청을 보내야 합니다. 이 엔드포인트는 프런트엔드가 navigator.credentials.create(...)에 전달해야 할 WebAuthn 생성 옵션을 반환합니다.

브라우저가 자격 증명을 반환하면, 애플리케이션은 name 필드와 navigator.credentials.create(...)가 반환한 직렬화된 PublicKeyCredential 객체를 담은 credential 필드를 포함해 /user/passkeys에 POST 요청을 보내야 합니다.

요청이 성공하면 Fortify는 다음 중 하나를 반환합니다.

  • 일반 요청의 경우, 세션에 passkey-registered 상태 값을 담은 리다이렉트 백(redirect back) 응답
  • XHR 요청의 경우, 새로 등록된 패스키의 id와 name을 포함한 status 키를 담은 JSON 페이로드와 함께 200 HTTP 응답

패스키 삭제하기

패스키를 삭제하려면, 애플리케이션은 /user/passkeys/{passkey}에 DELETE 요청을 보내야 합니다.

요청이 성공하면 Fortify는 다음 중 하나를 반환합니다.

  • 일반 요청의 경우, 세션에 passkey-deleted 상태 값을 담은 리다이렉트 백 응답
  • XHR 요청의 경우, status 키를 포함한 JSON 페이로드와 함께 200 HTTP 응답

비밀번호 재설정

비밀번호 재설정 링크 요청

회원가입

애플리케이션의 회원가입 기능을 구현하려면 먼저 Fortify에게 "register" 뷰를 어떻게 반환할지 알려줘야 합니다. Fortify는 헤드리스 인증 라이브러리라는 점을 다시 한번 기억해 두세요. 이미 완성된 프런트엔드 화면이 필요하다면, Fortify를 직접 다루기보다는 애플리케이션 스타터 키트를 사용하는 편이 훨씬 빠릅니다.

Fortify의 모든 뷰 렌더링 로직은 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 커스터마이징할 수 있습니다. 일반적으로 이러한 메서드는 App\Providers\FortifyServiceProvider 클래스의 boot 메서드 안에서 호출합니다:

use Laravel\Fortify\Fortify; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::registerView(function () { return view('auth.register'); }); // ... }

이렇게 설정하면 Fortify가 이 뷰를 반환하는 /register 라우트를 알아서 정의해 줍니다. 여러분이 만드는 register 템플릿에는 Fortify가 정의한 /register 엔드포인트로 POST 요청을 보내는 폼이 포함되어야 합니다.

/register 엔드포인트는 문자열 타입의 name, 이메일 주소(또는 아이디) 문자열, password, password_confirmation 필드를 필요로 합니다. 이때 이메일/아이디 필드의 이름은 애플리케이션의 fortify 설정 파일에 정의된 username 설정값과 일치해야 합니다.

회원가입에 성공하면 Fortify는 fortify 설정 파일의 home 설정 옵션에 지정된 URI로 사용자를 리다이렉트합니다. 만약 요청이 XHR 요청이었다면 201 HTTP 응답이 반환됩니다.

요청이 실패한 경우, 사용자는 다시 회원가입 화면으로 리다이렉트되며 검증 오류는 공유 변수인 $errors Blade 템플릿 변수를 통해 확인할 수 있습니다. XHR 요청의 경우에는 검증 오류가 422 HTTP 응답과 함께 반환됩니다.

회원가입 커스터마이징

사용자 검증 및 생성 과정은 Laravel Fortify 설치 시 함께 생성된 App\Actions\Fortify\CreateNewUser 액션 클래스를 수정하여 원하는 대로 커스터마이징할 수 있습니다.

NOTE

CreateNewUser 액션 안에서는 비밀번호 해싱, 이용약관 동의 여부 검증, 회원가입 완료 후 추가 처리 등 원하는 로직을 자유롭게 추가할 수 있습니다. 이 클래스 하나만 수정하면 되므로, 회원가입 관련 커스터마이징 지점을 여러 곳에서 찾아 헤맬 필요가 없습니다.

비밀번호 재설정

비밀번호 재설정 링크 요청

비밀번호 재설정 기능을 구현하려면 먼저 Fortify에게 "비밀번호를 잊으셨나요" 뷰를 어떻게 반환할지 알려줘야 합니다. Fortify는 헤드리스(headless) 인증 라이브러리라는 점을 기억하세요. Laravel의 인증 기능이 이미 완성된 프런트엔드 구현이 필요하다면 애플리케이션 스타터 키트를 사용하는 것이 좋습니다.

Fortify의 뷰 렌더링 로직은 모두 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 커스터마이징할 수 있습니다. 보통은 이 메서드를 애플리케이션의 App\Providers\FortifyServiceProvider 클래스의 boot 메서드 안에서 호출합니다:

use Laravel\Fortify\Fortify; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::requestPasswordResetLinkView(function () { return view('auth.forgot-password'); }); // ... }

Fortify는 이 뷰를 반환하는 /forgot-password 엔드포인트를 자동으로 정의합니다. forgot-password 템플릿에는 /forgot-password 엔드포인트로 POST 요청을 보내는 폼이 포함되어야 합니다.

/forgot-password 엔드포인트는 문자열 타입의 email 필드를 필요로 합니다. 이 필드(및 데이터베이스 컬럼)의 이름은 애플리케이션의 fortify 설정 파일에 정의된 email 설정값과 일치해야 합니다.

비밀번호 재설정 링크 요청 응답 처리하기

비밀번호 재설정 링크 요청이 성공하면, Fortify는 사용자를 다시 /forgot-password 엔드포인트로 리다이렉트하고, 비밀번호를 재설정할 수 있는 안전한 링크가 담긴 이메일을 사용자에게 전송합니다. 요청이 XHR 요청이었다면 200 HTTP 응답이 반환됩니다.

요청이 성공한 후 다시 /forgot-password 엔드포인트로 리다이렉트되고 나면, status 세션 변수를 사용해 비밀번호 재설정 링크 요청 시도의 상태를 화면에 표시할 수 있습니다.

$status 세션 변수의 값은 애플리케이션의 passwords 언어 파일에 정의된 번역 문자열 중 하나와 일치합니다. 이 값을 커스터마이징하고 싶은데 아직 Laravel의 언어 파일을 퍼블리시하지 않았다면, lang:publish Artisan 명령어를 통해 퍼블리시할 수 있습니다:

@if (session('status')) <div class="mb-4 font-medium text-sm text-green-600"> {{ session('status') }} </div> @endif

요청이 실패한 경우, 사용자는 다시 비밀번호 재설정 링크 요청 화면으로 리다이렉트되며, 검증 오류는 공유되는 $errors Blade 템플릿 변수를 통해 확인할 수 있습니다. XHR 요청의 경우에는 검증 오류가 422 HTTP 응답과 함께 반환됩니다.

비밀번호 재설정하기

비밀번호 재설정 기능 구현을 마무리하려면 Fortify에게 "비밀번호 재설정" 뷰를 어떻게 반환할지 알려줘야 합니다.

Fortify의 뷰 렌더링 로직은 모두 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 커스터마이징할 수 있습니다. 보통은 이 메서드를 애플리케이션의 App\Providers\FortifyServiceProvider 클래스의 boot 메서드 안에서 호출합니다:

use Laravel\Fortify\Fortify; use Illuminate\Http\Request; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::resetPasswordView(function (Request $request) { return view('auth.reset-password', ['request' => $request]); }); // ... }

Fortify는 이 뷰를 표시하는 라우트를 자동으로 정의합니다. reset-password 템플릿에는 /reset-password로 POST 요청을 보내는 폼이 포함되어야 합니다.

/reset-password 엔드포인트는 문자열 타입의 email 필드, password 필드, password_confirmation 필드, 그리고 request()->route('token')의 값을 담은 token이라는 이름의 숨김 필드(hidden field)를 필요로 합니다. "email" 필드(및 데이터베이스 컬럼)의 이름은 애플리케이션의 fortify 설정 파일에 정의된 email 설정값과 일치해야 합니다.

비밀번호 재설정 응답 처리하기

비밀번호 재설정 요청이 성공하면, Fortify는 사용자가 새 비밀번호로 로그인할 수 있도록 /login 라우트로 다시 리다이렉트합니다. 또한 로그인 화면에서 재설정 성공 상태를 표시할 수 있도록 status 세션 변수가 설정됩니다:

@if (session('status')) <div class="mb-4 font-medium text-sm text-green-600"> {{ session('status') }} </div> @endif

요청이 XHR 요청이었다면 200 HTTP 응답이 반환됩니다.

요청이 실패한 경우, 사용자는 다시 비밀번호 재설정 화면으로 리다이렉트되며, 검증 오류는 공유되는 $errors Blade 템플릿 변수를 통해 확인할 수 있습니다. XHR 요청의 경우에는 검증 오류가 422 HTTP 응답과 함께 반환됩니다.

비밀번호 재설정 커스터마이징

비밀번호 재설정 과정은 Laravel Fortify를 설치할 때 생성된 App\Actions\ResetUserPassword 액션을 수정하여 커스터마이징할 수 있습니다.

NOTE

비밀번호 재설정 로직을 직접 수정할 때는 비밀번호 확인 검증, 재설정 토큰 유효성 검사 등 Laravel이 기본으로 제공하는 보안 절차를 그대로 유지하는 것이 좋습니다. 필요한 경우 검증 로직만 추가하거나, 비밀번호 재설정 후 처리(예: 알림 발송)를 확장하는 방식으로 접근하세요.

이메일 인증

회원가입 후, 사용자가 애플리케이션을 계속 이용하기 전에 이메일 주소를 인증하도록 요구하고 싶을 수 있습니다. 시작하려면 fortify 설정 파일의 features 배열에서 emailVerification 기능이 활성화되어 있는지 확인하세요. 다음으로, App\Models\User 클래스가 Illuminate\Contracts\Auth\MustVerifyEmail 인터페이스를 구현하도록 해야 합니다.

이 두 가지 설정 단계를 완료하면, 새로 가입한 사용자는 이메일 소유권을 인증하라는 안내 메일을 받게 됩니다. 하지만 사용자에게 "이메일에 있는 인증 링크를 클릭하라"고 알려주는 이메일 인증 화면을 Fortify가 어떻게 표시해야 하는지는 별도로 알려줘야 합니다.

Fortify의 모든 뷰 렌더링 로직은 Laravel\Fortify\Fortify 클래스가 제공하는 적절한 메서드를 사용해 커스터마이징할 수 있습니다. 보통 이 메서드는 애플리케이션의 App\Providers\FortifyServiceProvider 클래스에 있는 boot 메서드에서 호출합니다:

use Laravel\Fortify\Fortify; /** * 애플리케이션의 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::verifyEmailView(function () { return view('auth.verify-email'); }); // ... }

Fortify는 Laravel에 내장된 verified 미들웨어에 의해 사용자가 /email/verify 엔드포인트로 리다이렉트될 때 이 뷰를 보여주는 라우트를 알아서 정의해줍니다.

verify-email 템플릿에는 사용자가 이메일로 전송받은 인증 링크를 클릭해야 한다는 안내 메시지를 포함해야 합니다.

이메일 인증 링크 재전송

원한다면 verify-email 템플릿에 버튼을 추가하여 /email/verification-notification 엔드포인트로 POST 요청을 보내도록 만들 수 있습니다. 이 엔드포인트가 요청을 받으면 사용자에게 새로운 인증 링크가 담긴 이메일이 다시 전송되므로, 이전 이메일을 실수로 삭제했거나 분실한 경우에도 새 링크를 받을 수 있습니다.

인증 링크 재전송 요청이 성공하면 Fortify는 사용자를 다시 /email/verify 엔드포인트로 리다이렉트하면서 status 세션 변수를 함께 전달합니다. 이를 이용해 사용자에게 "작업이 성공적으로 처리되었습니다"라는 안내 메시지를 보여줄 수 있습니다. 만약 요청이 XHR 요청이었다면 202 HTTP 응답이 반환됩니다:

@if (session('status') == 'verification-link-sent') <div class="mb-4 font-medium text-sm text-green-600"> 새로운 이메일 인증 링크가 전송되었습니다! </div> @endif

라우트 보호하기

특정 라우트 또는 라우트 그룹에 접근하려면 사용자가 이메일 인증을 완료해야 한다고 지정하려면, 해당 라우트에 Laravel에 내장된 verified 미들웨어를 적용하면 됩니다. verified 미들웨어 별칭은 Laravel이 자동으로 등록하며, Illuminate\Auth\Middleware\EnsureEmailIsVerified 미들웨어를 가리키는 별칭 역할을 합니다:

Route::get('/dashboard', function () { // ... })->middleware(['verified']);

Fortify

비밀번호 확인

애플리케이션을 개발하다 보면 특정 작업을 수행하기 전에 사용자에게 비밀번호를 다시 확인받아야 하는 경우가 있습니다. 예를 들어 결제 정보 수정이나 계정 삭제처럼 민감한 작업을 처리하기 전에 말이죠. 이런 라우트는 보통 Laravel에 내장된 password.confirm 미들웨어로 보호합니다.

비밀번호 확인 기능을 구현하려면 먼저 Fortify에게 애플리케이션의 "비밀번호 확인" 뷰를 어떻게 반환할지 알려줘야 합니다. Fortify는 헤드리스(headless) 인증 라이브러리라는 점을 기억하세요. 별도의 구현 없이 완성된 프런트엔드까지 갖춘 인증 기능을 원한다면 애플리케이션 스타터 키트를 사용하는 것이 좋습니다.

Fortify의 모든 뷰 렌더링 로직은 Laravel\Fortify\Fortify 클래스가 제공하는 메서드를 통해 커스터마이징할 수 있습니다. 보통 이 메서드는 애플리케이션의 App\Providers\FortifyServiceProvider 클래스에 있는 boot 메서드에서 호출합니다:

use Laravel\Fortify\Fortify; /** * 애플리케이션 서비스를 부트스트랩합니다. */ public function boot(): void { Fortify::confirmPasswordView(function () { return view('auth.confirm-password'); }); // ... }

Fortify는 이 뷰를 반환하는 /user/confirm-password 엔드포인트를 자동으로 정의합니다. confirm-password 템플릿에는 /user/confirm-password 엔드포인트로 POST 요청을 보내는 폼이 포함되어야 합니다. 이때 /user/confirm-password 엔드포인트는 사용자의 현재 비밀번호가 담긴 password 필드를 요구합니다.

입력한 비밀번호가 사용자의 현재 비밀번호와 일치하면, Fortify는 사용자가 원래 접근하려던 라우트로 리다이렉트합니다. 만약 해당 요청이 XHR 요청이었다면 201 HTTP 응답이 반환됩니다.

비밀번호가 일치하지 않아 요청이 실패하면, 사용자는 다시 비밀번호 확인 화면으로 리다이렉트되며, 공유된 $errors Blade 템플릿 변수를 통해 유효성 검증 오류를 확인할 수 있습니다. XHR 요청의 경우에는 422 HTTP 응답과 함께 유효성 검증 오류가 반환됩니다.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 9월 17일