Apple 패키지 분석 — 한국 Laravel 개발자 가이드
작성: 라라벨 코리아 (AI 초안 · AI 검수)
발행: 2026년 7월 12일
Laravel Socialite용 Apple OAuth2 프로바이더
요약
socialiteproviders/apple 패키지 버전 5.10.0은 Laravel Socialite를 통해 "Apple로 로그인(Sign In with Apple)" 기능을 구현할 수 있게 해주는 OAuth2 프로바이더입니다. Apple의 특수한 인증 방식(JWT 기반 client_secret, 6개월 만료 등) 때문에 일반 소셜 로그인보다 설정 난이도가 높으며, 한국 개발자들이 실무에서 자주 마주치는 함정들이 존재합니다. 이 글에서는 설치부터 운영 환경 적용까지 실무 중심으로 안내합니다.
핵심 내용
Apple 소셜 로그인이 다른 OAuth와 다른 이유
일반적인 Google, GitHub 소셜 로그인과 달리, Apple의 "Sign In with Apple"은 몇 가지 중요한 차이점이 있습니다.
- client_secret이 정적 문자열이 아닌 JWT 토큰: 일반 OAuth2에서
client_secret은 고정된 문자열이지만, Apple은 ES256 알고리즘으로 서명된 JWT를client_secret으로 사용합니다. - JWT 최대 유효기간 6개월: Apple 정책상 client_secret JWT의 최대 수명은 **6개월(180일)**입니다. 이를 간과하면 운영 중 갑작스러운
invalid_client오류가 발생합니다. - 반환 필드가 최소화: 반환되는 사용자 정보가
id,name,email세 가지뿐이며, 이름과 이메일은 최초 로그인 시에만 제공됩니다. 이후 로그인에서는name이 null로 반환됩니다.
두 가지 client_secret 전략
패키지는 두 가지 방식으로 client_secret을 처리할 수 있습니다.
방법 1: 수동으로 JWT를 생성하여 .env에 등록
'apple' => [
'client_id' => env('APPLE_CLIENT_ID'),
'client_secret' => env('APPLE_CLIENT_SECRET'), // 미리 생성한 JWT 문자열
'redirect' => env('APPLE_REDIRECT_URI'),
],- 장점: 설정이 단순함
- 단점: 6개월마다 수동 갱신 필수 — 캘린더 알림 없이 방치하면 운영 장애로 직결됨
방법 2: 매 요청마다 private key로 JWT를 자동 생성 (권장)
'apple' => [
'client_id' => env('APPLE_CLIENT_ID'),
'client_secret' => '', // 비워둠
'key_id' => env('APPLE_KEY_ID'),
'team_id' => env('APPLE_TEAM_ID'),
'private_key' => env('APPLE_PRIVATE_KEY'), // 절대 경로 필수 (예: /var/www/cert/AuthKey_XYZ.p8)
'passphrase' => env('APPLE_PASSPHRASE'), // 선택
'redirect' => env('APPLE_REDIRECT_URI'),
],- 장점: 만료 걱정 없이 자동 갱신
- 단점:
.p8키 파일의 서버 내 보안 관리 필요
JWT 시간 불일치 오류 (Known Issue)
실무에서 빈번히 발생하는 문제로, 다음과 같은 예외가 발생할 수 있습니다.
InvalidStateException: The token was issued in the future
at /vendor/socialiteproviders/apple/Provider.php:207이는 Apple 서버와 애플리케이션 서버 간의 시스템 시계 불일치로 인해 발생합니다. 해결 방법은 .env에 leeway 값을 추가하는 것입니다.
APPLE_JWT_ISSUED_TIME_LEEWAY=PT10S # 10초 여유 (기본값: PT3S)ISO 8601 Duration 형식을 사용합니다: PT3S(3초), PT1M(1분)
invalid_client 400 오류 대응
400 Bad Request {"error":"invalid_client"} 오류 발생 시 점검 순서:
client_secretJWT 만료 여부 확인APPLE_CLIENT_ID가 Apple Developer Console의 Services ID (Bundle ID가 아님)와 일치하는지 확인- Signer 알고리즘 불일치 시
config/services.php에 명시적으로 지정:
'signer' => \Lcobucci\JWT\Signer\Ecdsa\Sha256::class,Laravel 버전별 이벤트 리스너 등록 방식 차이
| Laravel 버전 | 등록 방법 |
|---|---|
| Laravel 11+ | AppServiceProvider의 boot() 메서드에서 Event::listen() 사용 |
| Laravel 10 이하 | EventServiceProvider의 $listen 배열에 등록 |
Laravel 11+ 예시:
// app/Providers/AppServiceProvider.php
public function boot(): void
{
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('apple', \SocialiteProviders\Apple\Provider::class);
});
}한국 Laravel 개발자에게 미치는 영향
호환성
- Laravel 11 기준:
EventServiceProvider가 기본 제거되었으므로, 구버전 가이드를 그대로 따라할 경우 리스너가 동작하지 않습니다. 반드시AppServiceProvider방식을 사용해야 합니다. - PHP 버전:
lcobucci/jwt라이브러리 의존성이 있으므로, PHP 8.1 이상 환경을 권장합니다.
보안 고려 사항
.p8개인 키 파일은 웹 루트(public/) 외부에 저장해야 합니다.- Laravel Sail 환경에서는 컨테이너 내부 절대 경로(
/var/www/html/cert/AuthKey_XYZ.p8)를 사용하고,docker-compose.yml의volumes에 키 파일 경로를 마운트해야 합니다. - Laravel Valet 환경에서는 macOS 로컬 절대 경로를 그대로 사용할 수 있으나,
.gitignore에.p8파일을 반드시 추가해야 합니다.
Apple 정책 특이사항 (한국 앱스토어 관련)
- iOS/macOS 앱에서 소셜 로그인을 제공할 경우 Apple은 "Apple로 로그인" 버튼을 반드시 포함하도록 강제합니다. 한국 앱 개발사가 Laravel 백엔드와 연동하는 경우 이 패키지가 사실상 필수입니다.
- App Store Connect에서 "Sign In with Apple" 기능을 활성화하고, Apple Developer의 Identifiers > Services IDs 설정이 선행되어야 합니다.
6개월 만료 운영 리스크
수동 JWT 방식을 사용하는 팀에서 갱신을 놓치는 경우, 운영 중 모든 Apple 로그인이 일시에 차단됩니다. 자동 생성 방식(private key 방식)을 기본으로 채택하고, 인프라팀과 키 파일 백업 정책을 사전에 합의할 것을 권장합니다.
실무 체크리스트
Apple Developer Console 설정
- App ID 생성 및 "Sign In with Apple" 기능 활성화
- Services ID 생성 (이것이
APPLE_CLIENT_ID로 사용됨 — App ID와 혼동 주의) - Services ID에 도메인 및 Return URL 등록 (
APPLE_REDIRECT_URI와 정확히 일치해야 함) - Keys 메뉴에서 "Sign In with Apple" 키 생성 후
.p8파일 다운로드 (재다운로드 불가) -
APPLE_KEY_ID(키 생성 시 표시되는 10자리 ID) 및APPLE_TEAM_ID(Apple Developer 계정 Team ID) 확인
패키지 설치 및 환경 설정
-
composer require socialiteproviders/apple실행 -
.env에 필요한 환경 변수 추가:
APPLE_CLIENT_ID=com.yourcompany.yourapp.service # Services ID
APPLE_CLIENT_SECRET= # private key 방식 사용 시 비워둠
APPLE_KEY_ID=XXXXXXXXXX
APPLE_TEAM_ID=XXXXXXXXXX
APPLE_PRIVATE_KEY=/var/www/cert/AuthKey_XXXXXXXXXX.p8
APPLE_REDIRECT_URI=https://yourapp.com/auth/apple/callback
APPLE_JWT_ISSUED_TIME_LEEWAY=PT5S # 시계 불일치 대비 여유값-
.p8파일을 웹 루트 외부에 배치 및.gitignore등록 확인 -
config/services.php에 apple 설정 블록 추가
Laravel 버전별 이벤트 리스너 등록
- Laravel 11+:
AppServiceProvider::boot()에Event::listen()방식으로 등록 - Laravel 10 이하:
EventServiceProvider::$listen에AppleExtendSocialite::class.'@handle'등록
로컬 개발 환경 (Valet / Sail)
- Valet:
https://환경 필수 —valet secure명령으로 TLS 활성화 (Apple은 HTTP 콜백 허용 안 함) - Sail:
docker-compose.yml에.p8파일 볼륨 마운트 추가:
volumes:
- ./cert:/var/www/cert:ro- Apple Developer Console의 Return URL에 로컬 도메인 추가 (예:
https://yourapp.test/auth/apple/callback)
스테이징 / 운영 배포
-
.p8파일을 CI/CD 시크릿 또는 서버 배포 스크립트로 안전하게 전달 (Git에 절대 포함 금지) - 운영 서버의 파일 권한 확인:
.p8파일은640또는600으로 설정 - 수동 JWT 방식 사용 팀: 6개월 만료일 기준 5개월 차에 갱신 알림을 팀 캘린더에 등록
- 최초 로그인 시에만
name이 반환됨을 DB 설계에 반영 (이후 로그인 시null처리 로직 필수) - 콜백 컨트롤러에서
email이 null인 경우 처리 로직 추가 (Apple은 이메일 숨기기 옵션 제공)
테스트
- 신규 Apple ID로 최초 로그인 →
name,email정상 수신 확인 - 동일 Apple ID로 재로그인 →
name이 null인 경우 정상 처리 확인 - "이메일 숨기기" 옵션 선택 시 릴레이 이메일(
@privaterelay.appleid.com) 정상 저장 확인 -
JWT_ISSUED_TIME_LEEWAY조정 후InvalidStateException재현 여부 확인