세션, JWT, SSO, OAuth 2.0: 장단점 및 사용 사례 비교 분석
안녕하세요! 웹 서비스를 개발하다 보면 '사용자 인증', 즉 사용자가 정말 본인이 맞는지 확인하는 과정은 빼놓을 수 없는 중요한 부분인데요.
프론트엔드(Frontend) 프로젝트에서 사용자를 인증하는 방법은 크게 네 가지 정도로 나누어 볼 수 있습니다: 바로 세션(Session), JWT(JSON Web Token), SSO(Single Sign-On), 그리고 OAuth 2.0입니다.
이 네 가지 방식들은 각각 어떤 특징을 가지고 있고, 어떤 장점과 단점을 가지고 있을까요?
오늘은 이 네 가지 인증 방식을 속 시원하게 비교 분석해보는 시간을 가져보겠습니다!
1. 전통적인 세션(Session) 기반 인증 방식
세션 기반 인증이란 무엇일까요?
세션 기반 인증은 프론트엔드(Frontend)와 백엔드(Backend) 시스템에서 가장 흔하게 사용되어 온 전통적인 사용자 인증 방식 중 하나입니다.
핵심은 서버가 사용자의 로그인 상태(세션)를 직접 만들고 관리하는 데 있습니다.
세션은 어떻게 동작할까요?
세션 인증 과정은 다음 단계들로 이루어집니다.
1단계: 사용자 로그인 및 서버 검증
사용자가 로그인 페이지에서 아이디와 비밀번호 같은 인증 정보(credentials)를 입력합니다.
이 정보는 프론트엔드(Frontend)에서 백엔드(Backend) 서버로 전송되어 유효성을 검증받습니다.
2단계: 서버의 세션 생성
서버는 사용자의 인증 정보가 유효하다고 판단되면, 해당 사용자를 위한 '세션(session)'을 생성합니다.
이때 고유한 '세션 ID(session ID)'를 만들어 서버 측에 저장합니다. (예: 메모리, 데이터베이스, 캐시 서버 등)
3단계: 세션 ID 쿠키 반환
서버는 생성된 세션 ID(session ID)를 프론트엔드(Frontend)로 다시 보내줍니다.
보통 HTTP 쿠키(Cookie)를 통해 전달됩니다.
4단계: 브라우저의 쿠키 저장 및 자동 전송
사용자의 웹 브라우저(browser)는 서버로부터 받은 세션 ID(session ID)가 담긴 쿠키(Cookie)를 저장합니다.
그리고 이후 해당 서버로 요청을 보낼 때마다 이 쿠키를 자동으로 함께 전송합니다.
5단계: 서버의 세션 검증
서버는 요청에 담겨 온 쿠키(Cookie)에서 세션 ID(session ID)를 확인하고, 서버에 저장된 세션 정보와 비교하여 사용자가 누구인지 식별하고 인증 상태를 확인합니다.
필요한 경우 세션 데이터를 활용해 권한 검사 등도 수행할 수 있습니다.
6단계: 세션 만료 및 관리
서버는 세션에 유효 기간을 설정할 수 있고, 주기적으로 만료된 세션을 정리합니다.
사용자가 로그아웃하거나 세션 유효 시간이 지나면 서버는 해당 세션을 삭제하거나 무효화시킵니다.
이 과정을 보면 알 수 있듯이, 세션 기반 인증에서는 프론트엔드(Frontend)가 특별히 무언가를 적극적으로 할 필요는 없습니다.
핵심적인 작업은 대부분 브라우저(browser)와 서버 사이에서 쿠키(Cookie)를 통해 이루어집니다.
장점과 단점
장점
구현의 단순성: 서버 측에서 세션과 사용자 인증 상태를 관리하는 것이 개발자에게 비교적 직관적이고 간단합니다.
높은 호환성: 대부분의 웹 브라우저(browser)는 쿠키(Cookie)를 잘 지원하기 때문에, 자동으로 쿠키를 주고받는 데 문제가 없습니다.
단점
확장성 문제: 사용자가 많아져 서버를 여러 대로 늘리는 분산 환경(distributed systems)에서는, 여러 서버가 동일한 세션 저장소(storage)를 공유해야 하는 문제가 발생하여 시스템 구조가 복잡해질 수 있습니다.
보안 의존성 (HTTPS 필수): 만약 쿠키(Cookie)가 중간에 탈취당하면, 공격자가 사용자의 세션을 가로채서 악용할 수 있습니다(세션 하이재킹).
따라서 데이터 전송 과정을 암호화하는 HTTPS 사용이 필수적이며, 추가적으로 쿠키(Cookie)에 HttpOnly
나 Secure
같은 속성을 설정하는 보안 조치가 필요합니다.
예제 코드 (Node.js Express)
익스프레스(Express) 프레임워크를 사용하여 세션 인증을 구현하는 간단한 예제입니다.
const express = require('express');
const session = require('express-session'); // express-session 미들웨어 사용
const app = express();
// express-session 미들웨어 설정 및 사용
app.use(
session({
secret: 'your-secret-key', // 세션 ID 쿠키를 서명하는데 사용되는 비밀 키 (보안상 중요!)
resave: false, // 세션이 변경되지 않아도 항상 다시 저장할지 여부 (보통 false)
saveUninitialized: true, // 초기화되지 않은 세션을 저장소에 저장할지 여부 (보통 true)
cookie: {
secure: true, // HTTPS를 통해서만 쿠키를 전송할지 여부 (배포 시 true 권장)
maxAge: 24 * 60 * 60 * 1000, // 쿠키 만료 시간 (예: 24시간)
},
})
);
// 로그인 라우트 핸들러
app.post('/login', (req, res) => {
// 사용자 인증 로직 (실제로는 DB 조회 등으로 검증)
const user = { id: 123 }; // 예시 사용자 ID
req.session.userId = user.id; // 세션에 사용자 ID 저장
res.send('로그인 성공');
});
// 보호된 페이지 접근 라우트 핸들러
app.get('/dashboard', (req, res) => {
if (req.session.userId) {
// 세션에 userId가 있다면 로그인된 사용자
res.send('대시보드 내용을 보여줍니다...');
} else {
// 세션에 userId가 없다면 로그인되지 않은 사용자
res.send('로그인이 필요합니다...');
}
});
app.listen(3000, () => {
console.log('서버가 3000번 포트에서 실행 중입니다...');
});
2. JWT (JSON 웹 토큰) 인증 방식
JWT 인증이란 무엇일까요?
JWT 인증은 현재 가장 널리 사용되는 인증 방식 중 하나입니다.
서버는 사용자의 신원을 나타내는 '토큰(token)'을 발급하여 클라이언트(client)에게 전달합니다.
클라이언트(client)는 이후 서버에 요청을 보낼 때마다 이 토큰을 요청 헤더(header)에 포함시켜 보내고, 서버는 이 토큰을 검증하여 사용자를 인증합니다.
HTTP 요청 자체가 상태를 저장하지 않기 때문에(stateless), 이 방식을 '상태 비저장(stateless) 인증'이라고도 부릅니다.
JWT는 어떻게 동작할까요?
JWT 인증 과정은 다음과 같습니다.
1단계: 사용자 로그인 및 서버 검증
사용자가 로그인 페이지에서 인증 정보(credentials)를 입력하고, 이 정보는 백엔드(Backend) 서버로 전송되어 검증됩니다.
2단계: 서버의 JWT 생성
서버는 사용자 인증 정보가 유효하면 JWT를 생성합니다. 이 토큰 안에는 보통 사용자의 기본 정보(예: 사용자 ID)와 메타데이터(예: 만료 시간) 등이 포함됩니다.
토큰은 서버의 비밀 키로 서명되어 위변조를 방지합니다.
3단계: JWT 반환
서버는 생성된 JWT를 프론트엔드(Frontend)로 다시 보내줍니다.
보통 응답 본문의 JSON 객체 안에 포함되어 전달됩니다.
4단계: 클라이언트의 JWT 저장
프론트엔드(Frontend)는 서버로부터 받은 JWT를 클라이언트(client) 측에 저장합니다.
주로 웹 브라우저(browser)의 로컬 스토리지(localStorage)
에 저장하는 경우가 많습니다.
(쿠키(Cookie)에 저장할 수도 있지만, XSS(Cross-Site Scripting)나 CSRF(Cross-Site Request Forgery) 같은 보안 위험에 노출될 수 있어 주의가 필요합니다.)
5단계: 요청 시 JWT 사용
프론트엔드(Frontend)는 서버 API를 호출할 때마다 저장해 둔 JWT를 HTTP 요청 헤더(header)의 Authorization
필드(field)에 Bearer <token>
형식으로 포함시켜 전송합니다.
6단계: 서버의 JWT 검증
서버는 요청 헤더(header)에서 JWT를 추출하여 유효성을 검증합니다.
(예: 서명이 올바른지, 만료 시간이 지나지 않았는지 확인) 토큰이 유효하다면 서버는 요청을 처리하고 해당 자원이나 데이터를 반환합니다.
7단계: 요청 응답
서버는 요청을 처리하고 결과를 응답으로 반환하며, 프론트엔드(Frontend)는 이 응답을 받아 필요한 작업을 수행합니다.
장점과 단점
장점
상태 비저장(Stateless): JWT 자체에 필요한 정보가 담겨 있으므로, 서버는 별도의 세션 정보를 저장하고 관리할 필요가 없습니다.
이는 서버의 확장성(scalability)을 높이고 로드 밸런싱(load balancing)을 단순화하는 데 도움이 됩니다.
다양한 도메인 환경 지원: 토큰 기반이므로 API 서버와 프론트엔드(Frontend) 서버의 도메인(domain)이 다른 경우(Cross-Origin)에도 인증 처리가 용이합니다.
단점
보안 고려사항: JWT의 보안은 비밀 키 관리와 토큰 만료 시간 설정에 크게 의존합니다.
만약 JWT가 탈취당하면 만료 시간 전까지는 악용될 수 있으므로, 적절한 만료 시간 설정과 필요시 토큰 무효화(revocation) 메커니즘(mechanism) 구현이 중요합니다. HTTPS 사용은 기본입니다.
토큰 크기: 토큰에 담는 정보가 많아지면 토큰의 크기가 커져서 매 요청마다 네트워크 오버헤드(overhead)가 발생할 수 있습니다.
예제 코드 (Node.js Express)
익스프레스(Express)와 jsonwebtoken
라이브러리를 사용한 JWT 인증 예제입니다.
const express = require('express');
const jwt = require('jsonwebtoken'); // jsonwebtoken 라이브러리 사용
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
const secretKey = 'your-very-secret-key'; // JWT 서명 및 검증에 사용할 비밀 키 (절대 노출 금지!)
// 로그인을 통해 JWT를 생성하는 라우트
app.post('/login', (req, res) => {
const { username, password } = req.body;
// 사용자 인증 로직 (실제로는 DB 검증)
// 여기서는 사용자가 유효하다고 가정
const user = { id: 1, username: 'testuser' }; // 예시 사용자 데이터
// JWT 생성 (페이로드, 비밀키, 옵션(만료시간 등))
const token = jwt.sign(user, secretKey, { expiresIn: '24h' }); // 24시간 유효한 토큰 생성
res.json({ token }); // 생성된 토큰을 JSON 형태로 반환
});
// 토큰 검증이 필요한 보호된 라우트
app.get('/dashboard', (req, res) => {
// 요청 헤더에서 토큰 추출 (Authorization: Bearer <token>)
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // 'Bearer ' 부분을 제외하고 토큰만 추출
if (!token) {
return res.status(401).send('접근 거부: 토큰이 제공되지 않았습니다.');
}
// 토큰 검증 (토큰, 비밀키, 콜백함수)
jwt.verify(token, secretKey, (err, decodedUser) => {
if (err) {
// 토큰이 유효하지 않은 경우 (만료, 서명 오류 등)
return res.status(401).send('접근 거부: 유효하지 않은 토큰입니다.');
}
// 토큰이 유효하면 decodedUser에 페이로드(사용자 정보)가 담겨 있음
console.log('인증된 사용자:', decodedUser);
res.send('대시보드 내용을 보여줍니다.');
});
});
app.listen(3000, () => {
console.log('서버가 3000번 포트에서 실행 중입니다...');
});
3. SSO (Single Sign-On) 통합 인증 방식
SSO 인증이란 무엇일까요?
SSO 인증은 주로 여러 개의 관련 서비스나 애플리케이션(application)을 묶어서 제공하는 "스위트(suite)" 형태의 환경에서 많이 사용됩니다.
사용자는 단 한 번의 로그인으로 여러 개의 서로 다른 애플리케이션(application)이나 서비스에 접근 권한을 얻게 됩니다. 즉, 여러 번 로그인할 필요가 없어지는 편리한 방식입니다.
예를 들어, 구글(Google) 계정 하나로 지메일(Gmail), 구글 드라이브(Google Drive), 유튜브(YouTube) 등에 모두 로그인되는 것이 SSO의 대표적인 예입니다.
SSO는 어떻게 동작할까요?
SSO 동작 과정은 다음과 같습니다.
1단계: 사용자의 애플리케이션 접근 시도 (SP)
사용자가 인증이 필요한 특정 애플리케이션(이를 서비스 제공자(SP, Service Provider)라고 부릅니다)에 접근하려고 합니다.
2단계: 인증 서버(IdP)로 이동
사용자가 아직 로그인 상태가 아니므로, 애플리케이션(SP)은 사용자를 중앙 로그인 시스템, 즉 ID 제공자(IdP, Identity Provider) 또는 로그인 센터(Login Center)라고 불리는 곳으로 보냅니다(리디렉션).
이 IdP가 실제 사용자 인증을 담당합니다.
3단계: IdP에서 사용자 로그인
사용자는 IdP 페이지에서 자신의 인증 정보(credentials)를 입력하여 로그인합니다.
(만약 이미 해당 IdP 시스템에 로그인되어 있는 상태라면, 이 단계를 건너뛸 수도 있습니다.)
4단계: SSO 토큰 생성 및 SP로 전달
IdP는 사용자 인증이 성공하면, 해당 사용자를 위한 SSO 토큰(token) (예: SAML 어설션(assertion) 또는 OAuth 토큰(token))을 생성합니다.
그리고 사용자를 원래 접근하려던 애플리케이션(SP)으로 다시 돌려보내면서(리디렉션) 이 토큰을 함께 전달합니다.
5단계: SP의 토큰 검증 요청 및 IdP의 확인
애플리케이션(SP)은 전달받은 SSO 토큰(token)을 IdP에게 보내 유효성을 확인해달라고 요청합니다.
IdP는 토큰을 검증하고 해당 사용자의 신원 정보를 SP에게 알려줍니다.
6단계: SP의 사용자 접근 허용
애플리케이션(SP)은 IdP로부터 받은 사용자 신원 정보를 바탕으로 인증을 완료하고, 사용자에게 서비스 접근을 허용합니다.
7단계: 다른 애플리케이션 접근 시 자동 인증
이제 사용자가 동일한 IdP를 사용하는 다른 애플리케이션(application)에 접근하려고 하면, 해당 애플리케이션(application) 역시 사용자를 IdP로 보냅니다.
하지만 사용자는 이미 IdP에 로그인된 상태이므로, IdP는 별도의 로그인 과정 없이 자동으로 사용자를 인증하고 다시 해당 애플리케이션(application)으로 돌려보내 줍니다.
사용자는 마치 자동으로 로그인되는 것처럼 느끼게 됩니다.
장점과 단점
장점
사용자 경험 향상: 사용자는 여러 서비스에 접근하기 위해 단 한 번만 로그인하면 되므로, 반복적인 로그인 과정을 거치지 않아 편리합니다.
중앙 집중 관리: 관리자는 사용자 계정과 접근 권한을 IdP에서 중앙 집중적으로 관리할 수 있어 효율성과 보안성을 높일 수 있습니다.
보안 강화: 사용자가 기억해야 할 비밀번호가 하나로 줄어들어 비밀번호 유출 위험을 낮출 수 있습니다. 또한 IdP에 MFA(Multi-Factor Authentication, 다중 인증) 같은 강력한 인증 메커니즘(mechanism)을 적용하기 용이합니다.
단점
단일 실패 지점(Single Point of Failure): 만약 중앙 로그인 시스템인 IdP에 문제가 발생하면, 해당 IdP에 의존하는 모든 애플리케이션(application)의 로그인이 불가능해지는 심각한 문제가 발생할 수 있습니다.
구현의 복잡성: SSO 솔루션(solution)을 구축하고 유지 관리하는 것은 상당히 복잡할 수 있습니다. 시스템 간의 연동 설정, 보안 구성 등을 철저히 관리해야 합니다.
주요 SSO 구현 기술
SAML (Security Assertion Markup Language)
XML 기반의 표준으로, IdP와 SP 간에 인증 및 인가 데이터를 교환하는 데 사용됩니다. 주로 기업 환경에서 많이 쓰입니다.
OAuth 2.0 & OpenID Connect
OAuth 2.0은 원래 인가(Authorization)를 위한 프레임워크(framework)이지만, 그 위에 구축된 OpenID Connect는 사용자 인증(Authentication) 계층을 추가하여 SSO 구현에 널리 사용됩니다. 웹 및 모바일 환경에서 자주 볼 수 있습니다.
CAS (Central Authentication Service)
웹 애플리케이션(application)을 위한 오픈 소스 SSO 솔루션(solution) 중 하나입니다.
4. OAuth 2.0 인증 방식
OAuth 2.0 인증이란 무엇일까요?
OAuth 2.0은 제3자 애플리케이션(third-party application)이 사용자 리소스(resource)에 제한된 접근 권한을 얻도록 허용하는 표준 프로토콜(protocol)입니다.
쉽게 말해, 사용자가 자신의 비밀번호를 직접 알려주지 않고도 다른 앱이 내 계정의 특정 정보나 기능(예: 페이스북(Facebook) 친구 목록 가져오기, 구글 캘린더(Google Calendar)에 일정 추가하기 등)에 접근할 수 있도록 '위임'하는 방식입니다.
흔히 보는 '페이스북(Facebook)으로 로그인', '카카오(Kakao)로 로그인' 같은 기능들이 OAuth 2.0을 기반으로 동작하는 경우가 많습니다.
중요한 점은 OAuth 2.0은 본질적으로 인가(Authorization, 권한 부여)를 위한 프로토콜(protocol)이지, 인증(Authentication, 신원 확인)을 위한 프로토콜(protocol)은 아니라는 것입니다.
하지만 실제로는 사용자 인증 과정과 결합되어 로그인 기능을 구현하는 데 널리 사용됩니다. (이때 OpenID Connect가 함께 사용되는 경우가 많습니다.)
OAuth 2.0은 어떻게 동작할까요?
OAuth 2.0은 역할과 흐름이 다소 복잡하므로, 먼저 주요 용어부터 이해하는 것이 중요합니다.
주요 용어 이해하기
OAuth 2.0을 이해하기 위해 다음 용어들을 알아두어야 합니다.
리소스 소유자 (Resource Owner)
보호된 리소스(resource)의 소유자, 일반적으로 최종 사용자(user)입니다. (예: 페이스북 사용자 본인)
리소스 서버 (Resource Server)
보호된 리소스(resource)를 가지고 있는 서버. 접근 제어를 담당합니다. (예: 페이스북(Facebook)의 사용자 정보 API 서버)
클라이언트 (Client)
리소스 소유자(Resource Owner)를 대신하여 보호된 리소스(resource)에 접근하고자 하는 애플리케이션(application)입니다. (예: '페이스북(Facebook)으로 로그인' 기능을 사용하는 쇼핑몰 웹사이트)
인가 서버 (Authorization Server)
리소스 소유자(Resource Owner)를 인증하고, 클라이언트(Client)에게 접근 권한(인가)을 부여하는 서버입니다.
최종적으로 접근 토큰(Access Token)을 발급하는 역할을 합니다. (예: 페이스북(Facebook)의 인증/인가 담당 서버)
기본 흐름 (인가 코드 승인 방식 기준)
가장 널리 사용되는 인가 코드 승인 방식의 흐름은 다음과 같습니다.
1단계: 사용자의 권한 부여 요청 (클라이언트 -> 인가 서버)
사용자가 클라이언트(Client) 애플리케이션(application)(예: 쇼핑몰)에서 '페이스북(Facebook)으로 로그인' 버튼을 클릭합니다.
클라이언트(Client)는 사용자를 인가 서버(Authorization Server)(예: 페이스북(Facebook) 인증 서버)로 보냅니다(리디렉션).
이때 클라이언트(Client)는 어떤 권한(scope)을 요청하는지 함께 전달합니다.
2단계: 사용자 동의 및 인가 코드 발급 (인가 서버 -> 클라이언트)
인가 서버(Authorization Server)는 사용자에게 로그인을 요구하고, 클라이언트(Client)가 요청한 권한(예: '기본 프로필 정보 접근')에 대해 동의할 것인지 묻습니다.
사용자가 동의하면, 인가 서버(Authorization Server)는 임시 코드인 인가 코드(Authorization Code)를 생성하여, 미리 등록된 클라이언트(Client)의 리디렉션 URI(Redirect URI)로 사용자를 돌려보내면서 이 코드를 전달합니다.
3단계: 접근 토큰 요청 (클라이언트 -> 인가 서버)
클라이언트(Client)는 백엔드(Backend)에서 방금 받은 인가 코드(Authorization Code)와 자신의 클라이언트 ID(Client ID), 클라이언트 시크릿(Client Secret)을 함께 인가 서버(Authorization Server)의 토큰(token) 발급 엔드포인트(endpoint)로 보냅니다.
4단계: 접근 토큰 발급 (인가 서버 -> 클라이언트)
인가 서버(Authorization Server)는 전달받은 정보들을 검증하고, 유효하다면 접근 토큰(Access Token) (그리고 경우에 따라 리프레시 토큰(Refresh Token))을 클라이언트(Client)에게 발급해줍니다.
5단계: 리소스 접근 (클라이언트 -> 리소스 서버)
클라이언트(Client)는 발급받은 접근 토큰(Access Token)을 사용하여 리소스 서버(Resource Server)(예: 페이스북(Facebook) API 서버)에 보호된 리소스(resource)(예: 사용자 프로필 정보)를 요청합니다.
요청 헤더(header)에 Authorization: Bearer <access_token>
형태로 토큰을 포함시켜 보냅니다.
6단계: 리소스 반환 (리소스 서버 -> 클라이언트)
리소스 서버(Resource Server)는 접근 토큰(Access Token)을 검증하고, 유효하다면 요청받은 리소스(resource)를 클라이언트(Client)에게 반환합니다.
클라이언트(Client)는 이 정보를 사용하여 사용자 로그인을 완료하거나 다른 작업을 수행합니다.
주요 OAuth 2.0 승인 방식 (Grant Types)
OAuth 2.0에는 클라이언트(Client)의 유형이나 상황에 따라 다른 '승인 흐름(Grant Flow)'을 제공합니다.
인가 코드 승인 방식 (Authorization Code Grant)
가장 일반적이고 안전한 방식으로, 웹 애플리케이션(application)에서 주로 사용됩니다. 위에서 설명한 흐름입니다.
암시적 승인 방식 (Implicit Grant)
과거에 자바스크립트(JavaScript) 기반의 SPA(Single-Page Application) 등 클라이언트 시크릿(Client Secret)을 안전하게 저장하기 어려운 환경을 위해 설계되었으나, 보안상의 이유로 현재는 권장되지 않습니다. (대신 PKCE를 사용한 인가 코드 승인 방식 사용 권장)
리소스 소유자 암호 자격증명 승인 방식 (Resource Owner Password Credentials Grant)
사용자가 자신의 아이디/비밀번호를 클라이언트(Client)에게 직접 제공하는 방식입니다. 보안 위험이 높아 클라이언트(Client)가 매우 신뢰할 수 있는 경우(예: 서비스 제공자가 직접 만든 앱)에만 제한적으로 사용해야 하며, 가급적 사용하지 않는 것이 좋습니다.
클라이언트 자격증명 승인 방식 (Client Credentials Grant)
사용자의 개입 없이, 클라이언트(Client) 애플리케이션(application) 자체가 리소스(resource)에 접근할 때 사용됩니다. (예: 서버 간 API 통신)
장점과 단점
장점
유연성: 다양한 클라이언트(Client) 유형과 시나리오에 맞춰 여러 가지 승인 흐름(grant flow)을 지원합니다.
보안 강화: 사용자의 아이디/비밀번호를 직접 공유하는 대신, 제한된 권한을 가진 토큰(token)을 사용하여 리소스(resource)에 접근하므로 보안성이 향상됩니다. 인가와 인증을 분리할 수 있습니다.
단점
구현의 복잡성: OAuth 2.0 프로토콜(protocol) 자체와 다양한 흐름을 이해하고 올바르게 구현하는 것이 다소 복잡할 수 있습니다. 토큰 관리, 보안 설정 등에 신경 써야 할 부분이 많습니다.
보안 위험: 접근 토큰(Access Token)이 유출되면 보안 사고로 이어질 수 있습니다. 따라서 HTTPS 사용은 기본이며, 토큰(token)의 유효 기간을 적절히 설정하고 안전하게 관리하는 전략이 필수적입니다.
예제 코드 (Node.js Express - 인가 코드 흐름)
익스프레스(Express)를 사용하여 OAuth 2.0의 인가 코드(Authorization Code) 흐름을 구현하는 간략한 예제입니다.
(실제로는 passport.js
같은 라이브러리를 사용하는 것이 일반적입니다.)
const express = require('express');
const axios = require('axios'); // HTTP 요청을 위한 라이브러리
const app = express();
// OAuth 2.0 클라이언트 설정 정보 (실제 값으로 대체해야 함)
const clientId = 'YOUR_CLIENT_ID';
const clientSecret = 'YOUR_CLIENT_SECRET';
const redirectUri = 'http://localhost:3000/callback'; // 인가 서버에 등록된 리디렉션 URI
const authorizationServerUrl = 'https://authorization-server.com'; // 실제 인가 서버 주소
const tokenEndpoint = `${authorizationServerUrl}/token`; // 토큰 발급 엔드포인트
const authorizationEndpoint = `${authorizationServerUrl}/authorize`; // 인가 요청 엔드포인트
const resourceServerUrl = 'https://resource-server.com'; // 실제 리소스 서버 주소
// 1. 사용자를 인가 서버로 보내는 로그인 라우트
app.get('/login', (req, res) => {
// 필요한 권한(scope) 등과 함께 인가 요청 URL 생성
const params = new URLSearchParams({
response_type: 'code', // 인가 코드를 받겠다는 의미
client_id: clientId,
redirect_uri: redirectUri,
scope: 'read_profile email', // 요청할 권한 범위
// state: '랜덤값' // CSRF 공격 방지를 위해 사용 권장
});
const authUrl = `${authorizationEndpoint}?${params.toString()}`;
res.redirect(authUrl); // 사용자를 인가 서버로 리디렉션
});
// 2. 인가 서버에서 사용자가 돌아올 콜백(callback) 라우트
app.get('/callback', async (req, res) => {
const { code } = req.query; // URL 쿼리 파라미터에서 인가 코드 추출
if (!code) {
return res.status(400).send('에러: 인가 코드가 없습니다.');
}
try {
// 3. 받은 인가 코드를 사용하여 접근 토큰 요청
const tokenResponse = await axios.post(tokenEndpoint, new URLSearchParams({
grant_type: 'authorization_code', // 인가 코드를 사용한다는 의미
code: code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret,
}), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
}
});
const { access_token } = tokenResponse.data;
// 4. 발급받은 접근 토큰을 사용하여 리소스 서버에 사용자 정보 요청
const userInfoResponse = await axios.get(`${resourceServerUrl}/userinfo`, {
headers: {
Authorization: `Bearer ${access_token}`, // Bearer 스킴 사용
},
});
// 최종적으로 얻은 사용자 정보 반환 (또는 로그인 처리)
res.json(userInfoResponse.data);
} catch (error) {
console.error('OAuth 처리 중 에러 발생:', error.response?.data || error.message);
res.status(500).send('인증 처리 중 오류가 발생했습니다.');
}
});
app.listen(3000, () => {
console.log('서버가 3000번 포트에서 실행 중입니다...');
});
마무리하며
오늘 살펴본 네 가지 사용자 인증 방식은 각각의 장단점과 적합한 사용 사례를 가지고 있습니다.
세션(Session) 방식은 비교적 간단한 서버 렌더링(server-rendered) 웹 애플리케이션(application)에 적합합니다.
JWT는 상태 비저장(stateless) 아키텍처(architecture), 모바일 앱, SPA(Single-Page Application) 등에 유리한 선택이 될 수 있습니다.
SSO는 여러 관련 서비스를 운영하는 기업 환경이나 포털 사이트 등에서 사용자 편의성과 관리 효율성을 높이는 데 효과적입니다.
마지막으로 OAuth 2.0은 제3자 애플리케이션(application) 연동, 외부 서비스 API 접근 권한 관리 등에 필수적인 표준 방식이라고 할 수 있습니다.
어떤 인증 방식을 선택할지는 개발하려는 서비스의 특성, 규모, 보안 요구사항, 개발 편의성 등을 종합적으로 고려하여 결정하는 것이 중요합니다.
오늘 내용이 여러분의 서비스에 가장 적합한 인증 방식을 선택하는 데 도움이 되었기를 바랍니다!
'Javascript' 카테고리의 다른 글
사이트마다 캐시가 다른 이유? 이중 키 캐싱(Double-keyed Caching) 완벽 이해! (0) | 2025.05.06 |
---|---|
리액트 서버 컴포넌트(RSC) 논쟁: 혁신인가 퇴보인가? 커뮤니티 시각 분석 (0) | 2025.05.06 |
RESTful API 완벽 이해: 원칙부터 디자인, 베스트 프랙티스까지 (0) | 2025.05.05 |
프리플라이트 요청(Preflight Request)이란 무엇일까요? (CORS 심층 분석) (0) | 2025.05.05 |
플레이라이트(Playwright) vs 퍼펫티어(Puppeteer): 지금 갈아타야 할까요? (마이그레이션 가이드) (0) | 2025.05.05 |