Open13

firebase auth関連

yasushi.kobayashiyasushi.kobayashi

サーバーでの認証のハンドリング

yasushi.kobayashiyasushi.kobayashi

golang twitter

jsonのサンプルでfirebase以下の部分は型が map[string]interface{} なので、データの整形がgoだと少し面倒

tsとかのほうが書きやすそう・・・

type (
	Claims struct {
		Name      string
		Picture   string
		TwitterID string
	}

	FirebaseAuth struct {
		*auth.Token
		Claims
	}
)

func abstractSlice(arr interface{}) []string {
	var dest []string
	switch sl := arr.(type) {
	case []interface{}:
		for _, b := range sl {
			dest = append(dest, fmt.Sprint(b))
		}
	case []string:
		for _, str := range sl {
			dest = append(dest, str)
		}
	case []int:
		for _, i := range sl {
			dest = append(dest, fmt.Sprint(i))
		}
	}
	return dest
}

func DecodeToken(token string) (*FirebaseAuth, error) {
	auth, err := newFirebase()
	if err != nil {
		return nil, errors.Wrap(err, "failed to create firebase client")
	}

	ctx := context.Background()
	verifyToken, err := auth.VerifyIDToken(ctx, token)
	if err != nil {
		return nil, errors.Wrap(err, "failed to verify token")
	}

	if verifyToken == nil {
		return nil, errors.New("token is nil")
	}

	// json example:
	//{
	//   "name": "Kobayashi.Yasushi",
	//   "picture": "https://pbs.twimg.com/profile_images/869211171517120512/bhVNCS-m_normal.jpg",
	//   "iss": "https://securetoken.google.com/twitter-hogehoge",
	//   "aud": "twitter-hogehoge",
	//   "auth_time": 1651825626,
	//   // uid
	//   "user_id": "uid",
	//   "sub": "",
	//   "iat": 1651825626,
	//   "exp": 1651829226,
	//   "firebase": {
	//     "identities": {
	//       "twitter.com": [
	//         "0101010101"
	//       ]
	//     },
	//     "sign_in_provider": "twitter.com"
	//   }
	// }
	name, _ := verifyToken.Claims["name"]
	profileImage, _ := verifyToken.Claims["picture"]
	fire, _ := verifyToken.Claims["firebase"]
	// nolint:forcetypeassert
	castFire := fire.(map[string]interface{})
	identities, _ := castFire["identities"]
	// nolint:forcetypeassert
	castIdentities := identities.(map[string]interface{})
	twitter := abstractSlice(castIdentities["twitter.com"])

	// nolint:forcetypeassert
	res := &FirebaseAuth{
		Token: verifyToken,
		Claims: Claims{
			Name:      name.(string),
			Picture:   profileImage.(string),
			TwitterID: twitter[0],
		},
	}
	return res, nil
}
yasushi.kobayashiyasushi.kobayashi

auth0との機能面での比較

yasushi.kobayashiyasushi.kobayashi

パスワードポリシー

  • auth0は簡単に管理画面で設定可能
  • firebaseには現状の機能としてなさそうなので、完全にパスワードポリシーを準拠するためには、サーバー側からユーザー作成等が必要そう
    • rate limitはデフォルトで設定されており、簡単に変更可能
yasushi.kobayashiyasushi.kobayashi

認証方法の柔軟性

  • firebaseはカスタム認証の自由度が高そう?
  • auth0はpipelineで色々柔軟にできる(指定企業だけMFAを必須にする等)し、そもそも多機能なので、ぱっと思いつくことは大体できた
yasushi.kobayashiyasushi.kobayashi

料金は、firebaseの方が圧倒的に安いが、基本的なことはどちらもほぼ無料でできる

yasushi.kobayashiyasushi.kobayashi

フロント

yasushi.kobayashiyasushi.kobayashi

onAuthStateChanged というメソッドがあり、firebaseの認証状況変化に合わせて、色々な処理を簡単にかけるのがめちゃくちゃ楽
nextなら、これを_app.tsxに入れておけば簡単に認証制御できる

yasushi.kobayashiyasushi.kobayashi

docker/firebase emulatorでローカル環境構築

yasushi.kobayashiyasushi.kobayashi

公式のfirebase emulatorのイメージはないが、firebase cliにデフォルトでemulatorの機能が入っていいるので、それを使える

yasushi.kobayashiyasushi.kobayashi

一つのプロジェクトであれば、普通に起動して使えるが、複数のプロジェクトのfirebase authを構築したい場合はfirebase emulatorもgolangのclientも対応不十分

yasushi.kobayashiyasushi.kobayashi

--export-on-exit というオプションはあるが、dockerが止まっても動くものではないので、データの永続化ができない