OAuth 2.0

Ryu·2022년 5월 3일
0

2020-archive

목록 보기
6/7

2020에 작성한 노트를 옮겨 적은 것입니다.

Scenario

일반적인 경우는 구글, 페이스북과 같은 authorizer (혹은 provider)를 사용하는 것이지만, 여기서는 authorizer도 같이 구현하는 경우를 정리함.

Flow

  1. 유저가 엑세스 권한을 얻기 위해 authorizer에게 리디렉트 됨.
  2. Authorizer 가 권한을 주고 (grant), 유저는 access token을 얻을 수 있는 '코드'와 함께 다시 token provider로 리디렉트 됨
  3. 유저는 token provider로부터 해당 grant에 맞는 토큰을 부여 받고, callback url (application entry)로 리디렉트 됨

Passport Configuration


const passport = require('passport')
  , OAuth2Strategy = require('passport-oauth').OAuth2Strategy;
 
passport.use('provider', new OAuth2Strategy({
    authorizationURL: 'https://www.provider.com/oauth2/authorize',
    tokenURL: 'https://www.provider.com/oauth2/token',
    clientID: '123-456-789',
    clientSecret: 'shhh-its-a-secret'
    callbackURL: 'https://www.example.com/auth/provider/callback'
  },
  function(accessToken, refreshToken, profile, done) {
    User.findOrCreate(..., function(err, user) {
      done(err, user);
    });
  }
));

위의 verify callback은 provider, 즉 authorizer가 발급한 토큰들을 적당히 처리함.

Route

// Redirect the user to the OAuth 2.0 provider for authentication.  When
// complete, the provider will redirect the user back to the application at
//     /auth/provider/callback
app.get('/auth/provider', passport.authenticate('provider'));
 
// The OAuth 2.0 provider has redirected the user back to the application.
// Finish the authentication process by attempting to obtain an access
// token.  If authorization was granted, the user will be logged in.
// Otherwise, authentication has failed.
app.get('/auth/provider/callback',
  passport.authenticate('provider', { successRedirect: '/',
                                      failureRedirect: '/login' }));

유저 접근 시, 처음에 provider로 리디렉트 해준 뒤, 유저의 권한이 인증되면 application entry로 접근하기 위한 callback url로 리디렉트 된다

Authorizer 서버 구현

참고 1.
참고 2.

유저의 ID, Secret을 가지고 grant와 token (access token, refresh token)을 발급하는 역할을 한다.

passport-oauth2 개발자가 만든 oauth2orize(https://yarnpkg.com/package/oauth2orize)를 사용하지만, 더 나은 방법이 있는지 알아봐야 함.

위 OAuth2Strategy에서 설정한 authorizationURL, tokenURL 엔드포인트를 구현한다.

Route

app.get('/oauth2/authorize',
    login .ensureLoggedIn(),
    server.authorize(clientID, redirectURI, done) => {});
 
app.post('/oauth2/token',
  passport.authenticate(['basic', 'other-strategy', ...]),
  server.token(),
  server.errorHandler(),
);

Flow

  1. 유저가 GET /authorize 요청

    • response_type: 'code'

      REQUIRED. The value MUST be one of "code" for requesting an
      authorization code as described by Section 4.1.1, "token" for
      requesting an access token (implicit grant) as described by
      Section 4.2.1, or a registered extension value as described by
      Section 8.4.

    • client_id: Public identifier
    • redirect_uri: Authorization 서버가 인증 승인 후 user 요청 리디렉트 할 주소
    • scope: space-separated strings.
    • state: 요청하는 단에서 보내는 random string. 인증 후 return 값이 해당 state와 같은지 체크해야함. 참고.
  2. Authorize의 엔드포인트에서 server.authorize() 실행

    1. client_id를 기준으로 등록된 사용자인지 검사 후 클라이언트 정보로 done()
    2. 이 때 session 필요함. (express.session())
    3. session support를 위해서 server에 serialization, deserialization 함수 등록 필요

Obtaining the user's authorization involves multiple request/response pairs. During this time, an OAuth 2.0 transaction will be serialized to the session. Client serialization functions are registered to customize this process, which will typically be as simple as serializing the client ID, and finding the client by ID when deserializing.

server.serializeClient(function(client, done) {
  return done(null, client.id);
});

server.deserializeClient(function(id, done) {
  Clients.findOne(id, function(err, client) {
    if (err) { return done(err); }
    return done(null, client);
  });
});

0개의 댓글