netbirdio/netbird · error
token received is empty
Error message
token received is empty
What it means
validateTokenAudience was handed an empty token string: the flow had nothing to check. The token to use is the id_token when UseIDToken is set, otherwise the access token, so the emptiness points at which piece the IdP failed to return.
Source
Thrown at client/internal/auth/util.go:34
if err != nil {
return "", fmt.Errorf("could not generate %d random bytes: %v", count, err)
}
return hex.EncodeToString(buf), nil
}
// validateTokenAudience checks that the token is a well-formed JWT whose
// audience claim matches the expected audience.
//
// It does NOT verify the token's cryptographic signature and therefore must not
// be treated as an authenticity check. The token is obtained by the client
// directly from the IdP token endpoint over TLS, and its signature is verified
// server-side by the management server against the IdP's JWKS
// (see shared/auth/jwt/validator.go). This function is only a client-side
// sanity check that the returned token targets the expected audience.
func validateTokenAudience(token string, audience string) error {
if token == "" {
return fmt.Errorf("token received is empty")
}
parts := strings.Split(token, ".")
if len(parts) != 3 {
return fmt.Errorf("token is not a well-formed JWT")
}
claimsString, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return err
}
claims := Claims{}
err = json.Unmarshal(claimsString, &claims)
if err != nil {
return err
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Check whether 'Use ID Token' is enabled in the IdP configuration while the flow's scopes lack openid - either add the openid scope or disable UseIDToken.
- Capture (at debug level) what the token endpoint returned; an empty token in a 200 response is an IdP application configuration problem.
- Re-run the login after fixing scopes in the NetBird IdP configuration.
- If the provider cannot issue JWT access tokens at all, switch the configuration to use the id_token.
Defensive patterns
Strategy: validation
Validate before calling
// before starting the flow, confirm the configuration can yield a usable token
func tokenSourcesConfigured(cfg PKCEAuthProviderConfig) error {
if cfg.UseIDToken && !strings.Contains(cfg.Scope, "openid") {
return fmt.Errorf("UseIDToken requires the openid scope")
}
return nil
} Type guard
func hasToken(t string) bool { return t != "" } Try / catch
tokenInfo, err := flow.WaitToken(ctx, info)
if err != nil {
if strings.Contains(err.Error(), "token received is empty") {
// the IdP returned no usable token: check UseIDToken + openid scope,
// or the token endpoint response, before retrying
}
} Prevention
- Include the openid scope whenever UseIDToken is enabled.
- Validate that the IdP token endpoint returns tokens in the standard OAuth2 JSON fields.
- Alert on empty-token responses: a 200 with an empty access_token is an IdP misconfiguration.
When it happens
Trigger: The token endpoint returned a response whose access token is empty, or UseIDToken is enabled and token.Extra("id_token") was absent so IDToken stayed empty while GetTokenToUse() returned the id_token path.
Common situations: IdP application registered without the openid scope so no id_token is minted while UseIDToken is on; a misconfigured token endpoint returning an error body that parses as an empty token; provider returning tokens only in a nonstandard field.
Related errors
- validate access token failed with error: %v
- authentication failed: invalid access token - %w
- token is not a well-formed JWT
- required token field audience is absent
- connector type change not allowed
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/d109de480d18c19e.
Report an issue: GitHub.