Firebase Auth workflow (custom provider)

최낙원·2022년 1월 11일
0

Firebase OAuth workflow Firebase OAuth workflow

Firebase OAuth custom provider workflow Firebase OAuth custom provider workflow

Firebase에 트위치 OAuth로 인증 기능을 사용할 때 처음에 이해가 안가는 부분이 있어서 헤메다가 왜 헤맸는지를 Firebase의 OAuth workflow를 설명하면서 정리하고자 한다.

Firebase Auth의 큰 특징

  • OAuth의 각종 설정을 Firebase 서버(API)에 저장
    • OAuth 링크와 status 코드도 Firebase API를 통해 가져옴
  • OAuth를 수행 후 token도 Firebase API로 전달됨
    • 어플리케이션으로 전달되지 않고 Firebase 서버에서 처리

Firebase OAuth workflow

Firebase OAuth workflow Firebase OAuth workflow

사용자 조작으로 signInWithPopup()을 호출하면
1. Firebase API로 사용자에게 보여줄 OAuth uri 요청

POST www.googleapis.com/identitytoolkit/v3/relyingparty/createAuthUri?key={firebaseConfig.apiKey}
{
    "continueUri": "https://wrd-user-filter.firebaseapp.com/__/auth/handler",
    "customParameter": {},
    "oauthScope": "{\"google.com\":\"profile\"}",
    "providerId": "google.com"
}
  1. 생성한 OAuth uri 응답
200
{
    "authUri": "https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={google.client_id(auto)}&redirect_uri=https://wrd-user-filter.firebaseapp.com/__/auth/handler&state={state_code}&scope={scope}",
    "kind": "identitytoolkit#CreateAuthUriResponse",
    "providerId": "google.com",
    "sessionId": "{sessionId}"
}
  1. 2에서 가져온 uri를 팝업창에 표시
GET https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={google.client_id(auto)}&redirect_uri={authUri}&context_uri={context_uri}
  1. 사용자가 OAuth 창에서 로그인 절차를 수행한 후 응답(리다이렉트)
302 https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={google.client_id(auto)}&redirect_uri={authUri}&context_uri={context_uri}

GET {authUri} = https://wrd-user-filter.firebaseapp.com/__/auth/handler?state={state_code}&code={auth_code}&scope={scope}&authuser=0&prompt=none
  1. 2에서 받은 응답의 정보를 Firebase API로 다시 보내 3의 절차를 수행한 사용자와 동일 사용자임을 인증(확인)
POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyAssertion?key=AIzaSyBA9iVpvQJLSaOywTzMUiBung4-GFKuJ9Q
{
    "requestUri": "https://wrd-user-filter.firebaseapp.com/__/auth/handler?state={state_code}&code={auth_code}&scope={scope}&authuser=0&prompt=none",
    "returnIdpCredential": true,
    "returnSecureToken": true,
    "sessionId": "{sessionId}"
}
  1. 로그인이 정상임을 응답하고 사용자 정보를 반환
200
{
    "context": "",
    "displayName": "{displayName}",
    "email": "{email}",
    "emailVerified": true,
    "expiresIn": "3600",
    "federatedId": "https://accounts.google.com/{federatedId}",
    "firstName": "{firstName}",
    "fullName": "{fullName}",
    "idToken": "{idToken}",
    "kind": "identitytoolkit#VerifyAssertionResponse",
    "lastName": "{lastName}",
    "localId": "{localId}",
    "oauthAccessToken": "{oauthAccessToken}",
    "oauthExpireIn": 3598,
    "oauthIdToken": "{oauthIdToken}",
    "photoUrl": "{photoUrl}",
    "providerId": "google.com",
    "rawUserInfo": "{rawUserInfo}"
}

이와 같이 Firebase에서 기본적으로 제공해주는 OAuth 프로바이더는 프론트엔드, 백엔드에서 OAuth를 위해 별도의 과정을 수행할 필요가 없다.

Firebase OAuth custom provider workflow

Firebase OAuth custom provider workflow Firebase OAuth custom provider workflow

Firebase에서 지원하지 않는 커스텀 프로바이더를 사용할 때는 Firebase OAuth workflow 5의 과정을 수행할 백엔드가 어떠한 형태든 필요하다.

일반적인 OAuth과정 처럼 토큰을 받아온 후
1. 백엔드에 토큰을 전달한다. (개발자마다 구현이 다른 부분)

GET http://localhost:5000/implicit?access_token={access_token}
  1. 백엔드에서 사용자의 고유 id (UID)로 signInWithCustomToken에 필요한 idToken을 생성한다.
    이 때 백엔드는 Firebase 프로젝트 관리자 계정으로 로그인 되어있어야 한다.
const firebaseToken = await admin.auth().createCustomToken(twitchUser.id);
  1. 백엔드에서 생성한 idToken을 프론트엔드에 전달한다. (1.의 응답으로 전달함)
200 JSONP
"{idToken}"
  1. signInWithCustomToken을 호출하여 3에서 전달받은 idToken을 Firebase API에 전달한다.
this.afAuth.signInWithCustomToken(idToken);
POST http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=AIzaSyB0EeQFiKVkUyq_zpY8UPJMUv-JZUklpX4

{
    "token":"{idToken}",
    "returnSecureToken":true
}
  1. access token과 refresh token를 응답

200
{
    expiresIn: "3600"
    idToken: "{secureIdToken}"
    isNewUser: false
    kind: "identitytoolkit#VerifyCustomTokenResponse"
    refreshToken: "{refreshIdToken}"
}

결론

signInWithCustomToken에 사용할 토큰을 만드는 별도의 서버가 필요하다.

Firebase의 기본 Auth 기능만 사용하다가 커스텀 프로바이더가 필요해서 자바스크립트에서 커스텀 인증 시스템을 사용하여 Firebase에 인증 설명을 봤을 때 별도의 서버가 필요하다는 것을 한번에 이해하기 힘들었다.

사용자가 앱에 로그인하면 사용자의 로그인 인증 정보(예: 사용자 이름과 비밀번호)를 인증 서버로 전송하세요. 서버가 사용자 인증 정보를 확인하여 정보가 유효하면 커스텀 토큰을 반환합니다.
원문

이 인증 서버가 별도의 서버라는 것을 이해하는데 많은 시행착오가....

PS

Firebase API 문서를 볼 때 admin 관련된 무언가가 있으면 이는 백엔드에서 수행하는 일이란 뜻이다.

참고자료

profile
한 발자국 성장하는 개발자

0개의 댓글