OpenNHP/opennhp · error

failed to parse token

Error message

failed to parse token: %w

What it means

VerifyJWT first parses the JWT with ParseUnverified solely to inspect the header; if the token string is malformed (bad base64, invalid JSON segments, wrong compact form), it returns 'failed to parse token: %w'. This is a pre-verification structural check before extracting the embedded JWK. The wrapped go-jose/jwt error names the exact defect.

Solutions

  1. Log/print the token structure: it must have exactly three dot-separated base64url segments.
  2. Fix the client to emit a valid ES256 JWT signed per the COSE/JWK-embedded scheme.
  3. Check for proxy or framework munging of the Authorization header (line folding, truncation).
  4. Ensure no whitespace/newlines are embedded in the token string.
  5. Decode each segment offline (e.g. `base64 -d` after padding) to find the malformed part.

Example fix

// client side: ensure compact JWS serialization, three base64url segments
// before: sending raw key material
token := base64.StdEncoding.EncodeToString(keyBytes)
// after: produce a properly signed JWT
token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
s, _ := token.SignedString(privateKey)
Defensive patterns

Strategy: validation

Validate before calling

func looksLikeJWT(token string) bool {
	parts := strings.Split(token, ".")
	if len(parts) != 3 { return false }
	for _, p := range parts {
		if _, err := base64.RawURLEncoding.DecodeString(p); err != nil { return false }
	}
	return true
}
// call looksLikeJWT(token) before VerifyJWT

Type guard

func isWellFormedJWS(s string) bool { return strings.Count(s, ".") == 2 && len(s) > 0 }

Try / catch

token, err := VerifyJWT(rawToken)
if err != nil {
	if strings.HasPrefix(err.Error(), "failed to parse token") {
		// malformed token: return 400, ask client to re-issue
	}
}

Prevention

When it happens

Trigger: GetResource is called with an Authorization token that is not a well-formed three-part JWT: truncated token, non-base64url characters, malformed JSON in header/payload, empty string, or extra segments.

Common situations: Client sends a raw API key or an opaque session token instead of a JWT; token truncated by an intermediary (header size limits, proxy mangling); wrong encoding (standard base64 with padding instead of base64url); missing 'Bearer ' prefix handling leaving stray text.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07). Data as JSON: /api/errors/cf900875208c3476. Report an issue: GitHub.

Appendix: source

Thrown at endpoints/server/kbs/resource/resource.go:216

		return nil, nil, nil, err
	}

	iv = make([]byte, gcm.NonceSize())
	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
		return nil, nil, nil, err
	}

	ciphertext = gcm.Seal(nil, iv, plaintext, nil)

	return ciphertext, iv, nil, nil
}

func VerifyJWT(tokenString string) (*jwt.Token, error) {
	// First parse the token without verification to get the header
	parser := jwt.NewParser()
	unverifiedToken, _, err := parser.ParseUnverified(tokenString, jwt.MapClaims{})
	if err != nil {
		return nil, fmt.Errorf("failed to parse token: %w", err)
	}

	// Extract JWK from header
	jwkHeader, ok := unverifiedToken.Header["jwk"].(map[string]any)
	if !ok {
		return nil, fmt.Errorf("missing or invalid jwk in header")
	}

	// Convert JWK back to ECDSA public key
	xStr, ok := jwkHeader["x"].(string)
	if !ok {
		return nil, fmt.Errorf("missing x coordinate in jwk")
	}
	yStr, ok := jwkHeader["y"].(string)
	if !ok {
		return nil, fmt.Errorf("missing y coordinate in jwk")
	}

View on GitHub (pinned to 6e04ca5ff0)