Skip to content
Pascal S. de Kloe edited this page Jun 19, 2022 · 4 revisions

Google

The Google Cloud exposes keys including a key ID [kid] as a JWKS.

// GoogleIAPKeys resolves the public keys from the Identity-Aware Proxy.
func GoogleIAPKeys() (*jwt.KeyRegister, error) {
        resp, err := http.Get("https://www.gstatic.com/iap/verify/public_key-jwk")
        if err != nil {
                return nil, fmt.Errorf("Google Identity-Aware Proxy public key lookup unavailable: %w", err)
        }
        defer resp.Body.Close()
        bytes, err := io.ReadAll(resp.Body)
        if err != nil {
                return nil, fmt.Errorf("Google Identity-Aware Proxy public key lookup interrupted: %w", err)
        }

        var keys jwt.KeyRegister
        n, err := keys.LoadJWK(bytes)
        if err != nil {
                return nil, fmt.Errorf("Google Identity-Aware Proxy public key lookup unusable: %w", err)
        }
        if n == 0 {
                return nil, fmt.Errorf("Google Identity-Aware Proxy public key lookup empty: %s", bytes)
        }
        return &keys, nil
}

Cloud services can apply tokens from the “assertion” header.

// IMKeys has the recognised credentials for the Identity Management service.
var IMKeys jwt.KeyRegister

// ClientCreds returns the credentials of a client request.
func ClientCreds(req *http.Request) (*jwt.Claims, error) {
	// https://cloud.google.com/iap/docs/signed-headers-howto#securing_iap_headers
	token := req.Header.Get("X-Goog-IAP-JWT-Assertion")
	if token == "" {
		return nil, fmt.Errorf("HTTP request from %s without Google Identity-Aware Proxy token", req.RemoteAddr)
	}
	claims, err := IMKeys.Check([]byte(token))
	if err != nil {
		return nil, err
	}

	const wantIssuer = "https://cloud.google.com/iap"
	if claims.Issuer != wantIssuer {
		return nil, fmt.Errorf("HTTP request from %s has Google Identity-Aware Proxy token issuer %q instead of %q", req.RemoteAddr, claims.Issuer, wantIssuer)
	}

	const skew = 30 * time.Second
	err = claims.AcceptTemporal(time.Now(), skew)
	if err != nil {
		return nil, fmt.Errorf("HTTP request from %s with bad Google Identity-Aware Proxy token: %w", req.RemoteAddr, err)
	}

	return claims, nil
}
Clone this wiki locally