OAuth 제공자에게 보내는 편지
(pilcrowonpaper.com)-
OAuth 공급자에게 보내는 편지
-
GitHub
- 토큰 엔드포인트가 오류에도 200 상태 코드를 반환함
- 오류 응답은 400 또는 401 상태 코드를 사용해야 함
-
Facebook
- 토큰 엔드포인트가 사용자 정의 오류 응답을 반환함
- 오류 필드가 있는 JSON 객체여야 함
-
TikTok
- 서버가 client_id 대신 client_key 매개변수를 사용함
- 사양에서 벗어난 이유가 없음
-
Strava
- 서버가 범위 매개변수에 쉼표로 구분된 목록을 사용함
- 공백으로 구분된 목록이어야 함
-
Naver
- 서버가 토큰 만료 시간을 문자열로 반환함
- 사양 준수 여부를 넘어선 문제임
-
다양한 OAuth 공급자
- 클라이언트 인증을 위해 client_secret 매개변수 대신 HTTP 기본 인증을 지원해야 함
- OAuth 2.1 표준에서 HTTP 기본 인증은 선택 사항이지만, PKCE가 요구됨에도 불구하고 대부분의 공급자가 이를 사용하지 않음
-
AWS
- OAuth 클라이언트 라이브러리와 함께 사용 시 여러 버그 보고를 받았으나, 문제를 재현할 수 없어 관련 내용을 삭제함
-
댓글과 토론
정부 대국민 서비스 프로젝트 구축하면서, OAuth (OIDC) 기능 구현에만 1달이 꼬박 걸린 경험이 있습니다...
외부 라이브러리를 쓸 수 없다보니, 일일히 다 구현해야 했는데 OAuth 표준을 제대로 지키는건 카카오나 구글 말고는 없었습니다...
네이버는 뭐, 로그인만 되면 문제 없지 수준이라 써도 되나 싶었고, 애플은 지금 생각해도 어떻게 구현했는지 기억조차 안날 정도로 기존 Oauth 소스의 3배 이상의 구현 코드가 필요했습니다.
위 본문처럼 응답 코드가 개판인 경우도 있고, 하다하다 418(I'm a teapot) 을 회신하는 제공자도 있었죠.
이런 경험이 있다보니 저는 소셜로그인 같은 기능을 편해도 안쓰게 되더랍니다...
Hacker News 의견들
-
OAuth에서 정말 짜증나는 건 제공자가 5개나 있고 이메일 가입까지 있는 서비스에서, 지난번에 뭘로 로그인했는지 잊어버릴 때임
그러다 실수로 새 계정을 만들게 되고, 예전 계정을 되찾을 방법이 없는 경우도 있음- 단순한 해결책은 이메일 가입을 쓰는 것이라고 봄
내 계정이 OAuth 제공자에 묶이는 걸 원하지 않음. OAuth 가입/로그인을 제공하는 서비스 중에는 그 제공자를 더 이상 쓸 수 없으면 계정까지 잠기는 방식으로 구현한 곳이 많음 - 이 문제는 비밀번호 관리자에 사용자 이름을 “OAuth: Use Google” 같은 식으로 저장해서 우회함
로그인할 때 브라우저 확장을 습관적으로 확인하거나 자동 채우기를 시도하면 어떤 OAuth를 썼는지 알 수 있음. 우아하진 않지만 충분히 쓸 만함 - 1Password 브라우저 확장은 이런 정보를 자동으로 기록하려고 시도함
- 일부 사이트는 사용한 이메일을 확인해서 새 계정을 만들지 않고 기존 계정에 연결해 주는데, 이 방식이 훨씬 마음에 듦
- 좋은 인증 솔루션을 쓰면 이런 중복 계정 생성을 막고, 이메일 주소 매칭으로 두 신원을 병합할 옵션을 줄 수 있음
안타깝게도 대부분은 자기 인증이 얼마나 나쁜지 신경 쓰지 않는데, 이해하기 어렵지만 현실임
- 단순한 해결책은 이메일 가입을 쓰는 것이라고 봄
-
1년 전에 인기 API 100개에 대해 OAuth 구현을 해봤음
경험은 원문 작성자가 설명한 것과 정확히 같았음: https://www.nango.dev/blog/why-is-oauth-still-hard- 대략 6개 API에 OAuth를 붙이는 시스템을 작업했는데, 전부 달랐음
OAuth는 명세라기보다 거친 지침들의 묶음이자 패턴에 가까움
- 대략 6개 API에 OAuth를 붙이는 시스템을 작업했는데, 전부 달랐음
-
나도 저런 이상한 OAuth를 만든 적 있음
회사 인트라넷용 OAuth 서버였고, 관련 앱의 OAuth 로그인을 구현하던 팀이 공식 명세를 따르지 않았음. 그들은 그대로는 로그인을 구현하는 게 “불가능”하다며 OAuth 동작을 바꿔 달라고 했고, 요구한 내용은 어떤 공식 명세도 따르지 않는 무작위 변경처럼 보였음. 몇 달 동안 오갔지만 결국 회사의 다른 사람들은 내가 비협조적이라고 결론내림
결국 굴복했고, 이제 모두가 쓰는 OAuth 옆에 그 팀만을 위한 OAuth 프랑켄슈타인이 같이 살고 있음. 문서에는 그들을 위한 전용#special-needs섹션을 만들었고, 왜 그런지는 설명하지 않았으니 다른 팀들이 재미있게 읽길 바람- OAuth 자체가 이미 프랑켄슈타인이라서, 색이 약간 다른 프랑켄슈타인을 하나 더 만든 셈임
-
많은 제공자가
prompt=select_account를 지원하지 않거나, 특히 OIDC에서 사용자가 어떤 계정으로 로그인할지 기본적으로 묻지 않는 점도 덧붙이고 싶음
업무에서 IAM 시스템을 다루고 여러 테스트 계정을 쓰다 보면, 예를 들어 SSO 대상 IdP에서 쉽게 로그아웃할 수 없을 때 답답함- 정말 짜증남. Chrome의 프로필 시스템이나 Firefox의 컨테이너 탭이 어느 정도는 되지만, 임시방편처럼 느껴짐
- 원하는 게 사이트가 동시에 여러 계정을 지원한다는 뜻의
select_account인지, 아니면 그냥prompt=login인지가 중요함
GitHub에 다중 계정을 추가한 뒤에도 아직 버그와 나쁜 동작을 잡는 중이라, 사람들이 구현을 꺼리는 이유는 이해됨
-
이런 공개 표준에는 누구나 바로 실행할 수 있는 공식 테스트 스위트가 있으면 정말 도움이 됨
물론 명세가 있긴 하지만, 결국 이런 걸 구현하게 되는 인턴이 전부 챙기기엔 너무 많음. 망치지 않았는지 검증할 수 있는 테스트 스위트가 있으면 매우 유용함 -
이런 문제 중 일부, 특히 Facebook의 사례는 기존 서비스 프레임워크로 OAuth2를 코딩하면서 명세에 맞게 조정하지 않았거나 못 한 것처럼 보임
다른 일부는 스크립팅에서 흔한 문제처럼 보이는데, 정수를 문자열처럼 다루고 문자열을 정수처럼 다루기 쉬운 점 때문임. “이제 명세 준수 문제가 아니다. 이 결정을 내린 사고 과정을 알고 싶다. 그리고 고쳐 달라”는 말에 대해, 사고 과정이 있었다기보다 서비스를 빨리 프로덕션에 내보내려는 압박과 세부 사항에 대한 부주의였을 수 있음. 많은 개발자가 오류 처리를 귀찮거나 선택적인 것으로 여기고, 그래서 80-20 규칙 같은 결과가 나옴 -
PHP 같은 걸 쓰면서 신경을 안 쓰면 이런 일이 생길 수 있음
데이터베이스에서 값을 읽을 때 PHP는 기본적으로 조회한 모든 컬럼 타입을 문자열로 캐스팅함. 예외는null이거나, 컬럼 타입을 PHP 타입에 맞추라고 설정한 경우뿐임- 내 추측으로는 JSON 직렬화기가 정밀도 손실을 피하려고
int64를 문자열로 쓰는 것 같음
- 내 추측으로는 JSON 직렬화기가 정밀도 손실을 피하려고
-
“Dear AWS” 섹션은 내 OAuth 클라이언트 라이브러리에서 여러 버그 보고를 받아 넣었지만, 재현할 수 없어서 글에서 제거했다는 부분이 아쉬움
AWS 자체에는 관심 없지만, 이 글은 흔한 함정에 대한 훌륭한 점검 목록임. 특정 제공자가 이미 고쳤더라도 남겨두면 여전히 유용했을 것 같음- https://github.com/pilcrowonpaper/pilcrow/commit/29b105e9c12... “remove aws”
- AWS OIDC의 큰 문제 하나는 API Gateway가 명세에서 요구하는
access_token이 아니라id_token으로 요청을 검증한다는 점임
다만 AppSync로 구독을 쓰면 그때는id_token이 아니라access_token을 요구함. 그런데 AWS의 amplify 라이브러리는 이 차이를 모르기 때문에 속여야 함. 프런트엔드에서 구현하기 참 재미있는 부분임
-
오류 필드가 있는 JSON 객체여야 한다는 건데, 보여준 것이 정확히 그 형태임
명세에서 그 필드가 문자열이어야 한다고 하나?- 형제 댓글 말처럼 단순히 문자열이라는 것뿐 아니라, 어떤 문자열들이 예상되는지도 정해져 있음
OIDC는 목록을 몇 개 더 확장함: https://openid.net/specs/openid-connect-core-1_0.html#AuthEr...
이 덕분에 클라이언트가 어떤 서버와도 상호 운용될 수 있음. Facebook이 하는 식으로 구현하면 RFC를 구현하는 주요 목적 중 하나인 상호 운용성을 완전히 무시하는 셈임 - https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1
- 형제 댓글 말처럼 단순히 문자열이라는 것뿐 아니라, 어떤 문자열들이 예상되는지도 정해져 있음
-
OIDC/OAuth 제공자들은 SCIM을 제대로 지원하고, API 우선 사고방식으로 시스템을 설계해 주면 좋겠음
리디렉션 라우트와 임베디드 로그인 기능도 내가 설계할 수 있게 해 달라. GNAP(Grant Negotiation and Authorization Protocol) https://oauth.net/gnap/로 넘어가기 전에 결정들을 다시 생각해 봐야 함