はじめに
業務でOAuth2のPKCEの対応(Mobile側)をすることになった。
当方はAndroidエンジニアだが、サーバサイドとの疎通がうまくいかない。
レスポンスを見る限りPKCEのCodeVerifierからChallengeに変換できていないようだ。
サーバサイドからおかしなところがあったら指摘してくれ、と言われたので与えられている情報から修正案を作ってみた。
なお、Go言語はSoftware Designの記事で少し触ってみただけで業務で使ってないので俺に聞くなというスタンス。
PKCEとは
簡単に言えば認可コード横取りを防ぐ仕組みです。
この記事がわかりやすいと思います。
https://qiita.com/samiii/items/9574d1e237228c718cd6
どんなことが起こっていたか
最初にコードを取得するところは問題ない。(Mobile側で作ったChallenge渡すだけなので)
実際にtokenを取得する際に "不正なCodeVerifier" と言われている。
ただ、Mobile側で(確認用に)使用しているCodeVerifierとCodeChallengeは以下の資料に載っているものなのでこちらが間違っているとは考えにくい。
https://tools.ietf.org/html/rfc7636#appendix-B
サーバサイドから与えられた情報から判断すると、CodeVerifierをsha256にかけた後は
13d31e961a1ad8ec2f16b10c4c982e0876a878ad6df144566ee1894acb70f9c3
となっており同じなのでおそらく正しい。
となるとBase64にかけたときに問題が起こっている。
期待値は以下。
E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
かけた結果として提示された値が以下。
MTNkMzFlOTYxYTFhZDhlYzJmMTZiMTBjNGM5ODJlMDg3NmE4NzhhZDZkZjE0NDU2NmVlMTg5NGFjYjcwZjljMw
そもそもChallengeはどうのようにして作られるか
- 48~128までの値Aを用意します。
- Aに対しsha256をかけた値をBとします。
- Bに対してunpaddedかつurl-safeなかたちでBase64をかけた値をCとします。
- CをChallengeとして使います。
どのようにして実装したか
package main
import (
"fmt"
"encoding/base64"
"crypto/sha256"
)
func main() {
codeVerifier := "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
codeChallenge := "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
converted := sha256.Sum256([]byte(codeVerifier))
fmt.Println(converted)
based := base64.RawURLEncoding.EncodeToString(converted[:])
fmt.Println(based)
result := codeChallenge == based
fmt.Println(result)
}
何がいけなかったか
ソースコードは見てないので断定できませんが、おそらくconvertedをhexでstringにしてそれをさらに[]byteにしたものをbase64にかけていたのだと思われる。
(このやり方だと提示された結果と同じ結果が得られた)
終わりに
とりあえず動くようにはできたので満足。
担当範囲おかしくなってない?とか思ったりもするけれどGo言語の勉強にもなったのでそれで自分を納得させている。
わりとGo言語好きかもしれない。
PKCEとは、っていう記事はそこそこ見るものの、PKCEをどう対応するか、とかは少ないのでもっと増えるといいなと思ったりする。
まぁMobileはAppAuthがあるのでそれを使ったら終わりなんですが…