엔지니어링 가이드

인증 붙이기

템플릿에는 인증이 없다. 무엇을 정하고 어디에 붙일지, 그리고 직접 해 볼 요청 예시

예시 서버는 127.0.0.1 에서만 열리고, 요청이 누구의 것인지 묻지 않는다. 이대로 밖에 열면 주소를 아는 누구나 메모를 읽고 지울 수 있다.

템플릿이 인증을 넣지 않은 이유는 방식이 프로젝트마다 다르기 때문이다. 브라우저 앱만 있으면 쿠키 세션이 맞고, 모바일 · 데스크톱 앱이 있으면 토큰이 필요하다. 사용자를 직접 확인할 수도, 외부 제공자(OIDC)에 맡길 수도 있다. 하나를 골라 넣어 두면 다른 방식을 쓰는 프로젝트는 그것을 걷어내는 일부터 해야 한다. 이 글은 구현 대신 정할 것과 붙일 자리를 정리하고, 에이전트에게 맡길 때 쓸 요청 예시를 남긴다.

먼저 정할 것

  • 누가 부르는가. 브라우저 앱만 있는지, 모바일 · 데스크톱 앱도 있는지에 따라 쿠키 세션과 토큰 중 하나를 고른다.
  • 누가 사용자를 확인하는가. 비밀번호를 직접 다루는지, OIDC 제공자의 토큰을 검증만 하는지 정한다.
  • 어느 서버가 검증하는가. 서버마다 검증하는지, 앱이 들어오는 gateway 한 곳에서 하는지 정한다(gateway 에서 하면 검증한 사용자 id 를 헤더로 넘기고, 서버는 gateway 를 거친 요청만 받게 막는다). 사용자 · 로그인을 맡는 서버(예: identity)를 따로 두면 다른 서버는 그 서버가 준 토큰을 검증만 한다. 서버 ↔ 서버(gRPC)는 사용자 인증과 별개로 mTLS 나 서비스 토큰으로 막는다.
  • 데이터의 주인과 오류 코드. 메모에 사용자 id 를 붙이고, 다른 사용자의 메모를 요청하면 404 로 숨길지 403 으로 알릴지 정한다. 인증이 없으면 401 이다.

이 선택은 여러 서버와 앱에 걸치고 되돌리기 어렵다. 구현 전에 decisions/template.md 로 ADR 을 쓴다.

붙일 자리

인증은 api 층의 일이다. domain 은 HTTP 헤더를 모르고, 요청한 사용자의 id 를 인자로 받는다.

층 할 일
gateway (고르면) 토큰을 검증하고 사용자 id 를 헤더로 넘긴다. 경로 표 앞에 한 단계를 둔다(servers/gateway). 서버의 api 는 그 헤더만 믿는다
api 요청에서 사용자를 확인한다. notes(Node)는 src/api/http/server.ts 의 요청 처리 앞, activity(Spring)는 Spring Security 필터, tags(FastAPI)는 dependency 나 server/support/security.py
domain 사용자 id 를 받아 그 사용자의 메모만 다룬다
storage notes 에 사용자 id 열을 더하는 새 마이그레이션 (database.md)
clients 외부 제공자(토큰 검증 키 조회 등)를 부르는 코드. 테스트에서는 Fake 로 바꾼다
  • 계약: 서버의 openapi 문서에 인증 방식(securitySchemes)이 나오게 해서 클라이언트도 알 수 있게 한다.
  • 테스트: 각 *_specs 에 “토큰이 없으면 401”, “다른 사용자의 메모는 404(또는 403)” 같은 경우를 더한다. 외부 제공자는 Fake 다(testing.md).
  • 브라우저: 쿠키 세션을 쓰면 JSON 본문만 받는 규칙만으로는 부족하다. SameSite 와 CSRF 토큰을 함께 정한다.

요청 예시

아래는 notes 서버와 web 앱에만 토큰 인증을 붙이는 요청이다. 꺾쇠(<...>)를 자기 프로젝트의 값으로 바꿔 쓴다. 첫 단계에서 ADR 을 제안하고 멈추게 한 것은, 인증 방식이 사람이 정할 일이기 때문이다.

목적: 메모를 사용자별로 나눈다. 로그인한 사용자만 자기 메모를 읽고 쓴다.

먼저: docs/decisions/template.md 로 인증 방식 ADR 을 "제안" 상태로 쓰고 멈춘다. 내가 확인한 뒤에 구현한다.
  정할 것: 토큰 발급자 <OIDC 제공자>, 전달 방식(Authorization: Bearer), 다른 사용자의 메모를 요청했을 때 404 와 403 중 무엇을 줄지.

변경 범위: notes 서버와 web 앱만. tags · activity 와 다른 앱은 바꾸지 않는다.
  - notes api: 액세스 토큰(JWT)을 검증하고 사용자 id 를 domain 에 넘긴다.
  - notes clients: 토큰 검증 키(JWKS)를 가져오는 코드를 둔다.
  - DB: notes 에 user_id 열을 더하는 새 마이그레이션. 기존 마이그레이션은 고치지 않는다.
  - web: 로그인 후 받은 토큰을 API 요청 헤더에 붙인다.

제약: 테스트에서 실제 제공자를 부르지 않는다. 키 조회는 Fake 로 바꾸고 테스트용 키로 토큰을 만든다. mock 은 쓰지 않는다.

완료 기준: /api/notes 의 각 *_specs 에 "토큰이 없으면 401", "다른 사용자의 메모는 <ADR 에서 정한 코드>" 를 더하고,
  기존 경우는 자기 토큰으로 지금처럼 통과한다. pnpm gen 결과가 같은 커밋에 있다.

확인: pnpm --filter @app/notes test 와 pnpm typecheck 를 실행한다. 화면은 verify-local 로 띄워 확인할 주소를 알려 준다.

보고: 실행한 확인과 결과, 실행하지 못한 확인과 이유, 범위 밖 변경이 필요했다면 그 이유와 대안을 나눠 적는다.

요청을 나누는 기준은 AI 와 개발하기의 “일을 맡기는 요청”과 같다.

GitHub 에서 고치기