Laravel Bluesky는 두 가지 인증 방식을 지원합니다. 인증 이후의 API 호출은 두 방식 모두 공통입니다.
| 항목 | App Password | OAuth |
|---|
| 내부 클래스 | LegacyAgent / LegacySession | OAuthAgent / OAuthSession |
| 진입점 | Bluesky::login() | Bluesky::withToken(OAuthSession) |
| 비밀 키 | 불필요 | BLUESKY_OAUTH_PRIVATE_KEY가 필요 |
| 사용자의 인가 조작 | 불필요 | 필요(브라우저에서 승인) |
| 백그라운드 실행 | ✅ 적합 | ✅ 가능(refresh_token을 저장) |
| 세션 키 | accessJwt / refreshJwt | access_token / refresh_token |
| 폐지 예정 | 없음 | — |
| 주 용도 | 자동 게시·알림·배치 처리 | 사용자 대리 조작·Socialite 연동 |
LegacyAgent라는 명칭은 “OAuth 이전의 인증 방식”을 의미하지만, App Password 자체는 폐지 예정이 아닙니다. 알림이나 자동 게시 등 사용자 조작이 필요 없는 상황에서는 App Password가 더 단순하고 적합합니다.
아키텍처
BlueskyManager는 Facade Bluesky의 실체입니다. login() 또는 withToken()으로 에이전트를 설정하고, 이후의 API 호출은 두 인증 방식 모두 동일한 메서드를 사용합니다.
App Password (LegacyAgent)
인증 흐름
Bluesky::login()
.env에 App Password를 설정하고 login()을 호출하기만 하면 됩니다.
BLUESKY_IDENTIFIER=your-handle.bsky.social
BLUESKY_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
use Revolution\Bluesky\Facades\Bluesky;
$response = Bluesky::login(
identifier: config('bluesky.identifier'),
password: config('bluesky.password'),
)->post('Hello Bluesky');
LegacySession의 재사용
매번 login()을 호출하면 매번 API 요청이 발생합니다. 세션을 캐시하여 재사용하면 더 효율적입니다.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Session\LegacySession;
// 최초 로그인 후 세션을 저장
Bluesky::login(
identifier: config('bluesky.identifier'),
password: config('bluesky.password'),
);
cache()->put('bluesky_session', Bluesky::agent()->session()->toArray(), now()->addDay());
// 다음 실행부터는 캐시에서 복원
$session = LegacySession::create(cache('bluesky_session', []));
Bluesky::withToken($session);
// 액세스 토큰이 만료되었다면 갱신
if (! Bluesky::check()) {
Bluesky::refreshSession();
}
$response = Bluesky::post('Hello from cached session');
LegacySession의 주요 키
| 키 | 내용 | 메서드 |
|---|
accessJwt | 액세스 토큰 | token() |
refreshJwt | 리프레시 토큰 | refresh() |
did | Bluesky DID | did() |
handle | 핸들 | handle() |
email | 이메일 주소 | email() |
active | 계정이 활성 상태인지 | active() |
적합한 사용 사례
- 백그라운드 잡·큐 처리에서의 자동 게시
- Laravel Notification 채널을 사용한 알림
- 배치 처리·스케줄링
- 애플리케이션 자신의 계정으로 게시하는 경우
OAuth (OAuthAgent)
인증 흐름
Bluesky::withToken()
Socialite로 취득한 OAuthSession을 withToken()에 전달합니다.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Session\OAuthSession;
// Laravel 세션에서 복원(Web 요청)
$session = OAuthSession::create(session('bluesky_session'));
$timeline = Bluesky::withToken($session)->getTimeline();
백그라운드 잡이나 Console에서도 DB에 저장한 값으로 OAuthSession을 구성할 수 있습니다.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Session\OAuthSession;
$session = OAuthSession::create([
'did' => $user->did,
'refresh_token' => $user->refresh_token,
// bsky.social 이외의 계정은 iss도 지정
// 'iss' => $user->iss,
]);
$response = Bluesky::withToken($session)
->refreshSession()
->post('Hello from OAuth');
OAuthSession의 주요 키
| 키 | 내용 | 메서드 |
|---|
access_token | 액세스 토큰 | token() |
refresh_token | 리프레시 토큰(1회만 사용 가능) | refresh() |
did / sub | Bluesky DID | did() |
iss | 인가 서버 URL | issuer() |
profile.handle | 핸들 | handle() |
profile.displayName | 표시 이름 | displayName() |
OAuth의 refresh_token은 한 번밖에 사용할 수 없습니다. OAuthSessionUpdated 이벤트를 사용하여 토큰 갱신 후에는 반드시 DB를 업데이트하세요. 자세한 내용은 Socialite를 참조하세요.
적합한 사용 사례
- Socialite를 사용한 사용자 로그인
- 사용자를 대신하여 API를 호출하는 조작
- 사용자별로 다른 계정으로 조작해야 하는 경우
인증 이후의 API 호출은 공통
두 인증 방식 모두 withToken() 이후에는 동일한 API 메서드를 사용합니다.
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Session\LegacySession;
use Revolution\Bluesky\Session\OAuthSession;
// App Password
Bluesky::login(config('bluesky.identifier'), config('bluesky.password'));
// 또는 OAuth
$session = OAuthSession::create(session('bluesky_session'));
Bluesky::withToken($session);
// ↓ 이후의 API 호출은 완전히 공통 ↓
Bluesky::post('Hello Bluesky');
Bluesky::getTimeline();
Bluesky::getProfile();
Bluesky::searchPosts(q: '#laravel');
BlueskyManager는 내부에서 LegacyAgent 또는 OAuthAgent를 나눠 사용하지만, 호출 측 코드에는 영향을 주지 않습니다.
어느 쪽을 선택해야 하는가
| 상황 | 권장 |
|---|
| 자동 게시·알림·배치 | App Password |
| 사용자 로그인 기능 | OAuth |
| 백그라운드 잡만 사용 | App Password |
| 사용자 대리 조작이 필요 | OAuth |
| 운용의 단순함을 우선 | App Password |
| 보안·권한 제어 중시 | OAuth |
망설여질 때는 목적별로 나누는 것이 가장 알기 쉽습니다. “앱이 스스로 동작”한다면 App Password, “사용자가 조작”한다면 OAuth입니다. 두 가지를 조합하는 것도 가능하며, 알림에는 App Password를 사용하고 사용자 로그인에는 OAuth를 사용하는 구성도 자주 볼 수 있습니다.
참고 링크