Firebase Authから返ってくるJWTをゴニョゴニョする(1)
同じモチベーションの人がいたら幸いです。
モチベーション
Rails にしろGoにしろ自前でAuth周りを書くのがだるい
- ログイン機能は必要だけど、さっさと作って使われるか検証したい
- 認証なしでやればいいじゃん?って話もあるけど、なんだかんだMyhogehogeみたいな機能を実装して試したい
Rails -> devisev? => なにか起こる度にRack::MiddleWareとかにログを指して折ってくのつらい..
- 2010年くらい(@Masashisalvadorが学生だったころ)から同じような感じ..
Go
- コードは読みに行けるけど..自前で実装すんのかよ => 本質的な機能の部分をさっさと実装したい (=認証は外付けにしたい)
FirebaseにAuthあるじゃん
最終的にやりたいこと
- Firebaseから飛んでくるJWTをよしなにパースして認証したい。
とりあえず認証をザクっと書いてJWTの中身を覗いてみる
コードはクソ雑ですが…
onClickSignInWithFacbook() { firebase.auth().signInWithPopup(provider).then((result) => { // This gives you a Facebook Access Token. You can use it to access the Facebook API. global.rrr = result; let token = result.credential.accessToken; // The signed-in user info. let user = result.user; // ...3 this.setState({ user }); console.log(token); console.log(user); }).catch((error) => { console.log(error); console.log("Error on facebook auth"); // Handle Errors here. let errorCode = error.code; let errorMessage = error.message; // The email of the user's account used. let email = error.email; // The firebase.auth.AuthCredential type that was used. let credential = error.credential; // ... }); } onClickSignInWithGoogle() { firebase.auth().signInWithPopup(gProvider).then((result) => { // This gives you a Google Access Token. You can use it to access the Google API. global.rrr = result; let token = result.credential.accessToken; // The signed-in user info. let user = result.user; this.setState({ user }); console.log(token); console.log(user); // ... }).catch((error) => { console.log("error on google auth"); console.log(error); // Handle Errors here. let errorCode = error.code; let errorMessage = error.message; // The email of the user's account used. let email = error.email; // The firebase.auth.AuthCredential type that was used. let credential = error.credential; // ... }); }
Google Authの場合
rrr.credential.idToken # .でくぎられたJWTが入ってる rrr.credential.idToken.split(".") # header / claims / signatureに別れてる
1つめのセグメント = splitした配列の先頭はただのヘッダのはず
echo -n "eyJhbGciOiJSUzI1NiIsImtpZCI6IjdhOWY5Yzc5ZGYzMDU5MzhlMjY4ODk3Y2JkNDc1ZDQ3MjY4MWI0ZWEifQ" | base64 -D {"alg":"RS256","kid":"7a9f9c79df305938e268897cbd475d472681b4ea"%
JWTのヘッダが入っている。閉じカッコがないのが気になるがこれは? kidは公開鍵を探しに行く時に使う。
echo -n "2つ目のセグメント" | base64 -D | jq .
{ "azp": "xxxxx.apps.googleusercontent.com", "aud": "xxxxx.apps.googleusercontent.com", "sub": "1111111111111111111", "email": "hoge@example.com", "email_verified": true, "at_hash": "xxxxxxx", "iss": "accounts.google.com", "iat": 1495084945, "exp": 1495088545 }
JWTのStandardぽいものに、認証に使ったemailなどが入っている。
Facebook Authの場合
上記コードの result.user.Yd
というキーで JWTが入っていた。google Auth
の場合も同様でした。(googleの場合はcredentialsにも入っている)
rrr.user.Yd.split(".")
{ "iss": "https://securetoken.google.com/xxxx", "name": "Masashi Salvador Mitsuzawa", "picture": "https://scontent.xx.fbcdn.net/v/t1.0-1/p100x100/16142336_1426152514084193_2027921832216883945_n.jpg?oh=8d6238d7d50034e2fd7208c8a4208fc1&oe=59745742", "aud": "xxxx", "auth_time": 1495086800, "user_id": "xxxx", "sub": "xxxx", "iat": 1495086800, "exp": 1495090400, "email": "xxxxx@yahoo.co.jp", "email_verified": false, "firebase": { "identities": { "facebook.com": [ "1562766520422791" ], "email": [ "m_m_moonty@yahoo.co.jp" ] }, "sign_in_provider": "facebook.com" } }
こんな感じでClaimsがDecodeできる。
} (closing bracket)が消える問題
echo -n "eyJhbGciOiJSUzI1NiIsImtpZCI6IjdhOWY5Yzc5ZGYzMDU5MzhlMjY4ODk3Y2JkNDc1ZDQ3MjY4MWI0ZWEifQ" | base64 -D {"alg":"RS256","kid":"7a9f9c79df305938e268897cbd475d472681b4ea"% # }が消えてる
同じ文字列を Golang
で書いた適当なコードでdecodeしてやると
(string) (len=64) "{\"alg\":\"RS256\",\"kid\":\"e62eaba0e06fe1463746c69efa974c1152234634\"}"
問題なく閉じカッコが出現する
}
はエンコードすると
echo -n "}" | base64 fQ==
となるので、たしかに文字列としてはたりなさそうに見える。 Base64自体はRFCかなにかで規定されている(はず)なので、挙動差異は変なのだが…何なのだろう?