{"record":{"id":"1a76a2e1966081ef","repo":"netbirdio/netbird","slug":"run-netbird-profile-list-show-id-to-see-ids","errorCode":null,"errorMessage":"\nRun `netbird profile list --show-id` to see IDs, then select by ID prefix:\n  netbird profile select|remove <id-prefix>","messagePattern":"\nRun `netbird profile list --show-id` to see IDs, then select by ID prefix:\n  netbird profile select\\|remove <id-prefix>","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/profile.go","lineNumber":322,"sourceCode":"\treturn nil\n}\n\n// wrapAmbiguityError turns the daemon's gRPC InvalidArgument errors\n// (which carry the resolver's message verbatim) into CLI-friendly text\n// that points the user at --show-id.\nfunc wrapAmbiguityError(err error, handle string) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\tst, ok := gstatus.FromError(err)\n\tif !ok {\n\t\treturn err\n\t}\n\tswitch st.Code() {\n\tcase codes.InvalidArgument:\n\t\tmsg := st.Message()\n\t\tif strings.Contains(msg, \"ambiguous\") {\n\t\t\treturn errors.New(msg + \"\\nRun `netbird profile list --show-id` to see IDs, then select by ID prefix:\\n  netbird profile select|remove <id-prefix>\")\n\t\t}\n\tcase codes.NotFound:\n\t\treturn fmt.Errorf(\"profile %q not found\", handle)\n\t}\n\treturn err\n}\n\n// addProfileOnDaemon issues the AddProfile RPC on an existing daemon client\n// and returns the new profile's ID. It is the single entry point for profile\n// creation, shared by `netbird profile add` and the `netbird up --profile\n// <name>` auto-create path.\nfunc addProfileOnDaemon(ctx context.Context, client proto.DaemonServiceClient, profileName, username string) (profilemanager.ID, error) {\n\tresp, err := client.AddProfile(ctx, &proto.AddProfileRequest{\n\t\tProfileName: profileName,\n\t\tUsername:    username,\n\t})\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"add profile failed: %w\", err)","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/profile.go#L304-L340","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Confirm the authorization request includes scope 'openid' so the IdP returns an id_token.","Verify the ClientID used for the proxy OIDC config matches the audience (aud) claim of the issued ID token.","If keys rotate frequently, retry the login flow once so provider discovery and verification use the same JWKS set."],"exampleFix":"// before: authorize URL built without the openid scope, IdP returns no id_token\nauthURL := oauth2Config.AuthCodeURL(state, oauth2.SetAuthURLParam(\"scope\", \"email profile\"))\n\n// after: include openid so extractUserIDFromToken gets an id_token with a sub claim\nauthURL := oauth2Config.AuthCodeURL(state, oauth2.SetAuthURLParam(\"scope\", \"openid email profile\"))","handlingStrategy":"validation","validationCode":"// Before redirecting users to the IdP, assert the flow will yield an id_token\n// with a subject: request the openid scope and sanity-check the client ID.\nif !strings.Contains(authorizeScopes, \"openid\") {\n    return errors.New(\"authorize scope must include 'openid' so the callback gets an id_token\")\n}\nif cfg.ClientID == \"\" {\n    return errors.New(\"proxy OIDC client ID must be configured\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include the openid scope in the authorize request.","Keep the ClientID exactly matching the ID token's aud claim.","On key-rotation-prone IdPs, retry the full login flow once when verification fails mid-session.","Watch for the precursor logs 'No id_token in OIDC response' / 'Failed to verify ID token' to classify the failure fast."],"tags":["oidc","jwt","claims","management","http"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}