백엔드 구현에서 **인증(Authentication)**과 **권한 관리(Authorization)**는 핵심 중 핵심이에요.
단계별로 정리하면서 실무에서 어떻게 구현하는지 차근차근 설명할게요.
1️⃣ 인증(Authentication) – 누가 접근하는지 확인
🔹 목적
- 사용자가 누구인지 확인
- 로그인, 세션, 토큰 등을 통해 신원을 검증
🔹 구현 방법
| 방법 | 설명 | 특징 |
| 세션 기반 인증 (Session-based) |
서버가 로그인 세션을 관리 쿠키에 세션 ID 저장 |
서버 메모리/DB에 상태 저장 필요 |
| 토큰 기반 인증 (Token-based, JWT) |
로그인 시 서버가 JWT(JSON Web Token) 발급 클라이언트가 매 요청마다 전송 |
서버는 상태 저장 불필요, 분산 환경 유리 |
| OAuth / Social Login | 구글, 카카오, 페이스북 등 외부 인증 사용 | 소셜 계정으로 로그인 가능 |
🔹 예시: JWT 인증 흐름
- 클라이언트 → 로그인 정보 제출
- 서버 → 사용자 확인 후 JWT 생성
- 클라이언트 → 요청 시 JWT 헤더(Authorization: Bearer <token>)에 포함
- 서버 → JWT 검증 후 요청 처리
핵심: 인증은 “누구인지 확인”하는 과정
Q. Authorization 헤더 유무
1️⃣ Authorization 헤더란?
- Authorization 헤더 = 클라이언트가 서버에 “나는 누구다”를 증명하는 정보를 담는 곳
- 보통 형식:
- 서버는 이 헤더를 보고 사용자를 인증(Authentication) 합니다.
2️⃣ 헤더가 없을 때 의미
- 헤더가 없다고 무조건 인증이 필요 없는 요청은 아님
- 의미는 클라이언트가 인증 정보를 보내지 않았다는 것
상황별 의미
| 공개 API | 누구나 접근 가능 | 헤더 없어도 OK |
| 인증 필요 API | 헤더 없음 | 401 Unauthorized → 인증 필요 |
| 선택적 인증 | 헤더 있으면 인증 처리, 없으면 기본값 | 예: 로그인 여부에 따라 동작 분기 |
즉, 헤더가 없으면 서버가 요청한 API에 따라 달라짐
3️⃣ 실무 예시 (Express.js + JWT)
- /public → 인증 필요 없음, 헤더 없어도 요청 처리
- /private → 인증 필요, 헤더 없으면 실패
4️⃣ 핵심 요약
- Authorization 헤더 = 사용자 인증 정보
- 없으면 인증 안 함이 아니라 서버가 요구하는 API에 따라 다름
- 공개 API → 헤더 없어도 OK
- 인증 필요 API → 헤더 없으면 401 Unauthorized
- 선택적 인증 가능 → 로그인 상태 확인용
💡 실무 팁:
- API 설계 시 각 엔드포인트마다 인증 필요 여부 명시
- 미들웨어에서 헤더 유무 + 유효성 검사 한 번에 처리
Q. 토큰 방식 종류
1️⃣ 토큰 기반 인증(Token-based Authentication)이란?
- 로그인 후 서버가 발급한 토큰을 클라이언트가 매 요청마다 보내는 방식
- 서버는 토큰을 검증해서 사용자 인증 수행
- 특징: 서버 상태를 유지하지 않아도 됨 → stateless
2️⃣ 토큰 방식 종류
| JWT (JSON Web Token) | 표준 규격, Payload에 사용자 정보 담아서 서명(Signature) | 많이 사용됨, 상태 비저장, 분산 서버에 유리 |
| Opaque Token (불투명 토큰) | 서버가 발급하고 DB/Redis에서 토큰-사용자 매핑 관리 | 서버에서 상태 관리 필요, JWT보다 안전성 높음(정보 노출 없음) |
| Session Token | 전통적 세션 기반 토큰, 세션 ID를 발급 | 서버 상태 유지 필요, 토큰 자체에 정보 없음 |
결론: JWT가 토큰 방식에서 가장 많이 쓰이는 편이지만 유일한 방식은 아님.
요구사항에 따라 Opaque Token, Session Token 등 다른 방식도 충분히 가능
3️⃣ JWT가 많이 쓰이는 이유
- 표준화 (RFC 7519)
- Stateless → 서버가 토큰 상태를 유지하지 않아도 됨
- 분산 시스템/마이크로서비스에서 편리
- Payload에 정보 담기 가능 → DB 조회 없이 인증 가능
4️⃣ JWT 한계
- 토큰 만료 전까지 취소가 어려움 (로그아웃 처리 어려움)
- Payload에 민감한 정보 넣으면 안됨 (암호화 필요)
- 길이가 길어서 요청 헤더에 부담될 수 있음
5️⃣ 실무 선택 기준
| 단일 서버, 상태 유지 OK | Session Token |
| 분산 서버, stateless | JWT |
| 보안 최우선, 토큰 유효 기간 길이 필요 | Opaque Token + DB/Redis 검증 |
✅ 정리
- 토큰 방식 = 서버 상태를 저장하지 않고 토큰으로 인증 처리
- JWT = 토큰 방식에서 가장 널리 쓰이는 표준
- 하지만 JWT만 있는 건 아님 → 상황과 요구사항에 맞춰 선택 가능
- 실무에서는 JWT + Refresh Token 조합이 흔함
Q. 로그인을 하고 나면, 서버가 세션 ID를 생성하고, 그 세션 ID를 쿠키에 저장한다는 거지?
이 쿠키는 영속 쿠키야, 세션 쿠키야? 브라우저 종료하면 사라지는 거야 유효기간까지 계속 있는거야?
그리고 서버 메모리/DB에 상태 저장이 왜 필요해? 어떤 상태 말하는 거임? 로그인 성공/실패?
1️⃣ 세션(Session) 기반 인증 기본 구조
- 사용자가 로그인 시도 → 서버가 사용자 인증
- 로그인 성공 → 서버가 세션 ID(Session ID) 생성
- 서버가 세션 저장소(메모리, DB, Redis 등)에 세션 ID와 사용자 정보를 저장
- 서버가 클라이언트(브라우저)에게 쿠키로 세션 ID 전달
- 이후 요청마다 쿠키에 있는 세션 ID를 서버에 보내서 인증 확인
2️⃣ 세션 쿠키 vs 영속 쿠키
- 세션 쿠키(Session Cookie)
- 브라우저 종료 시 자동 삭제
- 쿠키에 Expires/Max-Age가 지정되지 않은 경우
- 대부분 로그인 세션 쿠키는 기본적으로 세션 쿠키
- 영속 쿠키(Persistent Cookie)
- 유효기간(Expires 또는 Max-Age)이 지정되어 있음
- 브라우저 종료 후에도 남아 있음 → “로그인 유지” 등
즉, 세션 기반 로그인 쿠키는 보통 세션 쿠키로 설정
필요하면 “로그인 유지” 옵션으로 영속 쿠키로 만들 수도 있음
3️⃣ 서버에 상태를 저장하는 이유
- 서버가 세션 ID만으로 누가 로그인했는지 알 수 있어야 하기 때문
- 세션 저장소에 기록되는 상태(State):
| userId / role | 로그인한 사용자 정보 |
| 로그인 시간, 만료 시간 | 세션 만료 확인 |
| CSRF 토큰 등 | 보안 관련 상태 |
| 기타 임시 정보 | 예: 쇼핑카트, 진행 중인 단계 등 |
- 로그인 성공/실패만 저장하는 게 아님
- 로그인 성공 후 “누가 로그인했는지, 어떤 권한인지”를 유지하기 위해 필요
4️⃣ 요약 흐름
- 로그인 성공 → 서버: 세션 ID 생성 + 상태 저장
- 클라이언트: 세션 ID 쿠키 저장 (세션/영속)
- 요청 시 쿠키 전송 → 서버: 세션 ID 조회 → 사용자 인증/권한 확인
- 로그아웃 / 세션 만료 → 서버에서 상태 삭제
💡 한눈에 비교: 세션 vs 토큰 기반
| 상태 저장 | 서버(메모리/DB/Redis) | 서버 상태 저장 불필요(stateless) |
| 쿠키 | 세션 쿠키 / 영속 쿠키 | 보통 Authorization 헤더 |
| 장점 | 서버에서 제어 가능, 즉시 로그아웃 가능 | 분산 환경 용이, DB 조회 최소화 |
| 단점 | 서버 메모리 사용, 확장 어려움 | 토큰 탈취 시 즉시 차단 어려움 |
Q. OAuth 란? Social Login과 같은 것인가?
OAuth는 백엔드, 인증/소셜 로그인에서 핵심 개념이에요. 차근차근 설명할게요.
1️⃣ OAuth란?
- OAuth = Open Authorization의 약자
- 직역하면 “열린 권한 부여”
- 목적: 사용자 비밀번호를 직접 주고받지 않고, 서비스끼리 안전하게 권한을 위임하는 표준 프로토콜
즉, “내 비밀번호를 다른 서비스에 주지 않고, 다른 서비스가 내 데이터 일부를 사용하게 허락”하는 방법
2️⃣ OAuth 흐름 (간단하게)
예: GitHub 계정으로 로그인
- 사용자 → 애플리케이션 “GitHub로 로그인” 클릭
- 애플리케이션 → GitHub에 권한 요청
- GitHub → 사용자에게 “이 앱이 내 이메일, 이름 사용해도 되나요?” 동의 화면
- 동의 후 GitHub → 애플리케이션에 Authorization Code 전달
- 애플리케이션 → GitHub 서버에 Code를 Access Token으로 교환 요청
- GitHub → Access Token 발급 → 애플리케이션 사용
- 애플리케이션 → Access Token으로 사용자 정보 조회 후 로그인 처리
3️⃣ Social Login과의 관계
- Social Login = OAuth 기반 로그인
- 구글, 카카오, 네이버, 페이스북 등 외부 인증 서비스 사용
- Social Login = OAuth 2.0 프로토콜을 실제 서비스에 적용한 사례라고 보면 됨
즉, Social Login은 OAuth의 응용이고, OAuth 자체는 범용 인증/권한 위임 프로토콜
4️⃣ OAuth 특징
| 비밀번호 노출 없음 | 앱이 비밀번호를 직접 받지 않음 |
| Access Token 사용 | 권한 범위를 제한 가능 |
| Scope 지정 가능 | 이메일, 이름, 친구목록 등 접근 권한 제한 가능 |
| 표준화 | 서비스 간 일관된 인증/권한 위임 가능 |
5️⃣ OAuth vs JWT vs 세션
| 목적 | 서비스 간 권한 위임 | 인증 정보 안전하게 전달 | 서버에서 로그인 상태 유지 |
| 데이터 | Access Token | 토큰 안에 사용자 정보 | 서버 저장 |
| 특징 | Social Login, API 접근 허용 | Stateless 인증 | 서버 상태 필요 |
✅ 요약
- OAuth = Open Authorization
- 목적: 비밀번호 없이 안전하게 다른 서비스에 권한 위임
- Social Login = OAuth를 사용한 실제 로그인 구현
- 핵심 요소: Authorization Code → Access Token → 사용자 정보 조회
Q. Authorization: Bearer <token>에서 Bearer가 뭐야
1️⃣ Authorization 헤더 구조
- Authorization → HTTP 요청 헤더, 서버에 인증 정보 전달
- Bearer → 토큰 타입을 나타내는 키워드
- <token> → 실제 인증 토큰(JWT 등)
즉, 헤더 전체 의미:
“나는 Bearer 토큰 방식으로 인증할 테니, 서버는 이 토큰을 검증해 주세요.”
2️⃣ Bearer가 의미하는 것
- Bearer Token = “소지자(token을 가진 사람)에게 접근 권한이 있다”라는 의미
- 즉, 토큰 자체가 권한 증명 수단
- 서버 입장에서는 토큰을 가지고 있으면 누구인지 확인 가능
예: “토큰 가진 사람이 바로 권한을 가진 사람이다”
→ 토큰 자체가 증명서 역할
3️⃣ Bearer Token 특징
| 소지자 인증 | 토큰만 있으면 인증 가능, 별도 비밀번호 필요 없음 |
| 단순 사용 | Authorization 헤더에 Bearer <token>만 넣으면 됨 |
| 보안 주의 | 탈취되면 누구나 사용 가능 → HTTPS 필수 |
| 사용 범위 | OAuth2, JWT, API 인증 등에서 표준 |
4️⃣ 다른 Authorization 방식 예시
| Basic | Authorization: Basic <base64(username:password)> | 아이디/비밀번호 직접 전송 (암호화 필요) |
| Bearer | Authorization: Bearer <token> | 토큰 기반 인증, 현재 표준 |
| Digest | Authorization: Digest ... | HTTP Digest 인증, 보안 강화 |
요즘 API/백엔드 인증에서는 거의 대부분 Bearer 토큰 사용
✅ 요약
- Authorization 헤더 = 인증 정보 전달
- Bearer = “토큰 소지자가 접근 권한을 가진다”를 나타내는 토큰 타입
- <token> = 실제 인증 토큰(JWT 등)
- Bearer Token은 표준화된 API 인증 방식으로, HTTPS와 함께 사용해야 안전
2️⃣ 권한 관리(Authorization) – 무엇을 할 수 있는지 확인
🔹 목적
- 사용자가 특정 자원/기능에 접근할 수 있는지 검증
- 예: 일반 유저는 글 삭제 불가, 관리자만 삭제 가능
🔹 접근 방식
| 방식 | 설명 |
| Role-based Access Control (RBAC) | 사용자에게 역할(Role) 부여 / 역할에 권한 매핑 |
| Attribute-based Access Control (ABAC) | 사용자 속성, 리소스 속성, 환경 조건을 기준으로 접근 제어 |
| Permission 기반 | 세부 권한 단위(Permission) 직접 부여 |
🔹 예시: RBAC
- Roles: admin, user
- Permissions: create_post, delete_post, read_post
- 정책:
| Role | Permissions |
| admin | create, read, update, delete |
| user | create, read |
- 서버에서 요청 처리 시:
if (!req.user.roles.includes('admin')) {
return res.status(403).json({ message: "권한 없음" });
}
핵심: 권한 관리는 “누가 무엇을 할 수 있는지” 검증
Q. 서버에서 요청 처리 시 코드에 대한 설명
💡 전체 코드
이건 “관리자(admin) 권한이 없는 사용자면 접근 거부(403)” 하는 코드예요.
1️⃣ req 객체 — 요청(Request)
- req = 요청 객체(Request object)
- Express.js에서 클라이언트가 보낸 요청 정보를 담고 있음.
예:
여기서 req 안에는 이런 정보들이 들어 있어요 👇
| req.params | { id: 3 } | URL 경로 파라미터 |
| req.query | { page: 2 } | 쿼리스트링(?page=2) |
| req.body | { name: "Tom" } | 요청 본문 (POST/PUT) |
| req.headers | { authorization: "Bearer ..." } | 요청 헤더 |
| req.user | { id: 1, roles: ["user", "admin"] } | 인증 미들웨어가 추가한 사용자 정보 |
⚠️ req.user는 Express 기본 제공 속성이 아니에요.
JWT나 세션 인증을 처리하는 미들웨어가 직접 추가한 사용자 정보예요.
그래서 로그인한 사용자의 데이터가 들어가 있는 거죠.
2️⃣ req.user.roles와 includes()
예를 들어 미들웨어가 이렇게 넣었다고 가정해요:
- req.user.roles는 ["user"]라는 배열이에요.
- includes('admin')은 배열 안에 "admin"이 포함되어 있는지 확인하는 배열 메서드예요.
즉,
→ user의 roles 배열에 "admin"이 없으면 (관리자 아님)
→ 403 Forbidden 응답을 보내라는 뜻이에요.
3️⃣ res 객체 — 응답(Response)
- res = 응답 객체(Response object)
- 서버가 클라이언트에게 보낼 응답을 다루는 객체예요.
res.status(403)
- HTTP 응답 상태 코드를 설정하는 메서드
- 403은 Forbidden (권한 없음)
| 200 | 성공 |
| 201 | 생성됨 |
| 400 | 잘못된 요청 |
| 401 | 인증 실패 (로그인 필요) |
| 403 | 권한 없음 (로그인했지만 접근 금지) |
| 404 | 찾을 수 없음 |
즉,
→ “HTTP 상태 코드 403으로 응답을 준비하겠다”는 뜻이에요.
res.json({ message: "권한 없음" })
- json()은 JSON 형식의 응답 본문을 보낸다는 뜻.
- 안에 들어가는 { message: "권한 없음" }은 JS 객체예요.
- Express가 이걸 JSON 문자열({"message": "권한 없음"})로 변환해서 클라이언트로 보냄.
따라서 클라이언트가 받는 실제 응답은:
✅ 전체 동작 정리
- req.user → 로그인된 사용자 정보
- req.user.roles.includes('admin') → 관리자 권한인지 확인
- 조건에 안 맞으면→ 403 상태 코드와 JSON 메시지 반환
-
return res.status(403).json({ message: "권한 없음" });
🧠 한 줄 요약
이 코드는 “현재 요청한 사용자의 역할 배열(roles)에 ‘admin’이 포함되어 있는지 확인하고,
없으면 HTTP 403 응답을 JSON 형태로 돌려주는 권한 검사 로직”이에요.
Q. 요약
🌐 상황부터 먼저
지금 이 코드는 **“이 사용자가 관리자(admin)인지 확인하는 문”**이에요.
관리자만 접근할 수 있는 페이지나 API(예: /admin/dashboard) 같은 데서 쓰는 거죠.
🧩 코드 한 줄씩 말로 풀면
- req는 요청(request)을 담고 있는 객체예요.
→ 클라이언트가 서버로 보낸 내용(주소, 바디, 헤더 등)이 들어있어요. - req.user는 **“로그인한 사용자 정보”**를 담은 객체예요.
→ 예: { id: 1, name: "홍길동", roles: ["user"] }
→ 로그인할 때 JWT나 세션 인증 미들웨어가 req.user를 만들어 넣어요. - req.user.roles는 **그 사용자의 역할 목록(배열)**이에요.
→ 예: ["user", "admin"] 처럼 여러 개 들어있을 수도 있어요. - .includes('admin')은 roles 배열 안에 "admin"이라는 값이 들어있는지 확인하는 함수예요.
→ ["user", "admin"].includes("admin") → true
→ ["user"].includes("admin") → false - !는 “아니다”를 의미하는 부정 연산자예요.
→ “admin이 roles에 없다면”이 되는 거예요.
- res는 응답(response) 객체예요.
→ 서버가 클라이언트에게 “응답”을 보낼 때 쓰는 도구예요. - res.status(403)은 **응답 상태 코드 403 (Forbidden)**을 지정하는 거예요.
→ “너 로그인은 했지만, 이건 접근하면 안 돼.” 라는 뜻이에요. - .json({ message: "권한 없음" })은 응답 본문을 JSON으로 보내는 것이에요.
→ { message: "권한 없음" }은 JS 객체인데,
Express가 자동으로 JSON 문자열로 바꿔서 보냄.
→ 실제 클라이언트가 받는 건 {"message":"권한 없음"} 이거예요. - return은 더 이상 아래 코드 실행하지 말고 응답 보내고 끝내라는 뜻이에요.
📦 요약해서 한 문장으로
로그인한 사용자의 역할 목록에 "admin"이 없으면,
서버는 403 상태 코드와 "권한 없음" 메시지를 JSON 형태로 응답한다.
🔁 비유로 쉽게
- req.user는 “이 요청을 보낸 사람이 누구인지”를 담은 신분증이에요.
- roles는 그 사람이 가진 “직급 목록”이에요. (예: 일반회원, 관리자 등)
- includes('admin')은 “이 사람 직급 중에 관리자 있냐?” 물어보는 거예요.
- 없으면 → “넌 관리자 아니니까 못 들어와” 하고 403 돌려보내는 거예요.
3️⃣ 백엔드 설계 시 고려 사항
- 데이터 구조 설계
- User 테이블: id, email, password, role, status 등
- Token 관리(세션/refresh token) 필요 시 별도 테이블
- API 설계
- 인증 필요 API / 공개 API 구분
- 권한별 접근 가능 여부 명세
- 미들웨어/Interceptor 활용
- 요청 전 JWT 검증, Role 검증
- 코드 중복 최소화, 안전하게 통제
- 보안 추가
- 비밀번호는 반드시 해시화(Bcrypt 등)
- HTTPS 적용, 토큰 유효기간 관리, CSRF/XSS 방어
4️⃣ 정리
| 단계 | 역할 | |
| 인증(Authentication) | “누구인지” 확인 | 로그인/토큰 |
| 권한 관리(Authorization) | “무엇을 할 수 있는지” 검증 | Role/Permission |
| 데이터 구조 설계 | User 테이블 | Role, Token 등 포함 |
| 구현 포인트 | 미들웨어, JWT, 세션, API 접근 제어, 비밀번호 암호화 |
'프로그래밍' 카테고리의 다른 글
| AI 콘텐츠 블로그 탐지 (0) | 2025.10.31 |
|---|---|
| 서버 오픈 시간 늦는 이유 (0) | 2025.10.23 |
| 구글 스프레드시트 스크립트 :: Google Apps Sciprt(GAS) (0) | 2025.10.23 |
| 인증, 권한 관리 (0) | 2025.10.10 |
| DB 설계 :: DBSM :: SQL -> Query :: CRUD (0) | 2025.10.10 |
| 백엔드 API 명세 설계 예시 (0) | 2025.10.09 |
| 백엔드 API 명세 설계 예시 (0) | 2025.10.09 |
| fetch API 의 응답 분석 :: response, data 의 정체는? (0) | 2025.10.08 |