메인 콘텐츠로 건너뛰기

Sanctum이란

Laravel Sanctum은 SPA(싱글 페이지 애플리케이션)·모바일 앱·심플한 API를 위한 경량 인증 패키지입니다. 복잡한 OAuth 지식이 없어도, 사용자별로 여러 API 토큰을 발행·관리할 수 있습니다. Sanctum이 해결하는 문제는 2가지입니다.
인증 모드구조주요 용도
API 토큰 인증Authorization: Bearer <token> 헤더모바일 앱·서드파티 연계
SPA 인증세션 쿠키 + CSRF 보호자사 프론트엔드 (Vue/React 등)
자사 SPA로부터 API를 호출하는 경우는 SPA 인증을 사용합니다. 모바일 앱이나 서드파티가 API를 이용하는 경우는 API 토큰 인증을 사용합니다. 어느 한쪽만을 사용하는 것도 상관없습니다.

Passport와의 구분 사용

SanctumPassport
복잡함심플풀 기능 OAuth2
적합한 용도자사 SPA·모바일 앱외부 앱에의 OAuth 프로바이더
토큰 종별퍼스널 액세스 토큰OAuth2 액세스 토큰
외부 서비스에 대해 OAuth2 프로바이더가 될 필요가 있는 경우는 Passport를 선택하지만, 많은 애플리케이션에서는 Sanctum으로 충분합니다.

설치와 설정

설치

install:api Artisan 명령을 실행하기만 하면 Sanctum이 셋업됩니다.
php artisan install:api
이 명령은 이하를 자동적으로 수행합니다.
  • laravel/sanctum 패키지의 설치
  • personal_access_tokens 테이블의 마이그레이션 파일의 공개
  • 마이그레이션의 실행

HasApiTokens 트레이트를 추가

User 모델에 HasApiTokens 트레이트를 추가합니다.
// app/Models/User.php

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
이로써 $user->createToken()이나 $user->tokens 등의 메서드를 사용할 수 있게 됩니다.

API 토큰 인증

토큰 플로우

토큰을 발행

createToken() 메서드로 토큰을 발행합니다. plainTextToken 프로퍼티에서 평문의 토큰 값을 취득할 수 있습니다. 평문 토큰은 데이터베이스에 보존되지 않기 때문에, 발행 직후에 사용자에게 반환할 필요가 있습니다.
use Illuminate\Http\Request;

Route::post('/tokens/create', function (Request $request) {
    $token = $request->user()->createToken($request->token_name);

    return ['token' => $token->plainTextToken];
})->middleware('auth');
데이터베이스에는 SHA-256으로 해시화된 토큰이 보존됩니다.

스코프(어빌리티)를 설정

토큰에 대해 어빌리티(스코프)를 부여함으로써, 그 토큰으로 실행할 수 있는 조작을 제한할 수 있습니다.
// 스코프 첨부 토큰을 발행
$token = $user->createToken('mobile-app', ['server:update', 'server:read']);

return $token->plainTextToken;
리퀘스트 처리 시에 토큰의 스코프를 확인합니다.
if ($request->user()->tokenCan('server:update')) {
    // 업데이트 조작을 실행
}

if ($request->user()->tokenCant('server:update')) {
    abort(403);
}

미들웨어에서 스코프를 확인

bootstrap/app.php에 미들웨어 에일리어스를 등록합니다.
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'abilities' => CheckAbilities::class,  // 모든 어빌리티를 가짐
        'ability'   => CheckForAnyAbility::class, // 어느 하나의 어빌리티를 가짐
    ]);
})
라우트에 미들웨어를 적용합니다.
// check-status와 place-orders의 양쪽을 가진 토큰만 허가
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);

// check-status 또는 place-orders 중 어느 하나를 가진 토큰을 허가
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);

토큰의 유효 기한

기본적으로 Sanctum 토큰에 유효 기한은 없습니다. config/sanctum.phpexpiration 옵션에서 분 단위의 유효 기한을 설정할 수 있습니다.
// config/sanctum.php
'expiration' => 525600, // 365일(분)
토큰별로 유효 기한을 지정할 수도 있습니다.
$token = $user->createToken(
    'token-name',
    ['*'],
    now()->addWeeks(1) // 1주 후에 기한 만료
)->plainTextToken;
유효 기한을 설정하고 있는 경우는, 기한 만료 토큰을 정기적으로 삭제하는 스케줄을 설정합니다.
use Illuminate\Support\Facades\Schedule;

Schedule::command('sanctum:prune-expired --hours=24')->daily();

토큰을 실효시키기

// 전 토큰을 삭제
$user->tokens()->delete();

// 현재의 리퀘스트에서 사용되고 있는 토큰을 삭제
$request->user()->currentAccessToken()->delete();

// 특정의 토큰을 삭제
$user->tokens()->where('id', $tokenId)->delete();

SPA 인증

SPA 인증은 세션 쿠키를 사용하기 때문에, 토큰을 발행·관리할 필요가 없습니다. 자사 프론트엔드(Vue, React, Next.js 등)로부터 API를 호출하는 경우에 적합합니다.
SPA 인증을 사용하려면 SPA와 API가 같은 최상위 도메인을 공유하고 있을 필요가 있습니다(서브도메인은 달라도 상관없습니다). 또한 리퀘스트에 Accept: application/json 헤더와 Referer 또는 Origin 헤더를 포함할 필요가 있습니다.

Sanctum 미들웨어를 활성화

bootstrap/app.php에서 statefulApi() 미들웨어를 활성화합니다.
->withMiddleware(function (Middleware $middleware): void {
    $middleware->statefulApi();
})

1st-party 도메인을 설정

config/sanctum.phpstateful 옵션에 SPA의 도메인을 설정합니다.
// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    Sanctum::currentApplicationUrlWithPort()
))),

CORS 설정

다른 서브도메인에서 API를 호출하는 경우는, CORS 설정이 필요합니다.
php artisan config:publish cors
config/cors.php에서 supports_credentialstrue로 설정합니다.
// config/cors.php
'supports_credentials' => true,
프론트엔드의 axios에도 설정이 필요합니다.
// resources/js/bootstrap.js
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
세션 쿠키의 도메인 설정도 잊지 말고 수행합니다.
// config/session.php
'domain' => '.example.com', // 선두에 점을 붙임

SPA로부터의 인증 플로우

1

CSRF 쿠키를 취득

로그인 전에 /sanctum/csrf-cookie 엔드포인트를 호출해 CSRF 보호를 초기화합니다.
await axios.get('/sanctum/csrf-cookie');
2

로그인 리퀘스트를 송신

/login 엔드포인트에 POST 리퀘스트를 보냅니다.
await axios.post('/login', {
    email: '[email protected]',
    password: 'password',
});
3

인증 완료 리퀘스트를 보냄

로그인 후의 리퀘스트는 세션 쿠키로 자동적으로 인증됩니다.
const response = await axios.get('/api/user');
console.log(response.data); // 인증 완료 사용자 정보

인증 완료 라우트의 보호

auth:sanctum 미들웨어를 라우트에 적용하면, 미인증의 리퀘스트에 대해 401 Unauthorized가 반환됩니다. API 토큰 인증·SPA 인증의 양쪽을 이 미들웨어 하나로 처리할 수 있습니다.
use Illuminate\Http\Request;

// 단일 라우트를 보호
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

// 라우트 그룹을 보호
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::get('/posts', [PostController::class, 'index']);
});

실용 예: 로그인 API와 토큰 반환

모바일 앱을 위한 API 토큰 인증을 구현하는 예입니다.
1

로그인 엔드포인트를 작성

// routes/api.php

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

Route::post('/sanctum/token', function (Request $request) {
    $request->validate([
        'email'       => ['required', 'email'],
        'password'    => ['required'],
        'device_name' => ['required', 'string'],
    ]);

    $user = User::where('email', $request->email)->first();

    if (! $user || ! Hash::check($request->password, $user->password)) {
        throw ValidationException::withMessages([
            'email' => ['제공된 인증 정보가 올바르지 않습니다.'],
        ]);
    }

    return response()->json([
        'token' => $user->createToken($request->device_name)->plainTextToken,
    ]);
});
2

인증 완료 라우트를 작성

// routes/api.php

Route::middleware('auth:sanctum')->group(function () {
    // 현재 사용자 정보를 반환
    Route::get('/user', function (Request $request) {
        return $request->user();
    });

    // 현재의 토큰을 실효시켜 로그아웃
    Route::post('/logout', function (Request $request) {
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => '로그아웃했습니다.']);
    });

    // 전 디바이스에서 로그아웃
    Route::post('/logout/all', function (Request $request) {
        $request->user()->tokens()->delete();

        return response()->json(['message' => '전 디바이스에서 로그아웃했습니다.']);
    });
});
3

클라이언트로부터 리퀘스트를 보냄

// 로그인
const { data } = await axios.post('/api/sanctum/token', {
    email: '[email protected]',
    password: 'password',
    device_name: 'My iPhone',
});

const token = data.token;

// 인증 완료 리퀘스트
const response = await axios.get('/api/user', {
    headers: {
        Authorization: `Bearer ${token}`,
    },
});

테스트

Sanctum의 테스트에서는 Sanctum::actingAs()를 사용해 사용자를 인증하고, 부여할 어빌리티를 지정합니다.
use App\Models\User;
use Laravel\Sanctum\Sanctum;

test('태스크 일람을 취득할 수 있다', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['view-tasks']
    );

    $response = $this->get('/api/tasks');

    $response->assertOk();
});

test('전 어빌리티를 가진 토큰으로 접근할 수 있다', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['*']
    );

    $response = $this->get('/api/tasks');

    $response->assertOk();
});

정리

# Sanctum을 설치하여 마이그레이션을 실행
php artisan install:api
User 모델에 HasApiTokens 트레이트를 추가:
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
// 토큰 발행
$token = $user->createToken('token-name')->plainTextToken;

// 스코프 첨부 토큰 발행
$token = $user->createToken('token-name', ['read', 'write'])->plainTextToken;

// 스코프 확인
$user->tokenCan('read');   // true/false
$user->tokenCant('write'); // true/false

// 토큰 실효
$user->tokens()->delete();                        // 전 토큰
$request->user()->currentAccessToken()->delete(); // 현재의 토큰
$user->tokens()->where('id', $id)->delete();      // 특정의 토큰
  • API 토큰 인증: 모바일 앱, 서드파티, CLI 도구 등, 세션을 가지지 않는 클라이언트로부터 이용하는 경우.
  • SPA 인증: 자사의 Vue/React/Next.js 프론트엔드 등, 같은 도메인(또는 서브도메인) 위의 SPA로부터 이용하는 경우. 보다 시큐어하고 토큰 관리가 불필요.
마지막 수정일 2026년 7월 13일