netbirdio/netbird · error

Run `netbird profile list --show-id` to see IDs, then selec

Error message

Run `netbird profile list --show-id` to see IDs, then select by ID prefix:
  netbird profile select|remove <id-prefix>

What it means

Returned by the same callback handler when extractUserIDFromToken comes back empty after a successful token exchange. extractUserIDFromToken (auth.go:142) requires an id_token in the token response, verifies its signature and audience via provider.Verifier with ClientID, then reads the 'sub' claim; failure at any step (missing id_token, failed verification, unparseable claims) yields '' and the handler answers 401 'Failed to validate token'.

Source

Thrown at client/cmd/profile.go:322

	return nil
}

// wrapAmbiguityError turns the daemon's gRPC InvalidArgument errors
// (which carry the resolver's message verbatim) into CLI-friendly text
// that points the user at --show-id.
func wrapAmbiguityError(err error, handle string) error {
	if err == nil {
		return nil
	}
	st, ok := gstatus.FromError(err)
	if !ok {
		return err
	}
	switch st.Code() {
	case codes.InvalidArgument:
		msg := st.Message()
		if strings.Contains(msg, "ambiguous") {
			return errors.New(msg + "\nRun `netbird profile list --show-id` to see IDs, then select by ID prefix:\n  netbird profile select|remove <id-prefix>")
		}
	case codes.NotFound:
		return fmt.Errorf("profile %q not found", handle)
	}
	return err
}

// addProfileOnDaemon issues the AddProfile RPC on an existing daemon client
// and returns the new profile's ID. It is the single entry point for profile
// creation, shared by `netbird profile add` and the `netbird up --profile
// <name>` auto-create path.
func addProfileOnDaemon(ctx context.Context, client proto.DaemonServiceClient, profileName, username string) (profilemanager.ID, error) {
	resp, err := client.AddProfile(ctx, &proto.AddProfileRequest{
		ProfileName: profileName,
		Username:    username,
	})
	if err != nil {
		return "", fmt.Errorf("add profile failed: %w", err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check the management log immediately before the 401: 'No id_token in OIDC response' means the flow must request the openid scope; 'Failed to verify ID token' with 'invalid audience' means ClientID mismatch; 'Failed to extract claims' points to a malformed token.
  2. Confirm the authorization request includes scope 'openid' so the IdP returns an id_token.
  3. Verify the ClientID used for the proxy OIDC config matches the audience (aud) claim of the issued ID token.
  4. If keys rotate frequently, retry the login flow once so provider discovery and verification use the same JWKS set.

Example fix

// before: authorize URL built without the openid scope, IdP returns no id_token
authURL := oauth2Config.AuthCodeURL(state, oauth2.SetAuthURLParam("scope", "email profile"))

// after: include openid so extractUserIDFromToken gets an id_token with a sub claim
authURL := oauth2Config.AuthCodeURL(state, oauth2.SetAuthURLParam("scope", "openid email profile"))
Defensive patterns

Strategy: validation

Validate before calling

// Before redirecting users to the IdP, assert the flow will yield an id_token
// with a subject: request the openid scope and sanity-check the client ID.
if !strings.Contains(authorizeScopes, "openid") {
    return errors.New("authorize scope must include 'openid' so the callback gets an id_token")
}
if cfg.ClientID == "" {
    return errors.New("proxy OIDC client ID must be configured")
}

Prevention

When it happens

Trigger: The IdP token response omits id_token (some setups only return an access token, or the authorization request lacked the 'openid' scope); the ID token's aud does not equal the configured ClientID; the token is signed with an algorithm or key the verifier rejects (keys rotated between discovery fetch and verify); the 'sub' claim is absent or claims decoding fails.

Common situations: The OIDC authorization request was built without scope 'openid', so no ID token is issued; ClientID typo means audience mismatch ('invalid audience'); IdP signing-key rotation mid-flow; a custom IdP that issues JWTs without a 'sub' claim; clock skew breaking exp/iat verification.

Related errors


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