세션, JWT, SSO, OAuth 2.0: 장점, 단점 및 사용Use Cases
James Reed
Infrastructure Engineer · Leapcell

프론트엔드 프로젝트 개발에서 사용자 인증을 위한 주요 방법은 세션, JWT, SSO 및 OAuth 2.0입니다.
그렇다면 이 네 가지 방법의 장단점은 무엇일까요? 오늘, 이들을 비교해 봅시다!
클래식 세션 기반 인증
세션 기반 인증이란 무엇인가요?
세션 기반 인증은 프론트엔드 및 백엔드 시스템에서 일반적으로 사용되는 사용자 인증 방법입니다.
주로 서버가 사용자 세션을 생성하고 관리하는 데 의존합니다.
세션 작동 방식
세션 인증 프로세스는 6단계로 구성됩니다.
- 사용자 로그인: 사용자는 로그인 페이지에 자신의 자격 증명(예: 사용자 이름 및 비밀번호)을 입력합니다. 이러한 자격 증명은 유효성 검사를 위해 프론트엔드에서 백엔드 서버로 전송됩니다.
- 세션 생성: 자격 증명을 검증한 후 백엔드 서버는 세션을 생성합니다. 여기에는 일반적으로 고유한 세션 ID가 포함되며, 서버에 저장됩니다.
- 세션 ID 반환: 서버는 세션 ID를 프론트엔드로 다시 전송합니다. 일반적으로 쿠키를 통해 전송됩니다. 이 쿠키는 사용자 브라우저에 저장되며 후속 요청과 함께 자동으로 전송됩니다.
- 세션 ID 저장: 브라우저는 쿠키를 저장하고 서버로 전송되는 모든 요청에 자동으로 포함합니다. 이를 통해 서버는 사용자 세션을 인식하고 인증할 수 있습니다.
- 세션 유효성 검사: 서버는 세션 ID를 조회하고 연결된 세션 정보를 확인하여 사용자의 신원을 확인합니다. 또한 세션 데이터를 사용하여 권한 검사 및 접근 제어를 수행할 수 있습니다.
- 세션 만료 및 관리: 서버는 세션 만료 시간을 설정하고 만료된 세션을 주기적으로 삭제할 수 있습니다. 사용자가 로그아웃하거나 세션이 만료되면 서버는 세션을 삭제하거나 무효화합니다.
위의 프로세스에서 알 수 있듯이 세션 기반 인증에서는 프론트엔드가 적극적으로 참여할 필요가 없습니다. 주요 작업은 브라우저와 서버 간에 처리됩니다.
장단점
장점
- 간단하고 사용하기 쉬움: 개발자는 세션 및 사용자 인증을 비교적 간단하게 관리할 수 있습니다.
- 양호한 호환성: 대부분의 브라우저는 쿠키를 지원하므로 자동 전송 및 수신이 가능합니다.
단점
- 낮은 확장성: 분산 시스템에서 여러 서버는 세션 스토리지를 공유해야 할 수 있으므로 복잡성이 증가합니다.
- HTTPS 필요: 쿠키가 도난당하면 세션 하이재킹으로 이어질 수 있습니다. 따라서 HTTPS를 사용하여 데이터 전송을 보호해야 하며, 추가 보안 조치(예:
HttpOnly
및Secure
속성으로 쿠키 설정)를 사용해야 합니다.
예제 코드
Express를 사용하여 세션 인증을 구현하는 예제는 다음과 같습니다.
const express = require('express'); const session = require('express-session'); const app = express(); // express-session 미들웨어 구성 및 사용 app.use( session({ secret: 'your-secret-key', // 세션 ID 쿠키에 서명하는 데 사용되는 키로, 세션 보안 보장 resave: false, // 요청마다 세션을 저장할지 여부(변경되지 않은 경우에도) saveUninitialized: true, // 초기화되지 않은 세션을 저장할지 여부 cookie: { secure: true, // HTTPS를 통해서만 쿠키를 전송할지 여부(HTTPS 지원 필요) maxAge: 24 * 60 * 60 * 1000, // 쿠키 만료 시간(24시간으로 설정) }, }) ); // 로그인 경로 핸들러 app.post('/login', (req, res) => { // 사용자 인증(사용자가 유효하다고 가정) const user = { id: 123 }; // 예제 사용자 ID req.session.userId = user.id; // 세션에 사용자 ID 저장 res.send('로그인 성공'); }); app.get('/dashboard', (req, res) => { if (req.session.userId) { // 세션에 사용자 ID가 포함되어 있으면 사용자가 로그인한 것임 res.send('대시보드 콘텐츠...'); } else { // 세션에서 사용자 ID를 찾을 수 없으면 사용자가 로그인하지 않은 것임 res.send('로그인하세요...'); } }); app.listen(3000, () => { console.log('서버가 포트 3000에서 수신 중...'); });
JWT (JSON 웹 토큰) 인증
JWT 인증이란 무엇인가요?
JWT 인증은 현재 가장 일반적으로 사용되는 인증 방법 중 하나입니다.
서버는 사용자 신원을 나타내는 토큰을 반환합니다. 요청 시 토큰은 사용자 확인을 위해 요청 헤더에 추가됩니다.
HTTP 요청은 상태가 없으므로 이 방법을 상태 비저장 인증이라고도 합니다.
JWT 작동 방식
- 사용자 로그인: 사용자는 로그인 페이지에 자신의 자격 증명(예: 사용자 이름 및 비밀번호)을 입력하고, 이러한 자격 증명은 유효성 검사를 위해 백엔드 서버로 전송됩니다.
- JWT 생성: 사용자 자격 증명을 검증한 후 백엔드 서버는 JWT를 생성합니다. 이 토큰에는 일반적으로 기본 사용자 정보(예: 사용자 ID) 및 메타데이터(예: 만료 시간)가 포함됩니다.
- JWT 반환: 서버는 생성된 JWT를 프론트엔드로 다시 전송합니다. 일반적으로 JSON 응답으로 전송됩니다.
- JWT 저장: 프론트엔드는 JWT를 클라이언트 측에 저장합니다. 일반적으로
localStorage
에 저장됩니다. 드문 경우에 쿠키에 저장될 수 있지만 교차 사이트 스크립팅(XSS) 및 **교차 사이트 요청 위조(CSRF)**와 같은 보안 위험이 있습니다. - 요청에 JWT 사용: API를 호출할 때 프론트엔드는
Authorization
헤더에 JWT 토큰을 첨부하고(Bearer <token>
형식) 서버로 전송합니다. - JWT 유효성 검사: 요청을 받으면 서버는 JWT를 추출하고 유효성(예: 서명 및 만료 시간 확인)을 검사합니다. 유효한 경우 서버는 요청을 처리하고 해당 리소스 또는 데이터를 반환합니다.
- 요청에 응답: 서버는 요청을 처리하고 응답을 반환하며, 프론트엔드는 필요에 따라 이를 사용할 수 있습니다.
장단점
장점
- 상태 비저장: JWT는 자체 포함되어 있기 때문에 서버는 세션 정보를 저장할 필요가 없으므로 확장성 및 로드 밸런싱이 간소화됩니다.
- 교차 도메인 지원: JWT는 교차 출처 요청에 사용할 수 있습니다(예: API와 프론트엔드가 분리된 경우).
단점
- 보안 문제: JWT의 보안은 키 보호 및 토큰 만료 관리에 따라 달라집니다. JWT가 도난당하면 보안 위험이 발생할 수 있습니다.
예제 코드
Express를 사용하여 JWT 인증을 구현하는 예제는 다음과 같습니다.
const express = require('express'); const jwt = require('jsonwebtoken'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); const secretKey = 'your-secret-key'; // JWT 서명 및 확인을 위한 비밀 키 // JWT를 생성하는 로그인 경로 app.post('/login', (req, res) => { const { username, password } = req.body; // 사용자 인증(사용자가 유효하다고 가정) const user = { id: 1, username: 'user' }; // 예제 사용자 데이터 const token = jwt.sign(user, secretKey, { expiresIn: '24h' }); // JWT 생성 res.json({ token }); // JWT 반환 }); // 보호된 경로 app.get('/dashboard', (req, res) => { const token = req.headers['authorization']?.split(' ')[1]; if (!token) { return res.status(401).send('토큰이 제공되지 않았습니다.'); } jwt.verify(token, secretKey, (err, decoded) => { if (err) { return res.status(401).send('잘못된 토큰입니다.'); } res.send('대시보드 콘텐츠'); }); }); app.listen(3000, () => { console.log('서버가 포트 3000에서 수신 중...'); });
SSO (단일 로그온) 인증
SSO 인증이란 무엇인가요?
SSO 인증은 "스위트 기반" 애플리케이션에서 일반적으로 사용됩니다. 중앙 로그인 시스템을 통해 사용자는 한 번 로그인하여 다시 인증할 필요 없이 여러 애플리케이션에 액세스할 수 있습니다.
SSO 작동 방식
- 사용자가 애플리케이션에 액세스: 사용자는 인증이 필요한 애플리케이션(**서비스 제공자(SP)**라고 함)에 액세스하려고 시도합니다.
- ID 공급자(IdP)로 리디렉션: 사용자가 로그인하지 않았으므로 애플리케이션은 사용자를 SSO ID 공급자(IdP)(로그인 센터라고도 함)로 리디렉션합니다. 로그인 센터는 사용자 인증을 처리합니다.
- 사용자 로그인: 사용자는 로그인 센터에 자신의 자격 증명을 입력합니다. 이미 로그인한 경우(예: 회사 내부 SSO 시스템에 로그인한 경우) 이 단계를 건너뛸 수 있습니다.
- SSO 토큰 생성: 인증되면 ID 공급자는 SSO 토큰(예: OAuth 토큰 또는 SAML 어설션)을 생성하고 토큰을 첨부하여 사용자를 원래 애플리케이션으로 다시 리디렉션합니다.
- 토큰 유효성 검사: 애플리케이션(서비스 제공자)은 토큰을 수신하고 유효성 검사를 위해 SSO ID 공급자로 전송합니다. IdP는 토큰을 확인하고 사용자의 신원 정보를 반환합니다.
- 사용자 액세스 권한 획득: 인증에 성공하면 애플리케이션은 사용자의 신원 정보를 기반으로 액세스 권한을 부여합니다. 이제 사용자는 애플리케이션의 보호된 리소스에 액세스할 수 있습니다.
- 다른 애플리케이션 액세스: 사용자가 동일한 로그인 센터를 사용하는 다른 애플리케이션에 액세스하면 해당 센터로 리디렉션됩니다. 이미 로그인했으므로 로그인 센터는 사용자를 자동으로 인증하고 대상 애플리케이션으로 다시 리디렉션하여 원활한 로그인을 가능하게 합니다.
장단점
장점
- 사용자 경험 간소화: 사용자는 여러 애플리케이션에 액세스하기 위해 한 번만 로그인하면 되므로 반복적인 로그인 노력이 줄어듭니다.
- 중앙 집중식 관리: 관리자는 사용자 신원 및 액세스 권한을 중앙에서 관리하여 효율성 및 보안을 개선할 수 있습니다.
- 보안 강화: 사용자가 하나의 비밀번호만 기억하면 되므로 비밀번호 유출 위험이 줄어듭니다. 더 강력한 인증 메커니즘(예: 다단계 인증, MFA)도 적용할 수 있습니다.
단점
- 단일 실패 지점: 로그인 센터(SSO ID 공급자)에 문제가 발생하면 해당 센터에 의존하는 모든 애플리케이션이 영향을 받을 수 있습니다.
- 복잡한 구현: SSO 솔루션을 배포하고 유지 관리하는 것은 복잡할 수 있으며, 적절한 보안 구성과 시스템 간의 상호 운용성이 필요합니다.
일반적인 SSO 구현 기술
SAML(보안 어설션 마크업 언어)
- ID 공급자(IdP)와 서비스 제공자(SP) 간에 인증 및 권한 부여 데이터를 교환하는 데 사용되는 XML 기반 표준입니다.
- 엔터프라이즈 환경에서 일반적으로 사용됩니다.
OAuth 2.0 및 OpenID Connect
- OAuth 2.0은 사용자 리소스에 대한 타사 액세스 권한을 부여하기 위한 권한 부여 프레임워크입니다.
- OpenID Connect는 OAuth 2.0을 기반으로 구축되어 사용자 인증을 위한 ID 계층을 추가합니다.
- 웹 및 모바일 애플리케이션에서 자주 사용됩니다.
CAS(중앙 인증 서비스)
- 웹 애플리케이션을 위한 오픈 소스 SSO 솔루션으로, 사용자는 한 번 인증하고 여러 서비스에 액세스할 수 있습니다.
OAuth 2.0 인증
OAuth 2.0 인증이란 무엇인가요?
OAuth 2.0은 타사 애플리케이션이 사용자 리소스에 액세스할 수 있도록 권한을 부여하는 데 사용되는 표준 프로토콜입니다. 예는 다음과 같습니다.
- Facebook 로그인
- Discord 로그인
- 앱 QR 코드 로그인
OAuth 2.0은 인증보다는 권한 부여를 위해 주로 설계되었지만 사용자 로그인을 활성화하기 위해 인증과 함께 자주 사용됩니다.
OAuth 2.0 작동 방식
OAuth 2.0은 복잡하므로 해당 흐름을 이해하기 전에 몇 가지 주요 개념을 명확히 해야 합니다.
OAuth 2.0의 주요 개념
- 리소스 소유자: 일반적으로 보호된 리소스(예: 개인 데이터, 파일)를 소유한 사용자입니다.
- 리소스 서버: 보호된 리소스를 호스팅하고 권한이 있는 사용자만 액세스할 수 있도록 하는 서버입니다.
- 클라이언트: 보호된 리소스에 액세스하려는 애플리케이션 또는 서비스입니다. 클라이언트는 리소스 소유자의 권한을 획득해야 합니다.
- 권한 부여 서버: 리소스 소유자를 인증하고 클라이언트에 권한을 부여하는 역할을 담당하는 서버입니다. 클라이언트가 리소스 서버에 액세스할 수 있도록 하는 액세스 토큰을 발급합니다.
OAuth 2.0 워크플로
- 사용자 권한 부여: 사용자가 클라이언트 애플리케이션과 상호 작용하면 애플리케이션은 사용자의 리소스에 액세스할 수 있는 권한을 요청합니다. 사용자는 권한 부여 서버로 리디렉션됩니다.
- 권한 부여 코드 획득: 사용자가 동의하면 권한 부여 서버는 권한 부여 코드를 생성하고 클라이언트에 다시 전송합니다(리디렉션 URL을 통해).
- 액세스 토큰 획득: 클라이언트는 권한 부여 코드를 액세스 토큰으로 교환하여 권한 부여 서버에 요청합니다.
- 리소스 액세스: 클라이언트는 액세스 토큰을 사용하여 리소스 서버에서 보호된 리소스를 요청합니다. 리소스 서버는 토큰의 유효성을 검사하고 요청된 데이터를 반환합니다.
일반적인 OAuth 2.0 부여 유형(권한 부여 흐름)
-
권한 부여 코드 흐름(가장 일반적)
- 사용자 상호 작용이 필요한 웹 애플리케이션에 적합합니다.
- 클라이언트는 사용자 동의를 얻은 후 권한 부여 코드를 액세스 토큰으로 교환합니다.
-
암시적 흐름(권장되지 않음)
- 공용 클라이언트(예: 단일 페이지 애플리케이션)용으로 설계되었습니다.
- 사용자는 권한 부여 코드 대신 액세스 토큰을 직접 받습니다.
- 보안 문제로 인해 이 흐름은 더 이상 권장되지 않습니다.
-
리소스 소유자 비밀번호 자격 증명 흐름(제한된 사용)
- 사용자는 자신의 사용자 이름과 비밀번호를 클라이언트에 직접 제공합니다.
- 클라이언트는 이러한 자격 증명을 사용하여 액세스 토큰을 요청합니다.
- 보안 위험으로 인해 공용 애플리케이션에는 권장되지 않습니다.
-
클라이언트 자격 증명 흐름(컴퓨터 간)
- 클라이언트 애플리케이션이 사용자 대신 작동하는 것이 아니라 자체 리소스에 액세스해야 하는 경우에 사용됩니다.
- 서비스 간의 API 액세스에 일반적입니다.
장단점
장점
- 유연성: 여러 권한 부여 흐름을 지원하므로 다양한 클라이언트 유형 및 애플리케이션 시나리오에 적합합니다.
- 보안: 권한 부여와 인증을 분리하여 OAuth 2.0은 보안을 강화합니다. 사용자 이름과 비밀번호를 사용하는 대신 액세스 제어를 위해 토큰에 의존합니다.
단점
- 복잡성: OAuth 2.0을 구현하고 구성하는 것은 어려울 수 있으며 적절한 토큰 관리 및 보안 구성이 필요합니다.
- 보안 위험: 토큰이 유출되면 보안 위험이 발생할 수 있습니다. 따라서 적절한 보안 조치(예: HTTPS 사용 및 보안 토큰 관리 전략)를 마련해야 합니다.
예제 코드
다음은 OAuth 2.0 인증의 Express 구현입니다.
const express = require('express'); const axios = require('axios'); const app = express(); // OAuth 2.0 구성 const clientId = 'your-client-id'; const clientSecret = 'your-client-secret'; const redirectUri = 'http://localhost:3000/callback'; const authorizationServerUrl = 'https://authorization-server.com'; const resourceServerUrl = 'https://resource-server.com'; // 로그인 경로 - 사용자를 권한 부여 서버로 리디렉션합니다. app.get('/login', (req, res) => { const authUrl = `${authorizationServerUrl}/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=read`; res.redirect(authUrl); }); // 콜백 경로 - 권한 부여 코드 교환 처리 app.get('/callback', async (req, res) => { const { code } = req.query; if (!code) { return res.status(400).send('권한 부여 코드가 없습니다.'); } try { // 권한 부여 코드를 액세스 토큰으로 교환합니다. const response = await axios.post(`${authorizationServerUrl}/token`, { grant_type: 'authorization_code', code, redirect_uri: redirectUri, client_id: clientId, client_secret: clientSecret, }); const { access_token } = response.data; // 액세스 토큰을 사용하여 보호된 리소스를 가져옵니다. const resourceResponse = await axios.get(`${resourceServerUrl}/user-info`, { headers: { Authorization: `Bearer ${access_token}` }, }); res.json(resourceResponse.data); } catch (error) { res.status(500).send('토큰 교환 또는 리소스 액세스 중 오류 발생'); } }); app.listen(3000, () => { console.log('서버가 포트 3000에서 수신 중...'); });
결론
이러한 네 가지 인증 방법은 각각 고유한 장점, 단점 및 적합한 사용 사례가 있습니다.
- 세션: 간단한 서버 렌더링 애플리케이션에 적합합니다.
- JWT: 최신 상태 비저장 아키텍처 및 모바일 앱에 적합합니다.
- SSO: 여러 관련 서비스가 있는 엔터프라이즈 환경에 가장 적합합니다.
- OAuth 2.0: 타사 통합 및 API 액세스에 선호되는 선택입니다.
Leapcell은 Node.js 프로젝트 호스팅을 위한 최고의 선택입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하세요.
무제한 프로젝트를 무료로 배포하세요
- 사용량에 대해서만 지불하세요. 요청이 없으면 요금도 없습니다.
타의 추종을 불허하는 비용 효율성
- 사용한 만큼 지불하고 유휴 요금은 없습니다.
- 예: $25로 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
간편한 확장성 및 고성능
- 높은 동시성을 쉽게 처리할 수 있도록 자동 확장합니다.
- 운영 오버헤드가 없으므로 구축에만 집중하세요.
설명서에서 자세히 알아보세요!
X에서 저희를 팔로우하세요: @LeapcellHQ