fatedier/frp · error
couldn't generate OIDC token for login: %v
Error message
couldn't generate OIDC token for login: %v
What it means
This is the client side of OIDC login. Before sending the Login message, OidcAuthProvider.SetLogin calls generateAccessToken, which asks the oauth2 client-credentials TokenSource for a token (via oidcTokenSource, possibly falling back to a non-caching source when the provider omits expires_in). Any failure of that token request — network error, bad client credentials, wrong token endpoint, or failing to decode the token response — surfaces here.
Source
Thrown at pkg/auth/oidc.go:191
// source. This avoids an eager network call at construction time, which
// would prevent loopLoginUntilSuccess from retrying on transient IdP
// outages.
cachingSource := tokenGenerator.TokenSource(ctx)
return &OidcAuthProvider{
additionalAuthScopes: additionalAuthScopes,
tokenSource: &oidcTokenSource{
source: cachingSource,
fallbackCfg: tokenGenerator,
fallbackCtx: ctx,
},
}, nil
}
func (auth *OidcAuthProvider) generateAccessToken() (accessToken string, err error) {
tokenObj, err := auth.tokenSource.Token()
if err != nil {
return "", fmt.Errorf("couldn't generate OIDC token for login: %v", err)
}
return tokenObj.AccessToken, nil
}
func (auth *OidcAuthProvider) SetLogin(loginMsg *msg.Login) (err error) {
loginMsg.PrivilegeKey, err = auth.generateAccessToken()
return err
}
func (auth *OidcAuthProvider) SetPing(pingMsg *msg.Ping) (err error) {
if !slices.Contains(auth.additionalAuthScopes, v1.AuthScopeHeartBeats) {
return nil
}
pingMsg.PrivilegeKey, err = auth.generateAccessToken()
return err
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Read the wrapped %v — oauth2 errors include the HTTP status and response body from the IdP
- Verify oidc.tokenEndpointURL, oidc.clientid, oidc.clientsecret in the frpc config against the IdP
- Reproduce the request manually: curl -d 'grant_type=client_credentials&client_id=...&client_secret=...' <tokenEndpointURL>
- If the IdP uses a private CA, set oidc.trustedCaFile (or temporarily test with oidc.insecureSkipVerify)
- Check network/DNS/firewall reachability of the IdP from the frpc host
Example fix
# before authentication.method = "oidc" authentication.oidc.tokenEndpointURL = "https://idp.example.com/token" # after (correct issuer path + credentials + CA) authentication.method = "oidc" authentication.oidc.tokenEndpointURL = "https://idp.example.com/realms/frp/protocol/openid-connect/token" authentication.oidc.clientid = "frp-client" authentication.oidc.clientsecret = "***" authentication.oidc.trustedCaFile = "/etc/frp/idp-ca.pem"
Defensive patterns
Strategy: retry
Try / catch
token, err := auth.generateAccessToken()
if err != nil {
if isRetryableTokenErr(err) { // network/5xx/timeouts
token, err = backoff.Retry(auth.generateAccessToken)
}
if err != nil { return fmt.Errorf("login token fetch failed: %w", err) }
} Prevention
- Smoke-test credentials with curl against the token endpoint in CI
- Configure oidc.trustedCaFile for private IdPs from day one
- Monitor frpc logs for the wrapped oauth2 error to distinguish 401 (credentials) from network failures
When it happens
Trigger: frpc with authentication.method=oidc calling SetLogin: the POST to oidc.tokenEndpointURL with client_id/client_secret fails DNS/TLS/connectivity, returns 401 (invalid client credentials), returns a non-token body, or the provider's token endpoint URL is misconfigured.
Common situations: Wrong oidc.clientid/clientsecret pair; token endpoint URL missing or mistyped; the IdP is internal and unreachable from the frpc host; the IdP's TLS cert is not trusted (no trustedCaFile set); clock skew on the client.
Related errors
- invalid OIDC token in login: %v
- token in login doesn't match token from configuration
- token in heartbeat doesn't match token from configuration
- token in NewWorkConn doesn't match token from configuration
- failed to parse OIDC proxy URL %q: %w
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/873e862ff49c9555.
Report an issue: GitHub.