Laravel Fortify
번역일: 2026년 6월 25일
Laravel Fortify
소개
Laravel Fortify는 프론트엔드에 종속되지 않는 Laravel용 인증 백엔드 구현 패키지입니다. Fortify는 로그인, 회원가입, 비밀번호 재설정, 이메일 인증 등 Laravel의 모든 인증 기능을 구현하는 데 필요한 라우트와 컨트롤러를 등록합니다. Fortify를 설치한 후 route:list Artisan 명령어를 실행하면 등록된 라우트를 확인할 수 있습니다.
Fortify는 자체적인 UI를 제공하지 않으므로, Fortify가 등록한 라우트로 요청을 보내는 여러분만의 프론트엔드와 함께 사용해야 합니다. 이 문서의 나머지 부분에서 각 라우트에 어떻게 요청을 보내는지 자세히 설명합니다.
NOTE
Fortify는 Laravel 인증 기능 구현을 빠르게 시작할 수 있도록 돕는 패키지입니다. 반드시 사용해야 하는 것은 아닙니다. 인증, 비밀번호 재설정, 이메일 인증 문서를 참고해 Laravel 인증 서비스를 직접 구현할 수도 있습니다.
Fortify란 무엇인가?
앞서 설명했듯이, Laravel Fortify는 프론트엔드에 종속되지 않는 Laravel용 인증 백엔드 구현 패키지입니다. 로그인, 회원가입, 비밀번호 재설정, 이메일 인증 등 Laravel의 모든 인증 기능에 필요한 라우트와 컨트롤러를 등록합니다.
Laravel 인증 기능을 사용하기 위해 Fortify가 반드시 필요한 것은 아닙니다. 인증, 비밀번호 재설정, 이메일 인증 문서를 참고해 인증 서비스를 직접 구현할 수도 있습니다.
Laravel을 처음 접한다면 Fortify보다 Laravel Breeze 스타터 킷을 먼저 살펴보는 것을 권장합니다. Breeze는 Tailwind CSS로 구성된 UI를 포함한 인증 스캐폴딩을 제공합니다. Fortify와 달리 Breeze는 라우트와 컨트롤러를 애플리케이션 안에 직접 게시하므로, 코드를 직접 보고 Laravel 인증 기능을 학습하기에 적합합니다.
Fortify는 본질적으로 Laravel Breeze의 라우트와 컨트롤러를 UI 없이 패키지 형태로 제공하는 것입니다. 특정 프론트엔드 기술에 얽매이지 않고 인증 백엔드를 빠르게 구성하고 싶을 때 유용합니다.
언제 Fortify를 사용해야 할까?
Laravel의 애플리케이션 스타터 킷을 사용하고 있다면 이미 완전한 인증 구현이 포함되어 있으므로 Fortify를 별도로 설치할 필요가 없습니다.
스타터 킷을 사용하지 않고 인증 기능이 필요하다면 두 가지 선택지가 있습니다. 인증 기능을 직접 구현하거나, Fortify로 백엔드 구현을 담당하게 하는 것입니다.
Fortify를 설치하면 프론트엔드에서 이 문서에 설명된 Fortify의 인증 라우트로 요청을 보내 사용자를 인증하거나 등록할 수 있습니다.
반면 Fortify 없이 직접 구현하고 싶다면 인증, 비밀번호 재설정, 이메일 인증 문서를 참고하면 됩니다.
Laravel Fortify와 Laravel Sanctum
Laravel Sanctum과 Laravel Fortify의 차이를 헷갈리는 분들이 있습니다. 두 패키지는 서로 다른 문제를 해결하며, 경쟁 관계가 아닌 상호 보완적인 관계입니다.
Laravel Sanctum은 API 토큰 관리와 세션 쿠키 또는 토큰을 이용한 기존 사용자 인증만을 담당합니다. Sanctum은 회원가입, 비밀번호 재설정 등의 라우트를 제공하지 않습니다.
API를 제공하거나 SPA(싱글 페이지 애플리케이션)의 백엔드 역할을 하는 애플리케이션을 만든다면, Fortify(회원가입, 비밀번호 재설정 등)와 Sanctum(API 토큰 관리, 세션 인증)을 함께 활용할 수 있습니다.
설치
Composer로 Fortify를 설치합니다.
composer require laravel/fortify다음으로, fortify:install Artisan 명령어로 Fortify 리소스를 게시합니다.
php artisan fortify:install이 명령어는 Fortify의 액션 클래스를 app/Actions 디렉토리에 게시하고(없으면 자동 생성), FortifyServiceProvider, 설정 파일, 필요한 데이터베이스 마이그레이션 파일도 함께 게시합니다.
이후 마이그레이션을 실행합니다.
php artisan migrateFortify 기능 설정
fortify 설정 파일에는 features 배열이 있습니다. 이 배열에서 Fortify가 기본으로 노출할 백엔드 라우트와 기능을 지정합니다. Laravel Jetstream과 함께 사용하지 않는다면, 대부분의 Laravel 애플리케이션에서 필요한 기본 인증 기능만 활성화하는 것을 권장합니다.
'features' => [
Features::registration(),
Features::resetPasswords(),
Features::emailVerification(),
],뷰 비활성화
Fortify는 기본적으로 로그인 화면이나 회원가입 화면과 같은 뷰를 반환하는 라우트를 정의합니다. 하지만 JavaScript 기반의 SPA를 만들고 있다면 이런 라우트가 필요하지 않을 수 있습니다. config/fortify.php 설정 파일에서 views 값을 false로 설정하면 해당 라우트를 완전히 비활성화할 수 있습니다.
'views' => false,뷰 비활성화와 비밀번호 재설정
Fortify의 뷰를 비활성화하면서 비밀번호 재설정 기능을 구현하는 경우, "비밀번호 재설정" 화면을 표시하는 password.reset이라는 이름의 라우트는 직접 정의해야 합니다. Laravel의 Illuminate\Auth\Notifications\ResetPassword 알림이 password.reset 이름의 라우트를 통해 비밀번호 재설정 URL을 생성하기 때문입니다.
인증
인증 기능을 시작하려면 먼저 Fortify에게 "로그인" 뷰를 어떻게 반환할지 알려줘야 합니다. Fortify는 UI가 없는 헤드리스 인증 라이브러리라는 점을 기억하세요. 이미 완성된 프론트엔드 인증 구현이 필요하다면 애플리케이션 스타터 킷을 사용하세요.
뷰 렌더링 로직은 Laravel\Fortify\Fortify 클래스의 메서드를 통해 커스터마이징할 수 있습니다. 일반적으로 App\Providers\FortifyServiceProvider의 boot 메서드에서 호출합니다. Fortify는 아래 설정을 바탕으로 이 뷰를 반환하는 /login 라우트를 자동으로 정의합니다.
use Laravel\Fortify\Fortify;
/**
* 애플리케이션 서비스를 부트스트랩합니다.
*/
public function boot(): void
{
Fortify::loginView(function () {
return view('auth.login');
});
// ...
}로그인 템플릿에는 /login으로 POST 요청을 보내는 폼이 포함되어야 합니다. /login 엔드포인트는 문자열 email / username과 password를 기대합니다. 이메일/사용자명 필드의 이름은 config/fortify.php의 username 값과 일치해야 합니다. "로그인 상태 유지" 기능을 위해 boolean 타입의 remember 필드도 함께 전송할 수 있습니다.
로그인에 성공하면 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;
/**
* 애플리케이션 서비스를 부트스트랩합니다.
*/
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 인증에 Fortify를 사용하는 경우, Laravel의 기본 web 가드를 Laravel Sanctum과 함께 사용하세요.
인증 파이프라인 커스터마이징
Fortify는 로그인 요청을 일련의 호출 가능한 클래스들로 구성된 파이프라인을 통해 처리합니다. 필요하다면 로그인 요청이 통과할 커스텀 파이프라인 클래스를 정의할 수 있습니다. 각 클래스는 들어오는 Illuminate\Http\Request 인스턴스를 받는 __invoke 메서드를 가져야 하며, 미들웨어처럼 파이프라인의 다음 클래스로 요청을 전달하기 위한 $next 변수도 받습니다.
커스텀 파이프라인을 정의하려면 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\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 주소만을 기준으로 제한하는 등 다른 방식이 필요한 경우, fortify.limiters.login 설정 옵션을 통해 직접 속도 제한기를 지정할 수 있습니다. 이 옵션은 config/fortify.php 파일에 있습니다.
NOTE
횟수 제한, 2단계 인증, 외부 웹 애플리케이션 방화벽(WAF)을 함께 활용하면 가장 강력한 인증 보안을 구현할 수 있습니다.
리다이렉트 커스터마이징
로그인에 성공하면 fortify 설정 파일의 home 옵션에 지정된 URI로 리다이렉트됩니다. XHR 요청인 경우 200 HTTP 응답이 반환됩니다. 로그아웃 후에는 / URI로 리다이렉트됩니다.
이 동작을 더 세밀하게 커스터마이징하려면 LoginResponse와 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('/');
}
});
}2단계 인증
Fortify의 2단계 인증 기능을 활성화하면, 사용자는 인증 과정에서 6자리 숫자 토큰을 추가로 입력해야 합니다. 이 토큰은 TOTP(시간 기반 일회용 비밀번호) 방식으로 생성되며, 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단계 인증을 활성화/비활성화하고 복구 코드를 재생성할 수 있어야 합니다.
기본적으로
fortify설정 파일의features배열은 2단계 인증 설정을 변경하기 전에 비밀번호 확인을 요구하도록 설정되어 있습니다. 따라서 계속 진행하기 전에 Fortify의 비밀번호 확인 기능을 먼저 구현해야 합니다.
2단계 인증 활성화
2단계 인증을 활성화하려면 애플리케이션에서 Fortify가 정의한 /user/two-factor-authentication 엔드포인트로 POST 요청을 보내야 합니다. 요청이 성공하면 이전 URL로 리다이렉트되고 status 세션 변수가 two-factor-authentication-enabled로 설정됩니다. 이 세션 변수를 감지해 성공 메시지를 표시할 수 있습니다. XHR 요청인 경우 200 HTTP 응답이 반환됩니다.
2단계 인증을 활성화한 후에도 사용자는 유효한 2단계 인증 코드를 입력해 설정을 "확인"해야 합니다. 따라서 성공 메시지에서 추가 확인 단계가 필요함을 안내해야 합니다.
@if (session('status') == 'two-factor-authentication-enabled')
<div class="mb-4 font-medium text-sm">
아래에서 2단계 인증 설정을 완료해 주세요.
</div>
@endif다음으로, 사용자가 인증 앱으로 스캔할 수 있는 QR 코드를 표시해야 합니다. Blade로 프론트엔드를 렌더링하는 경우 사용자 인스턴스의 twoFactorQrCodeSvg 메서드를 통해 QR 코드 SVG를 가져올 수 있습니다.
$request->user()->twoFactorQrCodeSvg();JavaScript 기반 프론트엔드를 사용하는 경우 /user/two-factor-qr-code 엔드포인트에 XHR GET 요청을 보내면 svg 키를 포함하는 JSON 객체가 반환됩니다.
2단계 인증 확인
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>
@endifXHR 요청인 경우 200 HTTP 응답이 반환됩니다.
복구 코드 표시
사용자의 2단계 인증 복구 코드도 표시해야 합니다. 복구 코드는 사용자가 모바일 기기에 접근할 수 없을 때 인증에 사용할 수 있습니다. Blade를 사용하는 경우 인증된 사용자 인스턴스를 통해 복구 코드에 접근할 수 있습니다.
(array) $request->user()->recoveryCodes()JavaScript 기반 프론트엔드를 사용하는 경우 /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에게 해당 뷰를 어떻게 반환할지 알려줘야 합니다. 뷰 렌더링 로직은 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 필드 중 하나를 전송해