인증과 보안 (Authentication & Security)
사용자가 누구인지 확인하고(인증), 허가된 사람만 데이터에 접근할 수 있도록 보호하는(보안) 시스템입니다.
같은 말:인증AuthenticationAuth로그인OAuth
목차
🤔 혹시 이런 경험 있나요?
AI에게 "로그인 기능 만들어줘"라고 했더니 NextAuth, Supabase Auth, Clerk 같은 용어가 쏟아집니다. 또는 "Google로 로그인" 버튼을 만들라고 하니까 OAuth 설정이 필요하다고 합니다. 인증은 대체 왜 이렇게 복잡하고, 바이브코딩할 때 보안은 어디까지 신경 써야 할까요?
🔐 인증이란 무엇인가요?
인증(Authentication)은 "접속한 사람이 누구인지" 확인하는 과정입니다. 현실에서 비유하면 이렇습니다.
- 아파트 출입: 카드를 찍어야 문이 열립니다 → 비밀번호 로그인
- 공항 출입국: 여권을 보여줘야 합니다 → 신원 확인
- 은행 업무: 신분증 + OTP 번호가 필요합니다 → 다중 인증(MFA)
웹에서도 마찬가지입니다. 사용자가 이메일과 비밀번호를 입력하면, 서버가 "이 사람이 진짜 회원인지" 확인하는 것이 인증입니다.
본문 개념을 설명하는 학습용 예시입니다. 실제 서비스 화면이 아닙니다.
🎫 세션 vs 토큰: 로그인 상태를 유지하는 두 가지 방법
로그인에 성공하면 "이 사람은 확인된 사용자"라는 정보를 어딘가에 기록해야 합니다. 그래야 페이지를 이동할 때마다 다시 로그인하지 않아도 되니까요.
세션(Session) 방식
서버가 사용자 정보를 서버 메모리에 저장하고, 브라우저에는 세션 ID만 쿠키로 보내줍니다.
1. 로그인 → 서버: "user123 확인. 세션 ID: abc789"
2. 서버 메모리에 저장: { abc789: { userId: 123, name: '홍길동' } }
3. 브라우저 쿠키에 저장: session_id=abc789
4. 다음 요청 시 → 쿠키의 세션 ID를 보내서 본인 확인토큰(Token) 방식 - JWT
서버가 사용자 정보를 암호화된 토큰으로 만들어 브라우저에 보내줍니다. 서버는 아무것도 저장하지 않습니다.
1. 로그인 → 서버: "user123 확인. JWT 토큰 발급"
2. 토큰에 사용자 정보가 암호화되어 포함됨
3. 브라우저가 토큰을 저장 (localStorage 또는 쿠키)
4. 다음 요청 시 → 토큰을 보내면 서버가 복호화해서 확인바이브코딩에서는 대부분 토큰 방식(JWT)을 사용합니다. 서버가 상태를 저장하지 않아도 되어서 더 간단하기 때문입니다.
🌐 OAuth: "Google로 로그인"의 원리
"Google로 로그인", "GitHub로 로그인" 버튼을 본 적 있으실 겁니다. 이것이 바로 OAuth입니다.
OAuth는 다른 서비스의 계정으로 로그인할 수 있게 해주는 표준 방식입니다. 작동 원리는 이렇습니다.
1. 사용자: "Google로 로그인" 버튼 클릭
2. Google: "이 앱에 이메일 정보를 제공해도 될까요?"
3. 사용자: "허용합니다"
4. Google → 우리 앱: "이 사용자의 이메일은 hong@gmail.com입니다"
5. 우리 앱: 해당 정보로 로그인 처리OAuth의 장점은 우리 서버에 비밀번호를 저장하지 않아도 된다는 것입니다. 비밀번호 관리라는 큰 보안 부담을 Google이나 GitHub에 맡기는 셈입니다.
⚠️ 바이브코딩할 때 흔한 보안 실수
1. API 키나 비밀번호를 코드에 직접 작성
// 절대 이렇게 하면 안 됩니다
const dbPassword = 'mypassword123'
const apiKey = 'sk-abc123...'
// 환경 변수를 사용하세요
const dbPassword = process.env.DATABASE_PASSWORD
const apiKey = process.env.API_KEYGitHub에 코드를 올리면 이 비밀번호가 전 세계에 공개됩니다. 실제로 이런 실수로 수백만 원의 클라우드 비용이 청구되는 사례가 자주 발생합니다.
2. API 라우트에 인증 검사를 빠뜨림
AI가 만들어준 API 라우트가 누구나 접근 가능하게 되어 있는 경우가 많습니다. 예를 들어 /api/users/delete 같은 위험한 경로에 인증 검사가 없으면, 아무나 사용자를 삭제할 수 있습니다.
// 인증 검사 없이 위험한 작업 허용 (잘못된 예시)
export async function DELETE(req) {
await db.user.delete({ where: { id: req.params.id } })
}
// 인증 검사 추가 (올바른 예시)
export async function DELETE(req) {
const session = await getSession(req)
if (!session) return new Response('Unauthorized', { status: 401 })
await db.user.delete({ where: { id: req.params.id } })
}AI에게 코드를 요청할 때 "인증된 사용자만 접근할 수 있게 해줘"라고 반드시 명시하세요.
3. HTTPS를 사용하지 않음
HTTP로 데이터를 보내면 중간에 누군가 내용을 엿볼 수 있습니다. 다행히 Vercel, Netlify 같은 배포 플랫폼은 기본적으로 HTTPS를 제공하므로, 이 플랫폼들을 사용하면 별도 설정 없이 해결됩니다.
💼 인증이 실제 문제로 다가오는 상황
사내용 도구를 만들어 배포했을 때
AI로 만든 매출 대시보드를 Vercel에 배포하고 팀에 URL을 공유했다고 해봅시다. 로그인 기능이 없다면, 그 URL을 아는 사람은 누구든 회사 데이터를 볼 수 있습니다. 내부용 도구라도 배포하는 순간 전 세계에 열리므로, "우리 팀만 접근"이 필요하다면 인증부터 붙여야 합니다.
회원 기능을 최소 부담으로 만들고 싶을 때
회원 전용 콘텐츠나 신청 이력 조회 기능을 만들 때, 이메일과 비밀번호 방식은 암호화, 재설정, 유출 대응까지 챙길 것이 많습니다. "Google로 로그인" 같은 OAuth 방식을 선택하면 비밀번호 관리 책임을 대형 서비스에 맡길 수 있어, 혼자 만드는 프로젝트에 특히 유리합니다. AI에게 요청할 때도 "소셜 로그인만 지원해줘"라고 방향을 정해주면 결과물이 단순해집니다.
로그인이 자꾸 풀린다는 문의를 받았을 때
사용자가 "며칠 지나면 로그인이 풀려요"라고 문의하면, 대부분 토큰이나 세션의 만료 시간 설정이 원인입니다. 로그인 상태가 쿠키나 토큰으로 유지된다는 구조를 알면, AI에게 "토큰 만료 기간을 30일로 늘려줘"처럼 구체적으로 요청할 수 있습니다. 인증에 쓰이는 비밀 키들은 환경 변수로 관리해야 안전합니다.
📋 3줄 요약
-
인증은 접속한 사람이 누구인지 확인하는 절차이고 보안은 허가된 사람만 데이터에 닿게 하는 장치입니다.
-
로그인 상태를 유지하는 방법은 서버가 정보를 들고 브라우저에 세션 ID만 주는 세션 방식과 정보를 암호화한 토큰을 브라우저에 넘기는 JWT 방식으로 나뉩니다.
-
AI에게 코드를 맡길 때 자주 나는 사고는 API 키를 코드에 그대로 적는 것과 삭제 같은 위험한 API 경로에 인증 검사를 빠뜨리는 것입니다.

제대로 이해했는지 한 문제로 확인해 볼까요?
답을 고르면 바로 풀이가 나와요.
바이브코딩으로 만든 웹 앱에 'Google로 로그인' 기능을 넣었습니다. 이 방식의 가장 큰 보안상 장점은 무엇일까요?

