← 전체 글로 돌아가기

API

API 세션 인증이 로컬에서는 되는데 배포 후 안 될 때

로컬 개발 환경과 운영 환경의 인증 설정 차이를 추적하고 해결하기.

API 개발을 하다 보면 로컬에서는 잘 동작하던 인증 로직이 운영 환경에서 갑자기 안 되는 경험을 한다. 대부분 환경 설정 차이에서 비롯된다.

먼저 인증 상태를 확인하자

curl -i -H 'Authorization: Bearer token' 'https://api.example.com/me'

응답 코드를 보자.

  • 200: 정상
  • 401: 토큰 없거나 만료됨
  • 403: 권한 부족
  • 500: 서버 에러

상태 코드에 따라 원인이 달라진다.

로컬과 운영의 인증 차이

토큰 생성 방식

로컬에서는 테스트 토큰을 하드코딩할 수 있지만, 운영에서는 자동 갱신되는 토큰을 써야 한다.

// ❌ 로컬 개발용
const token = 'test-token-abc123';

// ✅ 운영
const token = await getAuthToken(); // API에서 동적으로 받기

쿠키 vs 헤더

로컬에서는 Authorization 헤더로 토큰을 전달하지만, 운영에서는 쿠키를 쓸 수 있다.

# 로컬: 헤더로 전달
curl -H 'Authorization: Bearer token' https://localhost:3000

# 운영: 쿠키로 전달
curl -b 'session=abc' https://api.example.com

이게 다르면 withCredentials 설정도 달라진다.

요청 파라미터 확인

curl -i 'https://api.example.com/api/items?page=1' \
  -H 'Authorization: Bearer token' \
  -H 'Content-Type: application/json'

확인할 것:

  • 쿠키가 제대로 첨부되었는가?
  • CORS 헤더가 있는가?
  • 요청 바디 형식이 맞는가?

응답 Body 확인

단순히 상태 코드만 보지 말고, 실제 응답 메시지를 봐야 한다.

{
  "error": "invalid_token",
  "error_description": "Token expired at 2024-06-30 14:30:00"
}

이 정보가 원인을 알려주는 경우가 많다.

환경 변수 체크리스트

로컬과 운영에서 다를 수 있는 것들:

# .env 파일 확인
echo $API_SECRET
echo $API_BASE_URL
echo $SESSION_TIMEOUT
echo $CORS_ORIGIN

로컬에서는 http://localhost:3000이지만 운영에서는 https://api.example.com일 수 있다.

상태 코드별 대응

401 (Unauthorized)

if (response.status === 401) {
  // 토큰 갱신 시도
  const newToken = await refreshToken();
  // 원래 요청 재시도
}

403 (Forbidden)

사용자는 인증되었지만 이 리소스에 접근할 권한이 없다. 권한 설정을 확인해야 한다.

500 (Server Error)

서버 로그를 확인한다.

sudo journalctl -u api-service -n 50

실제로 재현되는지 확인

# 로컬
flutter run  # 또는 npm start

# 운영
curl -H 'Authorization: Bearer $(cat ~/.tokens/api-token)' \
  https://api.example.com/api/user/me

같은 요청인데 결과가 다르면, 확실히 환경 차이다.

체크리스트

  1. 토큰이 실제로 유효한가? (갱신되었는가?)
  2. 요청이 올바른 엔드포인트로 가고 있는가?
  3. 헤더와 쿠키 설정이 일치하는가?
  4. CORS 설정이 올바른가?
  5. 타임존이 다르지는 않는가? (토큰 만료 시간)

마지막으로, 로그를 자세히 보면 대부분의 인증 문제는 해결된다. 작은 환경 차이가 큰 장애로 이어지는 게 API 인증의 특징이니까.