Skip to content

Feat/entra id confidential client#183

Open
scouturier wants to merge 10 commits intomainfrom
feat/entra-id-confidential-client
Open

Feat/entra id confidential client#183
scouturier wants to merge 10 commits intomainfrom
feat/entra-id-confidential-client

Conversation

@scouturier
Copy link
Copy Markdown
Contributor

@scouturier scouturier commented Apr 1, 2026

Issue #, if available: #179

Description of changes:

Extends the Entra ID authentication flow with two new modes alongside the existing public client:

  • Client secret — stored securely in the OS keyring; end users set it via --set-client-secret
  • Certificate — RS256 JWT client assertion built from PEM key/cert files at token exchange time; certificate takes priority over secret when both are configured

The setup wizard (init) prompts for the auth mode and stores the choice in the profile. The package command exports cert paths so packaged distributions can be pre-configured for certificate auth. Tests and Entra ID setup documentation updated accordingly.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

…179)

Adds certificate-based and client-secret confidential client auth modes for
enterprise Azure AD tenants where 'Allow public client flows' is disabled.
Public client flow (existing default) is unchanged when no new config is set.

New optional Profile fields: client_secret, client_certificate_path,
client_certificate_key_path. When certificate paths are set, authenticate_oidc
sends a signed RS256 JWT client_assertion (x5t thumbprint, 5-min lifetime)
instead of relying on public client flow. When only client_secret is set, it is
injected as a standard confidential client secret.
When provider domain resolves to azure, the wizard now asks the user to
choose between public client (existing default), client secret, or
certificate-based confidential client. Certificate mode includes inline
instructions for generating a self-signed cert with openssl.

Config round-trips correctly on re-run (existing values used as defaults).
Adds Section 5 covering both client secret and certificate-based
confidential client setup, updates Step 4.2 to explain the public vs
confidential client choice rather than blindly enabling public flows,
updates the wizard prompt example in Section 8, adds troubleshooting
entry for AADSTS7000218, and revises security best practices to
recommend certificate auth for production.
…isplay

- package.py: export client_certificate_path/key_path or client_secret to config.json when packaging a profile
- test.py: display Azure auth mode (certificate, client secret, or public client) in test command output
- credential_provider: read client secret from keyring at runtime when
  azure_auth_mode == "secret"; add --set-client-secret flag for end-user
  and MDM provisioning
- init.py: write secret to keyring during wizard, never to config;
  store azure_auth_mode field instead
- package.py: write azure_auth_mode to config.json; remove client_secret
- test.py: use azure_auth_mode from config for auth mode display
- config.py: add azure_auth_mode field to Profile
- docs: update entra-id-setup.md with per-user distribution steps and
  secret rotation guidance; add --set-client-secret to CLI_REFERENCE.md
…ient

Using "Mobile and desktop applications" platform causes Azure AD to skip
client credential enforcement, making confidential client auth appear to
succeed without a valid secret or certificate. Added explicit instructions
to use "Web" platform for confidential client setups, updated the
verification checklist, and added a troubleshooting entry for the silent
success symptom.
@scouturier scouturier requested a review from a team as a code owner April 1, 2026 15:17
if not secret:
try:
keyring.delete_password("claude-code-with-bedrock", f"{args.profile}-client-secret")
except Exception:

Check notice

Code scanning / Bandit

Try, Except, Pass detected. Note

Try, Except, Pass detected.
private_key = serialization.load_pem_private_key(key_pem, password=None)

# SHA-1 thumbprint of the DER-encoded certificate (x5t header)
thumbprint = cert.fingerprint(hashes.SHA1()) # noqa: S303 # nosec B303 # nosemgrep: python.cryptography.security.insecure-hash-algorithms.insecure-hash-algorithm-sha1 — required by OIDC spec (x5t)

Check warning

Code scanning / Semgrep OSS

Semgrep Finding: python.cryptography.security.insecure-hash-algorithms.insecure-hash-algorithm-sha1 Warning

Detected SHA1 hash algorithm which is considered insecure. SHA1 is not collision resistant and is therefore not suitable as a cryptographic signature. Use SHA256 or SHA3 instead.
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