protected function validateIdToken($idToken) {
        $segments = explode('.', $idToken);
        if (count($segments) != 3) {
            throw new InvalidIdTokenException('Invalid Token');
        }
        $header = json_decode($this->decodeBase64Url($segments[0]), true);
        if (empty($header)) {
            throw new InvalidIdTokenException('Invalid Token');
        }
        $payload = json_decode($this->decodeBase64Url($segments[1]), true);
        if (empty($payload)) {
            throw new InvalidIdTokenException('Invalid Token');
        }
        $signature = $this->decodeBase64Url($segments[2]);

        $signingInput = implode('.', array($segments[0], $segments[1]));
        $kid = isset($header['kid']) ? $header['kid'] : null;
        switch ($header['alg']) {
            case 'RS256':
            case 'RS384':
            case 'RS512':
                // 署名検証用に公開鍵を取得する
                $publicKey = $this->getPublicKey($kid);

                $algo = 'sha' . substr($header['alg'], 2);
                if (openssl_verify($signingInput, $signature, $publicKey, $algo) != 1) {
                    openssl_free_key($publicKey);
                    throw new InvalidIdTokenException('Signature Mismatch');
                }
                openssl_free_key($publicKey);
                break;
            default:
                throw new InvalidIdTokenException('Unsupported Algorithm: ' . $header['alg']);
        }

        // Check Issuer
        if ($payload['iss'] != 'minecraft.jp') {
            throw new InvalidIdTokenException('Invalid Issuer.');
        }

        // Check Client Id
        if ($payload['aud'] != $this->getClientId()) {
            throw new InvalidIdTokenException('Client ID Mismatch.');
        }

        // Check expired
        $now = time();
        if ($payload['exp'] < $now || $payload['iat'] < $now - 600) {
            throw new InvalidIdTokenException('ID Token expired.');
        }

        // Check nonce
        if ($payload['nonce'] != $this->sessionStorage->read('nonce')) {
            throw new InvalidIdTokenException('Nonce Mismatch.');
        }

        $this->sessionStorage->remove('nonce');

        return $payload;
    }