최근 OAuth 리소스 서버를 만드려고 하고 있다.
로또는 끝났냐고?
그거 로그인 기능 만들까 하다가 OAuth 적용을 해야 내가 공부가 되지 않을까 싶어서 그거 하는 중
OAuth으로 인증 및 권한을 위임 한다. 그 위임 방법이 grant type이라 하겠다.
즉 클라이언트에서 토큰을 어떻게 가지고 올래? 라는 뜻
grant type은 국룰로 한 4개 정도로 정해져 있다. 클라이언트나 서버를 어떻게 구성했냐에 따라 다르게 사용한다.
이 4가지로 구분 된다. 대부분은 1번 방식을 사용한다는 듯. 여기선 1번과 2번만 살펴보자
이건 뭐 이용자가 요청하는거니까 걍 넘기고
클라이언트가 인증 서버에게 권한 요청을 특정 엔드포인트에 한다.
이 엔드포인트 매핑은 제공 업체마다 다를 수 있음.
스프링 OAuth 서버도 기본 제공하는 api가 있을거임
/oauth/authoriza?response_type=code&client_id=foo&redirect_uri={example.oauth.server.com}&scope=블라블라&state=1q2w3e~!
대충 이런 식일거다.
response_type : Authorization Code 방식이므로 응답 값은 code로 들어와야 한다.
client_id : 클라이언트의 고유 식별자를 뜻한다.
redirect_uri : 인증 코드를 클라이언트에 보낼 때 사용자의 브라우저가 리다이렉션 되야 하는 uri다. 콜백 uri 혹은 콜백 엔드포인트라고도 한다.
scope : 액세스 하려는 사용자 데이터의 범위를 말한다. 사용자가 동의한 범위의 scope만이 액세스 토큰에 넣는다.
state : 클라이언트에서 랜덤 값을 저장해서 보낸다. 서버는 응답할 때 이 값을 정확하게 반환해야 한다. 이 매개변수는 엔드포인트에 대한 요청이 OAuth 요청을 시작한 사람 즉 리소스 오너와 동일한지 확인하는 값이다. csrf 공격을 차단하기 위한 수단으로 쓰겠지?
필수 값은 다아연히 response_type, client_id다 나머진 선택이나 state는 권장사항임.
따지면 동의를 얻는 부분이라 할 수 있겠다. 구글 로그인을 사용한다고 했을 때, 우리 휴대폰으로 "야 이거 니가 요청한거 맞냐?" 뭐 이런거 오잖아? 그런거랑 비슷한거지
즉 2번에 Code 요청이 정상적으로 잘 이루어질 경우, 동의하니? 화면을 보게 된다.
보통 한 번 동의를 해두면 이후엔 안해도 된다.
3에서 리소스 오너가 ㅇㅋㄷㅋ 하면 인증 서버에선 인증 코드를 보내준다. 이게 바로 Authorization Code인 거시다.
3에서 ㅇㅋ 하면 2에서 정해둔 redirect_uri로 사용자의 브라우저는 리다이렉션 된다. 이 때 get 요청이 나갈 땐 파라미터로 인증 코드랑 state가 나간다.
GET /bar?code=abcdefg123&state=1q2w3e~! HTTP/1.1
Host : test.com
대충 이런 식임 인가코드는 1회용이다. 동일한 인가코드로 액세스 토큰을 요청할 시 무적권 실패한다.
인가 코드는 보안적인 이유로 빠르게 사용해야함. 그래서 보통 만료시간을 10분으로 제한 하도록 권장한다칸다.
자 이제 인가코드가 들어왔으니 클라이언트는 액세스 토큰을 요청해야 한다.
클라이언트는 Post를 써서 인증 서버에 액세스 토큰을 요청한다.
이를테면
POST /token HTTP/1.1
Host : example.comclient_id=foo&client_secret={secret}&redirect_uri={example.oauth.server.com}&grant_type=authorization_code&code=abcdefg123
client_secret이 드디어 나왔다.
구글 api를 써보면 알겠지만 신청할 때 단 1번 시크릿을 알려준다. 외우지도 못하니까 잘 적어놔야함.
그걸 여기서 쏴줘야 한다.
그리고 당연히 grant_type는 authorization_code고
4번에서 받은 code를 여기서 똑같이 써준다.
인증 서버가 토큰을 만들어서 잘 준다.
클라이언트는 이걸 또 저장해서 리소스 서버에 요청을 해야겠지?
클라이언트가 드디어 리소스 서버에 자원을 요청할 수 있다.
GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization : Bearer 어쩌구저쩌꾸꺼쩌쩌
내가 지금 만들고 있는 OAuth 서버는 걍 리소스 서버랑 인증서버랑 통합해서 할거다. 귀찮음
그럼 걍 데이터 보내주면 끝!
클라이언트는 이걸 이용해서 로그인 잘 해두면 된다.
1번 인증 코드 방식에서 인증 코드 와리가리를 빼면 얘다.
나 sns 로그인 할꺼야
코드 방식과 거의 비슷하다 여기까진! 근데 코드를 요청하는게 아니라 토큰을 요청함
/oauth/authoriza?response_type=token&client_id=foo&redirect_uri={example.oauth.server.com}&scope=블라블라&state=1q2w3e~!
다른건 다 똑같은데 response_type이 토큰임에 주목하자
사용자가 로그인 하겠다고 ㅇㅋㄷㅋ 하는거다.
여기서 바로 클라이언트에게 액세스 토큰을 준다.
redirect_uri로 파라미터로 토큰을 전달한다
GET /callback#access_token=z0y9x8w7v6u5&token_type=Bearer&expires_in=5000&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com
이케이케 한다.
똑같음
GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization : Bearer 어쩌구저쩌꾸꺼쩌쩌
똑같음
흐름은 대부분이 이런 형식이다.
다만 리소스 서버랑 인증 서버가 통합일 경우도 있고, 응답이 Json으로 오는지 다른거로 오는지 업체마다 다를 수 있음
상기 Authorization Code의 흐름을 기준으로 설계를 한다면, 암묵적 방법 역시 쉽게 할 수 있을 것!
참고 사이트
https://portswigger.net/web-security/oauth/grant-types
https://kimdoky.github.io/oauth/2019/05/01/oauth-serverside-flow/