AlistGo/alist · error
oidc: malformed jwt, expected 3 parts got %d
Error message
oidc: malformed jwt, expected 3 parts got %d
What it means
Returned by parseJWT (server/handles/ssologin.go:178) during OIDC callback handling when the id_token has fewer than 2 dot-separated segments — i.e. it is not a JWT at all. Note the guard checks len(parts) < 2 while the message says 'expected 3 parts', so a token with zero or one dot triggers it; a normal JWT (header.payload.signature) passes.
Source
Thrown at server/handles/ssologin.go:178
SsoID: userID,
}
if err = db.CreateUser(user); err != nil {
if strings.HasPrefix(err.Error(), "UNIQUE constraint failed") && strings.HasSuffix(err.Error(), "username") {
user.Username = user.Username + "_" + userID
if err = db.CreateUser(user); err != nil {
return nil, err
}
} else {
return nil, err
}
}
return user, nil
}
func parseJWT(p string) ([]byte, error) {
parts := strings.Split(p, ".")
if len(parts) < 2 {
return nil, fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts))
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("oidc: malformed jwt payload: %v", err)
}
return payload, nil
}
func OIDCLoginCallback(c *gin.Context) {
useCompatibility := setting.GetBool(conf.SSOCompatibilityMode)
method := c.Query("method")
if useCompatibility {
method = path.Base(c.Request.URL.Path)
}
clientId := setting.GetStr(conf.SSOClientId)
endpoint := setting.GetStr(conf.SSOEndpointName)
provider, err := oidc.NewProvider(c, endpoint)
if err != nil {View on GitHub (pinned to 843d9dc814)
Solutions
- Verify the OIDC provider actually issues JWT id_tokens for your client
- Inspect the raw token string at the callback for truncation or embedded whitespace
- Log the segment count and the provider response to confirm which of the above applies
- Check conf.SSOCompatibilityMode if the method is derived from the URL path
Example fix
// before idToken := resp.AccessToken // opaque token, no dots // after idToken := resp.IDToken // proper JWT: header.payload.signature
Defensive patterns
Strategy: validation
Validate before calling
func looksLikeJWT(s string) bool { return strings.Count(s, ".") >= 2 && len(s) > 0 } Try / catch
if err != nil && strings.Contains(err.Error(), "malformed jwt") { reFetchTokenAndRetry() } Prevention
- Pass resp.IDToken, not AccessToken, to JWT parsing
- Verify providers issue JWT id_tokens before relying on claims parsing
- Check tokens for truncation when crossing proxies
When it happens
Trigger: OIDC provider returns an opaque access token instead of a JWT id_token; the token string got truncated (e.g. by URL parsing on '#' or whitespace); SSO compatibility mode misreads the callback path so the wrong value is parsed as the token.
Common situations: Provider configuration requesting scope/response_type that omits id_token; proxies stripping query fragments; identity providers that return errors in the token field during outages.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- cannot get username from SSO provider
- oidc: malformed jwt payload: %v
- failed to refresh token: sub not match
- not a jwt token because of invalid segments
- failed to decode jwt token
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/3926a2dc907b6637.
Report an issue: GitHub.