Cognitoの認証によってAWSの権限を利用する場合、適切なIAMロールを設定することによしなに権限の検証を行ってくれる
ただ自前でリソースサーバー等を使う場合、Cognitoによって発行されたトークンを検証する必要がある
ここでは、Echoを使ったHTTPサーバーでCognitoによって発行されたトークンを検証、claimの中身を利用する
パブリックなJSON Web キー(JWK)
Cognitoではユーザーブールを作成するとパブリックなJWKが取得可能になる
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
こちらのURLにアクセスすると下記のようなJSONが取得される
{ "keys": [{ "kid": "1234example=", "alg": "RS256", "kty": "RSA", "e": "AQAB", "n": "1234567890", "use": "sig" }, { "kid": "5678example=", "alg": "RS256", "kty": "RSA", "e": "AQAB", "n": "987654321", "use": "sig" }]}
これらを用いて、発行されたトークンの検証を行う
トークンの検証
下記に証明書を利用したトークンの検証方法についてのコードを示す
package mainimport ( "context" "errors" "fmt" "net/http" jwt "github.com/golang-jwt/jwt" echo "github.com/labstack/echo/v4" middleware "github.com/labstack/echo/v4/middleware" jwk "github.com/lestrrat-go/jwx/jwk")func getKey(token *jwt.Token) (interface{}, error) { // アクセスの度にパブリックキーを取得するので注意 keySet, err := jwk.Fetch(context.Background(), fmt.Sprintf("https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json", region, userPoolID)) if err != nil { return nil, err } keyID, ok := token.Header["kid"].(string) if !ok { return nil, errors.New("expecting JWT header to have a key ID in the kid field") } key, found := keySet.LookupKeyID(keyID) if !found { return nil, fmt.Errorf("unable to find key %q", keyID) } var pubkey interface{} if err := key.Raw(&pubkey); err != nil { return nil, fmt.Errorf("Unable to get the public key. Error: %s", err.Error()) } return pubkey, nil}func restricted(c echo.Context) error { user := c.Get("user").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) name := claims["name"].(string) return c.String(http.StatusOK, "Welcome "+name+"!")}func main() { e := echo.New() // Restricted group r := e.Group("/restricted") { config := middleware.JWTConfig{ KeyFunc: getKey, } r.Use(middleware.JWTWithConfig(config)) r.GET("", restricted) } e.Logger.Fatal(e.Start(":1323"))}
今回の例だとアクセスを受ける度にJWKを取得するロジックになっているため、実運用するにはオーバーヘッドが大きい可能性がある
自分がこの辺りの仕様について詳しいわけではないが、JWK自体更新されずにCognitoのユーザープールに紐づくものであれば、ローカルにファイルを落として利用することが可能だが、更新される場合、定期的に取得する必要がある
本番環境で利用する際にはURLをキーとして、ローカルキャッシュを利用する形にしようと思う