netbirdio/netbird · error

validate access token failed with error: %v

Error message

validate access token failed with error: %v

What it means

Raised by DeviceAuthorizationFlow.WaitToken after a token was successfully obtained, when validateTokenAudience rejects it (device_flow.go:302-305). validateTokenAudience (client/internal/auth/util.go:32) decodes the JWT payload without signature verification and requires the aud claim (string or array) to match providerConfig.Audience. A mismatch means the IdP issued a token for a different API/audience than the one NetBird management requested.

Source

Thrown at client/internal/auth/device_flow.go:304

					log.Infof("device flow: IdP requested slow_down, polling interval increased to %s", interval)
					continue
				}

				return TokenInfo{}, errors.New(tokenResponse.ErrorDescription)
			}

			tokenInfo := TokenInfo{
				AccessToken:  tokenResponse.AccessToken,
				TokenType:    tokenResponse.TokenType,
				RefreshToken: tokenResponse.RefreshToken,
				IDToken:      tokenResponse.IDToken,
				ExpiresIn:    tokenResponse.ExpiresIn,
				UseIDToken:   d.providerConfig.UseIDToken,
			}

			err = validateTokenAudience(tokenInfo.GetTokenToUse(), d.providerConfig.Audience)
			if err != nil {
				return TokenInfo{}, fmt.Errorf("validate access token failed with error: %v", err)
			}

			log.Infof("device flow: user authorization confirmed after %d polls in %s", polls, time.Since(start).Round(time.Second))
			return tokenInfo, err
		}
	}
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Compare the aud claim of the returned token (decode the JWT payload) with the Audience configured in NetBird management - they must match exactly
  2. On Azure AD, verify the app registration's 'Application ID URI' and that the NetBird service app has the user-scope consent for that API
  3. If the IdP cannot issue JWT access tokens with the right audience, enable UseIDToken in the management IdP config so the (always JWT) ID token is validated and used instead
  4. After changing the IdP config on management, restart the login flow; cached flow state can keep requesting the old audience
Defensive patterns

Strategy: validation

Validate before calling

// Compare the token's aud claim with the configured audience before handing it on
func tokenAudienceMatches(token, want string) bool {
	parts := strings.Split(token, ".")
	if len(parts) != 3 {
		return false
	}
	claims, err := base64.RawURLEncoding.DecodeString(parts[1])
	if err != nil {
		return false
	}
	var c struct {
		Aud any `json:"aud"`
	}
	if json.Unmarshal(claims, &c) != nil {
		return false
	}
	switch aud := c.Aud.(type) {
	case string:
		return aud == want
	case []any:
		for _, a := range aud {
			if s, ok := a.(string); ok && s == want {
				return true
			}
		}
	}
	return false
}

Try / catch

token, err := flow.WaitToken(ctx, info)
if err != nil {
	if strings.Contains(err.Error(), "validate access token failed") {
		// configuration-level mismatch: point the administrator at the IdP audience settings
	}
}

Prevention

When it happens

Trigger: The token's aud claim differs from the Audience configured in the NetBird IdP settings. Concrete producers: Azure AD returning an opaque or v1-audience access token when the API audience (api://...) is not registered/granted, Auth0 audience parameter not honored because the API is not configured, or management's configured Audience not matching the IdP application's identifier URI.

Common situations: Azure AD tenants where the NetBird app registration exposes api://<client-id> but admin consent or the audience grant is missing; Auth0 where the API identifier in NetBird management differs by a trailing slash or version from the API's identifier; switching an account's IdP configuration while old clients still hold the previous audience.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/85e88c239ecc4622. Report an issue: GitHub.