OAuth practice

전체적인 flow

https://docs.github.com/en/developers/apps/building-github-apps/identifying-and-authorizing-users-for-github-apps#2-users-are-redirected-back-to-your-site-by-github

  1. Users are redirected to request their GitHub identity
  2. Users are redirected back to your site by GitHub
  3. Your GitHub App accesses the API with the user's access token

깃허브 oauth 앱을 만들어서 앱에 로그인 시 깃허브에 있는 유저 정보를 받을 수 있도록 한다

1) 앱 로그인
2) 깃허브 로그인 페이지로 이동 (깃허브 authorization code 받는 uri + client_id)
3) 깃허브 로그인 페이지가 뜬다
4) 로그인 후 url이 /callback(내가 설정한 redirect 주소) + query에 넣은 client_id가 code로 바뀐다
5) code를 추출해서 서버로 보낸다
(post요청에 body(payload)로)
이유: token을 받아야 하는데 서버에서 token을 받는 게 더 안전하기 때문에

server
/callback
1)위에서 client_id 가 code로 변경해서 callback주소로 온다
ex. http://localhost:3000/callback?code=088
이 스프린트에서는 body로 받아서 사용하지만 사실은 req.query로 사용해도 괜찮을 거 같다
왜 body로 쓴거지? 쿼리는 더 노출되어 있어서 그런가? 잘 모르겠다

2)token을 받을 수 있는 주소로 code, client_id, client_secret을 보낸다
: api 확인하면 이 세가지는 필수라고 나온다
: 환경변수에 저장해둔 둘과 req.body로 받은 code까지 합쳐서 해당 주소로 post요청을 한다
: token을 받아서 client의 state에 넣는다

Client
3)깃허브 api 주소를 통해 요청을 할 때
1차적으로 깃허브에 있는 사용자 정보에 접근하기 위해 header에 accesstoken을 함께 보낸다
//token에서 했는데 accesstoken은 유효기간이 짧아서 그런지 클라의 state, localstorage, cookie등에 저장해도 되고
//refreshToken은 더 길어서 그런지 더 닿을 수 없는 위치에 저장한다(token sprint에서는 cookie(set-cookie랑 같은 res.cookie 사용, req.cookie로 조회)에 저장했다
받은 응답에서 setState를 통해 저장한다
header로 보내니까 get으로 보내도 된다

4)resource server의 /images를 받아온다
: 마찬가지로 token을 header에 보내서 인증을 받는다
: response 중 images를 받아서 setState
: images에 들어간 배열을 활용해서 뿌린다

Server
5)/images
: token이 있는지 확인하고 있으면 images를 보낸다

Client

callback 주소 : redirect 이후 돌아올 곳



1. 앱 생성 + OAuth 등록

깃허브에서 앱을 생성할 때 Oauth app 생성하기가 있다
이를 이용하면 깃허브를 Oauth server(authorization server + token server)로 등록할 수 있다
1. 앱 이름
2. 홈피 url
3. 앱 콜백 url
을 등록한다

앱에서 로그인 시 깃허브 로그인 페이지로 redirect되는데 깃허브 로그인 후 다시 원래 홈페이지로 돌아올 때 사용할 url을 3번 앱 콜백 url에 적는다

2. 환경변수 설정

server/env.

1번에서 생성한 앱의 client id와 client secret(앱 안에서 생성하고 copy를 해야 한다. 바로 복사 안하면 다시 발급 받아야할 수 있으니까 바로 복사하기!)

3.서버/ index.js

index.js 살펴보기
1. express를 이용해서 서버 생성
2. cors
: app.use(cors({origin: true})
cors()는 express의 middleware

cors option 중 origin
cross-site 접근 요청 또는 preflight request의 출처(true는 뭔지 모르겠음)
If you want to restrict AJAX access to a single origin, you can use the origin option
ex. {origin : 'www.localhost.com/3000'}

  1. post/get 요청
app.post('/callback', handleCallback);
app.get('/images', handleImages)

/callback, /images path에 대해 controller 이용
(model(db와 소통) - controller(중재) - view(UI))

app.listen(PORT, () => {
  console.log(`listening on port ${PORT}`);
});

4.서버/controller/callback.js

/callback으로 요청을 보내기 전에 클라이언트에서 일어났을 일
1)GET https://github.com/login/oauth/authorize로 REQUIRED인 client_id만 client_id=${client_id}로 보내주면 된다
그러면 redirect되어서 위의 client_id부분이 code=~~로 바뀐다

2)원래는 ?code='~~'로 redirect되니까 req.query로 들어오지 않을까?
(해보기)
하지만 여기서는 클라이언트 쪽에서 post요청+data로 authorizationCode를 넣어줬기 때문에 서버에서는 req.body에 { authorizationCode: 'fake_auth_code' }형태로 들어온다

3)이제 서버에서 access token을 받는다
클라에서 code를 이용해서 AUTHROIZATION SERVER에 요청을 보내도 되지만 서버로 굳이 code를 보내는 이유는 클라보다 서버에서 token을 받는 게 더 안전하기 때문이다

POST https://github.com/login/oauth/access_token
payload에는 client_id, client_secret, code가 필수

axios 사용법
https://github.com/axios/axios

// Send a POST request
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

axios.post(url, {params}..)등으로 보내도 되지만 이건 왠지 헷갈려서 나는 위의 방법 추천!

4)response
위의 url에 payload에 세가지 항목을 넣고 post요청을 보내면

이런 형태로 응답이 온다
응답을 받는 방법 1. async, await

응답 받는 방법 2. then

클라에서 state에 저장할 수 있도록 accessToken을 응답으로 보낸다

원래대로라면 req.body로 들어 온 authorizationCode가 맞는지 확인해줘야 하는 거 아닌가?

클라

클라/app.js

state에 isLogin, accessToken 저장하고 component인 Login, Mypage에서 사용

클라/components/login.js


isLogin이 false일 때 나오는 컴포넌트
즉 로그인하기 전 화면

로그인 버튼을 누르면 socialLoginHandler()가 실행된다
window.location.assign(url)는 url로 주소를 옮긴다
이때 우리는 깃허브 로그인 페이지로 이동시켜서 깃허브 로그인을 한다면 인증을 받았다는 의미로 authorizationCode를 돌려줘야 한다
그러므로 먼저 url자리에

GET https://github.com/login/oauth/authorize
client_id 필수

위의 url+ ?client_id=깃허브 oauth 앱 생성 시 발급받은 client_id
를 넣어준다
왜 ?지

그러면

서버에서 withCredentials를 써야 cookie 전달

axios앞에 await를 써야 기다렸다가
1. state를 갱신하는데 시간이 걸린다
2. 또는 authorizationCode를 받아올 때까지 시간이 걸린다

1번인듯
왜냐면 브라우저에서 했을 때는 con

좋은 웹페이지 즐겨찾기