
HTTP 401 vs 403: 인증 실패와 권한 부족, 헷갈리지 않게 구분하는 법
HTTP 401 Unauthorized와 403 Forbidden 오류의 차이를 인증(Authentication)과 인가(Authorization) 개념으로 이해하고, 실무에서 바로 적용할 수 있는 점검 순서와 상황별 코드 선택 기준을 정리합니다.
HTTP 401 Unauthorized는 클라이언트가 인증되지 않았거나 유효한 인증 정보가 부족할 때 발생합니다. 403 Forbidden은 인증은 완료되었지만 요청한 리소스에 대한 접근 권한이 없을 때 반환됩니다. 따라서 문제 원인이 인증 단계인지 권한 단계인지 구분하고, 인증 정보 확인 후 권한 설정을 점검하는 순서로 접근해야 합니다.
HTTP 상태 코드 4xx가 의미하는 클라이언트 오류의 개요
HTTP 상태 코드 중 4XX는 클라이언트 오류를 나타냅니다. 이는 서버가 요청을 정상적으로 받았지만, 요청 내용에 문제가 있어 처리를 거부했음을 뜻합니다. 401 Unauthorized와 403 Forbidden도 이 범주에 속하며, 각각 인증과 인가라는 서로 다른 층위의 문제를 나타냅니다. 따라서 오류 메시지만으로는 혼동하기 쉬우므로, 두 코드의 근본적인 차이를 이해하는 것이 중요합니다.
401 Unauthorized: 인증되지 않은 요청
HTTP 401 Unauthorized는 클라이언트가 인증되지 않았으며 유효한 자격 증명이 필요함을 의미합니다. 이 응답을 받은 클라이언트는 적절한 인증 정보를 포함하여 다시 요청할 수 있습니다. 실제로 401은 단순히 ‘인증 정보 없음’ 뿐만 아니라, 인증 토큰의 만료 또는 잘못된 형식으로 인해 발생할 수 있습니다. 401 오류가 발생하면 가장 먼저 인증 토큰의 존재, 형식, 유효성을 확인하고 자격 증명이 정확한지 검사해야 합니다.
401이 발생하는 대표 시나리오
401은 다음과 같은 상황에서 자주 나타납니다.
- 사용자가 로그인하지 않거나 유효하지 않은 자격 증명으로 보호된 페이지에 접근하는 경우. 사용자가 로그인하지 않거나 유효하지 않은 자격 증명으로 보호된 페이지에 접근하면 서버는 401을 반환합니다.
- 요청에 Authorization 헤더가 없거나, Bearer 토큰 등의 인증 수단이 누락된 경우. 인증 정보가 누락된 요청, 예를 들어 Authorization 헤더가 없는 경우 서버는 401을 반환합니다.
- AccessToken 없이 API를 호출하는 경우. AccessToken 없이 보낸 요청은 401 Unauthorized 응답을 받습니다.
- 로그인 과정에서 다중 요소 인증(MFA)을 완료하지 않은 경우. 로그인 과정에서 필수 다중 요소 인증(MFA)을 완료하지 않은 경우 서버는 401을 반환합니다.
- 인증 토큰이 만료되었거나 무효화된 경우. 401은 인증 토큰이 없거나 유효하지 않거나 만료되어 발생하는 인증 실패입니다.
이러한 상황에서는 서버가 클라이언트에게 인증을 다시 시도하거나 자격 증명을 확인하도록 유도합니다.
403 Forbidden: 인증은 됐지만 권한이 없는 요청
HTTP 403 Forbidden은 클라이언트가 인증은 되었지만 리소스에 접근할 권한이 없음을 나타냅니다. 401과 달리, 403 응답은 이미 인증은 통과했지만 인가에 실패했음을 알립니다. MDN에 따르면 403 응답은 재인증으로 해결되지 않습니다. 따라서 403은 단순히 ‘권한 없음’을 넘어, 의도적인 접근 제어 결과로 이해해야 합니다.
403이 발생하는 대표 시나리오
403 오류는 다음과 같은 경우에 발생합니다.
- 인증된 사용자가 필요한 권한이나 역할을 가지고 있지 않을 때. 인증된 사용자가 필요한 권한이나 역할을 가지고 있지 않을 때 403이 반환됩니다.
- 관리자 역할이 없는 사용자가 관리자 전용 페이지에 접근하려고 하는 경우. 관리자 역할이 없는 사용자가 관리자 전용 페이지에 접근하려고 하면 서버는 403을 반환합니다.
- 리소스 접근이 특정 사용자나 그룹에 의도적으로 제한된 경우. 리소스 접근이 특정 사용자나 그룹에 의도적으로 제한된 경우 403이 반환됩니다.
- 이미 인증된 사용자가 다른 사용자의 데이터에 접근하려는 경우. 인증된 사용자가 접근 권한이 없는 리소스를 요청할 때 전형적으로 403 응답이 발생합니다.
403 응답은 인가가 실패했음을 명시하지만, 때로는 보안 정책에 따라 403 대신 404 Not Found를 반환하는 관례도 있습니다.
401과 403을 구분하는 핵심 기준: 신원 확인 vs 접근 허가
401과 403의 경계는 인증과 인가의 차이에서 비롯됩니다. 인증은 ‘누구인지 확인’하는 과정이고, 인가는 ‘무엇을 할 수 있는지 허가’하는 과정입니다. 401은 인증 실패이므로, 올바른 자격 증명을 제공하면 문제가 해결될 가능성이 높습니다. 반면 403은 인증은 완료되었으므로 자격 증명을 바꾸거나 다시 로그인해도 해결되지 않으며, 권한 설정을 변경해야 합니다. MDN에 따르면 401은 403과 유사하지만 사용자 인증으로 해결될 수 있습니다. 다음 표는 두 상태 코드의 차이를 요약합니다.
| 구분 | 401 Unauthorized | 403 Forbidden |
|---|---|---|
| 의미 | 인증되지 않음 | 권한 없음 |
| 주요 원인 | 자격 증명 없음, 토큰 만료, 잘못된 형식 | 역할 부족, 접근 제한 |
| 재인증 효과 | 유효한 인증 시 성공 | 재인증해도 해결 불가 |
| 응답 헤더 | WWW-Authenticate 필수 권장 | 없음 |
실무에서는 이러한 차이를 바탕으로 API 응답 코드를 선택해야 합니다. 상태 코드 선택이 중요한 것과 마찬가지로, 적절한 리다이렉션 상태 코드(예: 301과 302의 차이)도 운영에 큰 영향을 줍니다. 자세한 내용은 301 vs 302 리다이렉트 차이 글을 참고하세요.
보안 관례: 403 대신 404를 반환하는 이유
일부 웹 애플리케이션은 리소스 존재 여부를 숨기기 위해 403 대신 404를 반환합니다. 이는 403 응답을 보내면 요청한 리소스가 존재함을 공격자에게 알려주기 때문에 보안에 취약할 수 있습니다. 공격자는 403 응답을 통해 관리자 페이지나 내부 API 경로의 존재를 추측할 수 있으므로, 이런 정보를 숨기기 위해 서버는 의도적으로 404를 내려줍니다. 리소스의 존재 자체를 숨기고 싶다면 403보다 404 Not Found가 더 적합할 수 있습니다.
대표적인 사례로 GitHub는 다른 사용자의 비공개 저장소에 접근할 때 403 대신 404를 반환합니다. 또 한 결제 회사는 내부 자격 증명이 제공되지 않으면 내부 엔드포인트에 대해 404를 반환합니다. 이러한 관행은 보안을 강화하지만, 정상 사용자에게 혼란을 줄 수 있으므로 상황에 맞게 신중히 선택해야 합니다. 상황에 따라 절대적으로 올바른 상태 코드는 없으며, 유연하게 선택할 수 있습니다.
실전 예제: 상황별 상태 코드 선택
로그인 없이 보호된 페이지에 접근한 경우
비로그인 상태에서 /dashboard 같은 인증이 필요한 페이지를 요청하면, 서버는 클라이언트의 신원을 알 수 없으므로 401 Unauthorized를 반환해야 합니다. 이때 응답 헤더에 WWW-Authenticate를 포함하여 어떤 인증 방식이 필요한지 알려주는 것이 좋습니다.
로그인한 사용자가 관리자 전용 페이지에 접근한 경우
일반 사용자로 로그인한 후 /admin과 같은 관리자 전용 페이지에 접근하려고 하면, 인증은 통과했지만 ‘관리자’ 역할이 없기 때문에 403 Forbidden이 적합합니다. 경우에 따라 이 페이지의 존재 자체를 숨기고 싶다면 404를 반환할 수도 있습니다.
로그인 중 MFA를 완료하지 않은 경우
사용자가 올바른 아이디와 비밀번호를 입력했지만, 설정된 다중 요소 인증(예: OTP)을 아직 완료하지 않은 상태에서 보호된 리소스를 요청하면, 인증 절차가 완전히 끝나지 않은 것이므로 401을 반환합니다. 이때는 추가 인증을 안내하는 메시지를 함께 제공하는 것이 일반적입니다.
401·403 오류 발생 시 점검 순서
오류가 발생했을 때는 증상에 따라 체계적으로 점검해야 합니다. 다음 체크리스트를 순서대로 따라가면 문제의 원인을 빠르게 찾을 수 있습니다.
401 Unauthorized 응답 점검 체크리스트
401 오류가 발생하면 가장 먼저 인증 토큰의 존재, 형식, 유효성을 확인하고 자격 증명이 정확한지 검사해야 합니다. 만약 스프링 시큐리티를 사용하고 있다면, 스프링 시큐리티에서 AuthenticationEntryPoint는 인증 예외를 처리하고 401 상태 코드를 전달합니다. 다음 항목을 점검하세요.
- 요청에 Authorization 헤더가 존재하는지 확인하고,
Bearer,Basic등의 형식이 올바른지 점검합니다. - 토큰이 만료되지 않았는지, 유효한 서명이나 비밀키로 생성되었는지 검증합니다.
- API 키 또는 사용자 이름과 비밀번호가 정확한지 확인하고, 서버에서 기대하는 인증 수단(예: OAuth2, JWT)과 일치하는지 봅니다.
- MFA가 필요한 서비스라면 추가 인증이 완료되었는지 체크합니다.
403 Forbidden 응답 점검 체크리스트
403 오류가 발생했다면 이미 인증은 성공했지만 권한 부여 과정에 문제가 있습니다. 403은 토큰이 유효하더라도 발생하는 권한 부여 실패입니다. 스프링 시큐리티에서 AccessDeniedHandler는 권한 예외를 처리하고 403 상태 코드를 전달합니다. 다음 항목을 점검하세요.
- 사용자에게 해당 리소스에 접근할 수 있는 역할(Role)이나 권한(Permission)이 부여되어 있는지 확인합니다.
- 접근 제어 목록(ACL)이나 요청 메서드(GET, POST 등) 별 제한 사항이 있는지 검토합니다.
- 서버 로그를 통해 인가 처리가 어떤 단계에서 거부되었는지 추적합니다.
- 보안 정책상 403 대신 404를 반환하도록 의도한 것은 아닌지 확인합니다.
참고 자료
- Logto 블로그: 401 vs 403 — 확인일 2026-08-01
- 망키티스토리: 401 vs 403 — 확인일 2026-08-01
- 주니어 데이터리스트: 401, 403 차이 — 확인일 2026-08-01
- Reddit 프로그래밍 스레드 — 확인일 2026-08-01
- 벨로그: 401 vs 403 비교 — 확인일 2026-08-01