메인 콘텐츠로 건너뛰기

Fortify란

Laravel Fortify는, 프론트엔드에 의존하지 않는 인증 백엔드 구현입니다. 로그인·등록·비밀번호 재설정·메일 확인·2FA·패스키에 필요한 라우트와 컨트롤러를 모두 제공합니다.
Fortify는 UI를 가지지 않습니다. 스타터 킷이나 자체 UI에서 Fortify의 라우트로 요청을 보냄으로써 기능합니다.
“프론트엔드 비의존”이라는 설계 사상이 중요합니다. Blade·Inertia(React/Vue/Svelte)·API 등, 어떤 프론트엔드 스택에서도 동일한 인증 백엔드를 재이용할 수 있습니다. 이것이 Fortify가 오래 계속 사용되고 있는 이유입니다.

역사: Jetstream에서 현행 스타터 킷까지

왜 현행 스타터 킷에서도 Fortify가 사용되고 있는가

당초의 React/Vue 스타터 킷은 Fortify 없이 구현되어 있었습니다. 그러나 이중 인증(2FA)에 대한 대응이 필요해졌을 때, Fortify가 그대로 채택된 것으로, 인증 전체가 Fortify 기반으로 전환되었습니다. Fortify는 “프론트엔드 비의존”으로서 설계되어 있기 때문에, Inertia를 사용하는 스타터 킷과의 궁합이 좋고, 현재도 계속 사용되고 있습니다.
Fortify는 현재, 가장 오래 계속 사용되고 있는 Laravel 공식 인증 패키지입니다. 2020년의 등장 이후, Jetstream → 현행 스타터 킷과 형태를 바꿔가면서 현역을 지속하고 있습니다.

현행 스타터 킷의 구성

React/Vue 스타터 킷에서는 다음의 파일에서 Fortify가 설정되어 있습니다.
  • app/Providers/FortifyServiceProvider.php — 뷰·액션·레이트 리밋의 등록
  • config/fortify.php — 활성화할 기능과 인증 설정

config/fortify.php의 주요 설정

use Laravel\Fortify\Features;

return [
    'guard'    => 'web',
    'username' => 'email',
    'home'     => '/dashboard',

    'limiters' => [
        'login'      => 'login',
        'two-factor' => 'two-factor',
    ],

    'features' => [
        Features::registration(),
        Features::resetPasswords(),
        Features::emailVerification(),
        Features::twoFactorAuthentication([
            'confirm'         => true,
            'confirmPassword' => true,
        ]),
    ],
];
스타터 킷에서는 패스키(Features::passkeys())는 기본으로 활성화되어 있지 않습니다. 활성화하려면 features 배열에 추가합니다.

FortifyServiceProvider의 설정

스타터 킷의 FortifyServiceProvider는 3가지 역할을 담당합니다.

1. 액션 설정

private function configureActions(): void
{
    Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
    Fortify::createUsersUsing(CreateNewUser::class);
}
app/Actions/Fortify/에 배치된 클래스에서 사용자 작성과 비밀번호 재설정 로직을 커스터마이즈합니다. 검증이나 해시 처리는 여기에 집약되어 있습니다.

2. 뷰 설정

private function configureViews(): void
{
    Fortify::loginView(fn (Request $request) => Inertia::render('auth/login', [
        'canResetPassword' => Features::enabled(Features::resetPasswords()),
        'canRegister'      => Features::enabled(Features::registration()),
        'status'           => $request->session()->get('status'),
    ]));

    Fortify::resetPasswordView(fn (Request $request) => Inertia::render('auth/reset-password', [
        'email' => $request->email,
        'token' => $request->route('token'),
    ]));

    Fortify::requestPasswordResetLinkView(
        fn (Request $request) => Inertia::render('auth/forgot-password', [
            'status' => $request->session()->get('status'),
        ])
    );

    Fortify::verifyEmailView(
        fn (Request $request) => Inertia::render('auth/verify-email', [
            'status' => $request->session()->get('status'),
        ])
    );

    Fortify::registerView(fn () => Inertia::render('auth/register'));

    Fortify::twoFactorChallengeView(fn () => Inertia::render('auth/two-factor-challenge'));

    Fortify::confirmPasswordView(fn () => Inertia::render('auth/confirm-password'));
}
각 뷰 메서드는 Inertia 컴포넌트를 반환하는 클로저를 받습니다. Features::enabled()로 기능 플래그를 확인하여 뷰에 전달하고 있는 것이 포인트입니다.
Blade 앱에서는 Inertia::render(...) 대신 view('auth.login')을 반환합니다. 프론트엔드를 바꿔도 FortifyServiceProvider 측만 수정하면 인증 로직은 바뀌지 않습니다.

3. 레이트 리밋 설정

private function configureRateLimiting(): void
{
    RateLimiter::for('two-factor', function (Request $request) {
        return Limit::perMinute(5)->by($request->session()->get('login.id'));
    });

    RateLimiter::for('login', function (Request $request) {
        $throttleKey = Str::transliterate(
            Str::lower($request->input(Fortify::username())) . '|' . $request->ip()
        );

        return Limit::perMinute(5)->by($throttleKey);
    });
}
  • login 리미터: 이메일 주소와 IP 주소의 조합으로 제한(브루트포스 대책)
  • two-factor 리미터: 세션 내의 로그인 시도 ID로 제한
config/fortify.phplimiters 키와 일치하는 키를 RateLimiter::for()에 등록합니다.

주요 기능과 등록되는 라우트

Fortify가 등록하는 주요 라우트를 기능별로 정리합니다.
기능메서드라우트
로그인GET/login
로그인POST/login
로그아웃POST/logout
등록GET/register
등록POST/register
비밀번호 재설정 요청GET / POST/forgot-password
비밀번호 재설정GET / POST/reset-password
메일 확인GET/email/verify
메일 확인 링크 재전송POST/email/verification-notification
비밀번호 확인GET / POST/user/confirm-password
2FA 활성화POST/user/two-factor-authentication
2FA 챌린지GET / POST/two-factor-challenge
패스키 로그인GET / POST/passkeys/login
패스키 관리GET / POST / DELETE/user/passkeys
php artisan route:list --name=fortify 또는 단순히 php artisan route:list로 실제로 등록되어 있는 라우트를 확인할 수 있습니다.

이중 인증(2FA)

스타터 킷에서는 Features::twoFactorAuthentication()이 활성화되어 있습니다. confirmconfirmPassword는 모두 true로 설정되어 있습니다.
옵션의미
confirm활성화 후에 인증 코드에서의 확인을 요구함
confirmPassword2FA의 설정 변경 전에 비밀번호 확인을 요구함
2FA의 설정 화면에서, 사용자는 이하의 조작을 할 수 있습니다.
1

2FA를 활성화한다

/user/two-factor-authentication에 POST 요청을 송신합니다. 성공하면 세션에 two-factor-authentication-enabled 상태가 세팅됩니다.
2

QR 코드를 확인한다

/user/two-factor-qr-code에 GET 요청을 보내면, 인증 앱에 읽어들이는 QR 코드의 SVG가 반환됩니다.
3

인증 코드로 확인한다

/user/confirmed-two-factor-authentication에 POST 요청으로 코드를 송신하고, 설정을 완료합니다.
4

리커버리 코드를 보관한다

/user/two-factor-recovery-codes에 GET 요청을 보내고, 리커버리 코드를 취득하여 안전한 장소에 보관합니다.

패스키

패스키는 Fortify의 기능으로서 최근 추가되었습니다. WebAuthn을 사용한 비밀번호 없는 인증으로, Face ID·Touch ID·Windows Hello·하드웨어 시큐리티 키에 대응하고 있습니다.

활성화

config/fortify.phpfeatures 배열에 추가합니다.
'features' => [
    Features::registration(),
    Features::resetPasswords(),
    Features::emailVerification(),
    Features::twoFactorAuthentication([
        'confirm'         => true,
        'confirmPassword' => true,
    ]),
    Features::passkeys([
        'confirmPassword' => true,
    ]),
],
다음으로, User 모델에 PasskeyUser 컨트랙트와 PasskeyAuthenticatable 트레이트를 추가합니다.
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laravel\Fortify\Contracts\PasskeyUser;
use Laravel\Fortify\PasskeyAuthenticatable;

class User extends Authenticatable implements PasskeyUser
{
    use PasskeyAuthenticatable;
}
WebAuthn 설정은 config/fortify.phppasskeys 키에서 관리합니다.
'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,
],
Fortify의 패스키는 내부에서 laravel/passkeys Composer 패키지를 래핑하고 있습니다. laravel/passkeys의 설정 파일을 공개할 필요는 없고, config/fortify.phppasskeys 키가 우선됩니다.
패스키의 상세한 구현(@laravel/passkeys JS 클라이언트, React/Vue/Svelte 헬퍼 등)에 대해서는, 패스키 초기 조사도 참조해 주세요.

관련 페이지

커스텀 인증 가드

Guard·StatefulGuard 인터페이스를 구현하여 커스텀 인증 가드를 만드는 방법을 해설합니다.

공식 문서: Laravel Fortify

설치·전체 기능·커스터마이즈의 상세는 공식 문서를 참조해 주세요.
마지막 수정일 2026년 7월 13일