netbirdio/netbird · error

authentication failed: %s

Error message

authentication failed: %s

What it means

The IdP redirected back to the local callback with the RFC 6749 error parameter set and an error_description present. This is the provider's own refusal of the authorization request, surfaced verbatim: for example 'access_denied' with a consent message, 'invalid_scope', or a tenant policy explanation from Azure AD / Auth0 / Keycloak.

Source

Thrown at client/internal/auth/pkce_flow.go:262

		}

		renderPKCEFlowTmpl(w, nil)
		tokenChan <- token
	})

	server.Handler = mux
	if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
		errChan <- err
	}
}

func (p *PKCEAuthorizationFlow) handleRequest(req *http.Request) (*oauth2.Token, error) {
	query := req.URL.Query()

	if authError := query.Get(queryError); authError != "" {
		authErrorDesc := query.Get(queryErrorDesc)
		if authErrorDesc != "" {
			return nil, fmt.Errorf("authentication failed: %s", authErrorDesc)
		}
		return nil, fmt.Errorf("authentication failed: %s", authError)
	}

	// Prevent timing attacks on the state
	if state := query.Get(queryState); subtle.ConstantTimeCompare([]byte(p.state), []byte(state)) == 0 {
		return nil, fmt.Errorf("authentication failed: Invalid state")
	}

	code := query.Get(queryCode)
	if code == "" {
		return nil, fmt.Errorf("authentication failed: missing code")
	}

	exchangeStart := time.Now()
	token, err := p.oAuthConfig.Exchange(
		req.Context(),
		code,

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Read the description text - it is the IdP's verbatim explanation and points at the exact consent or policy problem.
  2. Retry the login and complete the consent step; if consent was denied by policy, an IdP tenant admin must grant admin consent for the requested scopes.
  3. Ask the NetBird administrator to verify the IdP application's API permissions and scopes match the PKCE provider configuration.
  4. If a conditional-access or MFA policy blocks the client, satisfy the policy (compliant device, approved network) or have it relaxed for this application.
Defensive patterns

Strategy: try-catch

Try / catch

_, err := flow.WaitToken(ctx, info)
if err != nil && strings.Contains(err.Error(), "authentication failed:") {
    // err.Error() embeds the IdP's verbatim error_description;
    // surface it to the user and map known codes (access_denied, invalid_scope)
    // to remediation prompts instead of retrying blindly
}

Prevention

When it happens

Trigger: Callback query contains a non-empty error and a non-empty error_description: the user denied the consent prompt, a requested scope is not granted to the IdP application, conditional-access or MFA policy blocked the sign-in, or the application is misconfigured for the authorization-code grant.

Common situations: User cancels the consent screen; IdP app lacks admin consent for scopes such as offline_access or openid; tenant administrators disabled user consent; conditional access requires a compliant or domain-joined device; scope names in management's IdP config do not match what the app exposes.

Understand the failure class

Related errors


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