Skip to content

feat(bfabric): OAuth service accounts and RFC 7592 client management - #622

Open
Caushi wants to merge 6 commits into
refactor/auth-method-unionfrom
feature/oauth-service-accounts-on-union
Open

feat(bfabric): OAuth service accounts and RFC 7592 client management#622
Caushi wants to merge 6 commits into
refactor/auth-method-unionfrom
feature/oauth-service-accounts-on-union

Conversation

@Caushi

@Caushi Caushi commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #621 — review that first; this PR's diff is only the service-account work on top of it. Replaces #619, which targets main and predates the auth-method union.

  • Add auth_method: client_credentials, so an environment authenticates a service account from its inline client_secret and Bfabric.connect() works unattended, with no browser and no cached token.
  • Add bfabric-cli auth service-account to record one, prompting for the secret rather than taking it on the command line.
  • Add read_client, update_client and delete_client, and the auth client-show / client-update / client-delete commands, so a client registered through the CLI can be corrected or revoked later using its registration access token.
  • Add --save-env to auth register and register-webapp, recording the registration credentials needed to edit the client later. A webapp is never recorded as a service account, even when --service-user gave it the grant.
  • Change a service account's recorded scope to be requested on every token request, narrowing the token; without one the server applies the client's default. Interactive OAuth is unaffected.
  • Change auth service-account to ask before converting an existing environment to a service account, and to refuse non-interactively.
  • Change auth client-delete to clear auth_method along with the dead credentials, since a client_credentials environment without its secret cannot authenticate.
  • Change auth logout to clear a stored client secret, and auth status / auth list to report client_credentials environments.

@Caushi
Caushi force-pushed the feature/oauth-service-accounts-on-union branch 2 times, most recently from 5649796 to 6ff6d8d Compare August 25, 2026 14:24
Claudio Cannizzaro and others added 6 commits August 25, 2026 16:28
Adds an `auth_method: client_credentials` environment that authenticates from
an inline `client_secret`, so cron jobs and scripts connect without a browser
or a cached token, and `bfabric-cli auth service-account` to record one.

Registration responses can now be saved with `auth register --save-env`,
including the RFC 7592 `registration_access_token` / `registration_client_uri`.
That makes `auth client-show` / `client-update` / `client-delete` possible, so a
client registered with a wrong redirect URI is corrected in place rather than
re-registered.

Two write paths need care, both verified against the live TEST instance:

B-Fabric rotates *both* the client secret and the registration access token on
every successful update and revokes the old ones immediately (confirmed: the
previous token returns 401). Since the config writer replaces every auth-owned
key at once, writing only the rotated keys would drop the untouched ones and
strand the client unmanageable. `merge_auth_owned_keys` carries the rest along.
Rotation is detected by comparing against the stored value rather than testing
for presence, so a server echoing an unchanged credential reports nothing.

`--save-env` into an existing environment would likewise replace its stored
credentials, so it now refuses unless `--force` is passed.

Also refuses `api delete` / `api update` without a terminal to confirm on:
unattended service-account runs would otherwise hang or die on a prompt.
A client_credentials grant has no authorization step to inherit a scope
from, so the token request is the only place one can be expressed. The
service account passed scope="" and dropped the scope the operator
recorded, taking whatever the server granted by default while
`auth status` displayed the narrower scope as though it applied.

Carry `scope` on ConfigData (through the file reader and the JSON
export, so it survives BFABRICPY_CONFIG_OVERRIDE) and pass it to the
provider. An empty scope omits the parameter, keeping the server default
as the fallback.

The interactive path keeps scope="": its scope is fixed at authorization
time and a refresh inherits it, so re-requesting one could only narrow
the token below what the user consented to. A regression test pins that.
`auth service-account` rewrote auth_method on an existing environment
with no prompt, so every later connect() authenticated as the service
account instead of whoever was configured. The superseded login/password
stayed behind in the file, unreachable but still a stored secret.

Ask before converting, refuse without a terminal (matching
_confirm_repoint), and drop the superseded credentials on the way. A
re-run against an environment that is already a service account does not
prompt — that is the documented path for storing a rotated secret.

Also correct save_registration's guard docstring: it claimed the write
would strip the credentials an existing login authenticates with, which
merge_auth_owned_keys made false. The real hazard is client_id being
replaced while auth_method stays "oauth", leaving the token cache (keyed
on client_id) unable to match. Pinned by a test.
The feature was written against merge_auth_owned_keys, which the refactor replaced with an
explicit auth mode. The four call sites move to write_environment_to_config(auth="merge")
and read_environment_auth_keys, so the read-modify-write sandwich and its extra file reads
are gone.

auth client-delete now also clears auth_method when the environment was a service account:
validate_writable_environment refuses to persist client_credentials without a secret, which
is exactly the state deleting the client leaves behind.
…ve path

save_registration and _resolve_token_from_config took a plain str, so a
BaseUrl was cast back down to str at the two call sites and then
re-normalised inside save_registration. Type both on BaseUrl and
normalise once, where the CLI argument enters.

Also drops an inconsistency in cmd_login_register, which passed the
normalised URL to register_client but the raw one to save_registration.
save_registration re-read the environment it had just written to decide
whether to warn about missing registration credentials. The merge cannot add
keys the server did not return, so the response already answers the question.

Also repoint the service-account tests at from_config_data, replacing the
_connect_oauth_from_config alias dropped in the parent branch.

Claude-Session: https://claude.ai/code/session_01RZNr7BRtYpGSP4EXNgp8hk
@Caushi
Caushi force-pushed the feature/oauth-service-accounts-on-union branch from 6ff6d8d to 2eeec95 Compare August 25, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants