메인 콘텐츠로 건너뛰기

개요

Laravel Bluesky는 두 가지 인증 방식을 지원합니다. 인증 이후의 API 호출은 두 방식 모두 공통입니다.
항목App PasswordOAuth
내부 클래스LegacyAgent / LegacySessionOAuthAgent / OAuthSession
진입점Bluesky::login()Bluesky::withToken(OAuthSession)
비밀 키불필요BLUESKY_OAUTH_PRIVATE_KEY가 필요
사용자의 인가 조작불필요필요(브라우저에서 승인)
백그라운드 실행✅ 적합✅ 가능(refresh_token을 저장)
세션 키accessJwt / refreshJwtaccess_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()
didBluesky DIDdid()
handle핸들handle()
email이메일 주소email()
active계정이 활성 상태인지active()

적합한 사용 사례

  • 백그라운드 잡·큐 처리에서의 자동 게시
  • Laravel Notification 채널을 사용한 알림
  • 배치 처리·스케줄링
  • 애플리케이션 자신의 계정으로 게시하는 경우

OAuth (OAuthAgent)

인증 흐름

Bluesky::withToken()

Socialite로 취득한 OAuthSessionwithToken()에 전달합니다.
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 / subBluesky DIDdid()
iss인가 서버 URLissuer()
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를 사용하는 구성도 자주 볼 수 있습니다.

참고 링크

마지막 수정일 2026년 7월 13일