Skip to main content

Microsoft SSO + Azure Key Vault credential management for Sanoptis Claude Code plugins.

Project description

sanoptis-auth

Microsoft SSO + Azure Key Vault credential management for Sanoptis Claude Code plugins.

A single library that any Sanoptis plugin can use to fetch its API secrets, gated by the user's normal Microsoft sign-in. No more per-plugin dotfiles, chmod gymnastics, or hand-rolled credential bootstrap docs.

Install

pip install sanoptis-auth

What it does

  • Fetches secrets from kv-sanoptis-plugins Azure Key Vault.
  • Authenticates the user via Microsoft device-code flow on first use; caches the refresh token (90 days) for subsequent calls.
  • Surfaces the login prompt as a clickable link in Claude chat (via the bundled start_sanoptis_login MCP tool) — no terminal required.
  • Enforces RBAC at the Entra security-group level: a user with sg-sanoptis-plugin-yokoy-users can fetch yokoy secrets but not DATEV secrets, even from the same machine.

Use it in a plugin

Add to your plugin's requirements.txt:

sanoptis-auth>=0.1.2

Replace any per-plugin credential loading with:

from sanoptis_auth import get_secret

api_key = get_secret("yokoy--api-key")
api_secret = get_secret("yokoy--api-secret")

Register the MCP server alongside your own in .mcp.json so users can run start_sanoptis_login from chat:

{
  "mcpServers": {
    "sanoptis-auth": {
      "command": "python",
      "args": ["-m", "sanoptis_auth.mcp_server"],
      "env": {
        "PYTHONPATH": "${CLAUDE_PLUGIN_DATA}/site-packages",
        "CLAUDE_PLUGIN_DATA": "${CLAUDE_PLUGIN_DATA}"
      }
    }
  }
}

First-time login (end user)

  1. Install the plugin in Claude Code or Cowork.
  2. Use any tool that needs a secret. Claude will say something like "Sanoptis login required — run the start_sanoptis_login tool."
  3. Run that tool. Claude shows you a clickable Microsoft device-code URL and a short code.
  4. Click the link, sign in with your Sanoptis Microsoft account, paste the code.
  5. Done — the next 90 days of plugin usage are automatic.

Local dev override

For working offline or before your Entra group membership is set up:

export SANOPTIS_AUTH_LOCAL_OVERRIDE_FILE=~/.sanoptis-auth-overrides.env
cat > ~/.sanoptis-auth-overrides.env <<'EOF'
yokoy--api-key=dev-key
yokoy--api-secret=dev-secret
EOF
chmod 600 ~/.sanoptis-auth-overrides.env

get_secret() checks this file first when the env var is set.

Adding a new secret to the vault

az login --tenant ea0bd7d3-b29f-47f4-aedc-da7b52a28ba0
az keyvault secret set --vault-name kv-sanoptis-plugins --name "myplugin--api-key" --value "..."

Or use the rotate-secrets.yml GitHub Actions workflow (workflow_dispatch) for an audited rotation.

Adding a new plugin

  1. Add a plugins entry in infra/variables.tf (e.g., "myplugin").
  2. PR → terraform-plan posts the diff (new security group + role assignments).
  3. Merge → terraform-apply provisions sg-sanoptis-plugin-myplugin-users and binds it to scoped KV secret access.
  4. Add teammates to the new group in Entra.
  5. In your plugin code: get_secret("myplugin--api-key").

Repo layout

Path Purpose
sanoptis_auth/ Python package: MSAL + KV client + MCP server
sanoptis_auth/mcp_server/ stdio MCP server exposing start_sanoptis_login and whoami
tests/ pytest suite (unit + mocked Azure)
infra/ Terraform: KV, Entra app, security groups, role assignments, GHA OIDC
.github/workflows/ CI, release, terraform plan/apply, secret rotation

Architecture decisions

  • Public client (no client secret). The Entra app uses delegated access — secrets are read as the signed-in user, not as the app. Nothing to leak or rotate at the app level.
  • Per-plugin token cache. Each plugin's ${CLAUDE_PLUGIN_DATA} dir gets its own MSAL cache. The user signs in once per plugin; refresh tokens last 90 days. Trade-off: prevents one plugin from reading another's tokens.
  • Hand-rolled MSAL over azure-identity.DefaultAzureCredential. DefaultAzureCredential tries 7 different credential chains and surfaces opaque error messages. We use msal.PublicClientApplication directly with a single device-code path — failures are explicit.
  • Group-scoped RBAC at the secret level. A user with sg-sanoptis-plugin-yokoy-users cannot read DATEV secrets even if they install the DATEV plugin. RBAC is enforced by Azure Key Vault, not by application code.
  • Terraform over Bicep. Reviewable, multi-cloud-portable, and the standard Sanoptis-BI infra tool. Runs via OIDC federated identity in CI — no service principal secret stored in GitHub Actions.

Provisioning new infrastructure

See infra/README.md for the one-time Azure bootstrap procedure (Andrej / Matthias action).

Source of truth

This repo is the only place credentials for Sanoptis Claude Code plugins should be managed. If you find a plugin reading secrets from a dotfile or environment variable, file an issue — it should be migrated to sanoptis_auth.get_secret.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sanoptis_auth-0.1.2.tar.gz (52.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sanoptis_auth-0.1.2-py3-none-any.whl (18.6 kB view details)

Uploaded Python 3

File details

Details for the file sanoptis_auth-0.1.2.tar.gz.

File metadata

  • Download URL: sanoptis_auth-0.1.2.tar.gz
  • Upload date:
  • Size: 52.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sanoptis_auth-0.1.2.tar.gz
Algorithm Hash digest
SHA256 f16b624af7db30c5c8df8aee75846193425386a4d7bae9e44660e0e5dbd8f185
MD5 513b9caf09d1b489848963aa4e9d9670
BLAKE2b-256 9c0d884c4c84f184b6881c6d0f0c1b8b82baeb592961979b93928c5f32fb60d7

See more details on using hashes here.

Provenance

The following attestation bundles were made for sanoptis_auth-0.1.2.tar.gz:

Publisher: publish.yml on Sanoptis-BI/sanoptis-auth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sanoptis_auth-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: sanoptis_auth-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 18.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sanoptis_auth-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5a4fc1453a40bc5aac0803debef4a2d455bf7b5ddfad0271411b1a7759d0af6d
MD5 1f0fd73f66821554d391734b3bc01566
BLAKE2b-256 7e7638fdff0e89ad1251a529d043defa4de05f93708557083634c3f0e3986798

See more details on using hashes here.

Provenance

The following attestation bundles were made for sanoptis_auth-0.1.2-py3-none-any.whl:

Publisher: publish.yml on Sanoptis-BI/sanoptis-auth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page