authsome 0.4.1__tar.gz → 0.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (343) hide show
  1. authsome-0.4.2/.github/release-please-manifest.json +3 -0
  2. {authsome-0.4.1 → authsome-0.4.2}/CHANGELOG.md +20 -0
  3. {authsome-0.4.1 → authsome-0.4.2}/PKG-INFO +1 -1
  4. {authsome-0.4.1 → authsome-0.4.2}/pyproject.toml +1 -1
  5. {authsome-0.4.1 → authsome-0.4.2}/skills/authsome/SKILL.md +10 -5
  6. {authsome-0.4.1 → authsome-0.4.2}/skills/authsome/references/adding-provider.md +1 -1
  7. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/__init__.py +3 -3
  8. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/audit/__init__.py +2 -0
  9. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/flows/pkce.py +1 -1
  10. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/models/config.py +3 -0
  11. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/models/connection.py +6 -2
  12. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/models/provider.py +2 -0
  13. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/sessions.py +1 -1
  14. authsome-0.4.2/src/authsome/cli/admin.py +193 -0
  15. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/cli/client.py +40 -24
  16. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/cli/context.py +4 -7
  17. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/cli/daemon_control.py +1 -1
  18. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/cli/helpers.py +6 -12
  19. authsome-0.4.2/src/authsome/cli/main.py +616 -0
  20. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/identity/__init__.py +6 -0
  21. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/identity/local.py +53 -4
  22. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/identity/principal.py +2 -0
  23. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/paths.py +2 -0
  24. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/proxy/server.py +15 -8
  25. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/credential_service.py +2 -2
  26. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/auth.py +7 -4
  27. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/health.py +1 -21
  28. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/ui.py +1 -1
  29. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/schemas.py +3 -0
  30. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/ui/pages.py +48 -8
  31. authsome-0.4.2/src/authsome/store/__init__.py +5 -0
  32. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/store/interfaces.py +1 -0
  33. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/store/local.py +1 -1
  34. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/vault/__init__.py +7 -48
  35. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/vault/crypto.py +0 -92
  36. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_client_signing.py +62 -1
  37. authsome-0.4.2/tests/cli/test_daemon.py +87 -0
  38. authsome-0.4.2/tests/cli/test_doctor.py +63 -0
  39. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_get.py +27 -34
  40. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_identity.py +6 -13
  41. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_import_env.py +12 -34
  42. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_init.py +6 -9
  43. authsome-0.4.2/tests/cli/test_list.py +81 -0
  44. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_login.py +16 -26
  45. authsome-0.4.2/tests/cli/test_logout.py +35 -0
  46. authsome-0.4.2/tests/cli/test_register.py +94 -0
  47. authsome-0.4.2/tests/cli/test_revoke.py +39 -0
  48. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_whoami.py +9 -28
  49. {authsome-0.4.1 → authsome-0.4.2}/tests/identity/test_identity.py +50 -3
  50. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_pop_auth.py +0 -33
  51. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_ui_sessions.py +1 -1
  52. {authsome-0.4.1 → authsome-0.4.2}/uv.lock +3 -1
  53. authsome-0.4.1/.github/release-please-manifest.json +0 -3
  54. authsome-0.4.1/src/authsome/cli/main.py +0 -1198
  55. authsome-0.4.1/src/authsome/store/__init__.py +0 -1
  56. authsome-0.4.1/tests/cli/test_daemon.py +0 -99
  57. authsome-0.4.1/tests/cli/test_doctor.py +0 -79
  58. authsome-0.4.1/tests/cli/test_list.py +0 -198
  59. authsome-0.4.1/tests/cli/test_logout.py +0 -49
  60. authsome-0.4.1/tests/cli/test_register.py +0 -133
  61. authsome-0.4.1/tests/cli/test_revoke.py +0 -53
  62. authsome-0.4.1/tests/cli/test_ui.py +0 -23
  63. authsome-0.4.1/tests/vault/test_rekey.py +0 -167
  64. {authsome-0.4.1 → authsome-0.4.2}/.claude/commands/run-evals.md +0 -0
  65. {authsome-0.4.1 → authsome-0.4.2}/.claude-plugin/marketplace.json +0 -0
  66. {authsome-0.4.1 → authsome-0.4.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  67. {authsome-0.4.1 → authsome-0.4.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  68. {authsome-0.4.1 → authsome-0.4.2}/.github/dependabot.yml +0 -0
  69. {authsome-0.4.1 → authsome-0.4.2}/.github/pull_request_template.md +0 -0
  70. {authsome-0.4.1 → authsome-0.4.2}/.github/release-please-config.json +0 -0
  71. {authsome-0.4.1 → authsome-0.4.2}/.github/workflows/pr-title.yml +0 -0
  72. {authsome-0.4.1 → authsome-0.4.2}/.github/workflows/publish-rc.yml +0 -0
  73. {authsome-0.4.1 → authsome-0.4.2}/.github/workflows/publish.yml +0 -0
  74. {authsome-0.4.1 → authsome-0.4.2}/.github/workflows/release-please.yml +0 -0
  75. {authsome-0.4.1 → authsome-0.4.2}/.github/workflows/test.yml +0 -0
  76. {authsome-0.4.1 → authsome-0.4.2}/.gitignore +0 -0
  77. {authsome-0.4.1 → authsome-0.4.2}/.pre-commit-config.yaml +0 -0
  78. {authsome-0.4.1 → authsome-0.4.2}/AGENTS.md +0 -0
  79. {authsome-0.4.1 → authsome-0.4.2}/CLAUDE.md +0 -0
  80. {authsome-0.4.1 → authsome-0.4.2}/CONTEXT.md +0 -0
  81. {authsome-0.4.1 → authsome-0.4.2}/CONTRIBUTING.md +0 -0
  82. {authsome-0.4.1 → authsome-0.4.2}/LICENSE +0 -0
  83. {authsome-0.4.1 → authsome-0.4.2}/README.md +0 -0
  84. {authsome-0.4.1 → authsome-0.4.2}/TODOS.md +0 -0
  85. {authsome-0.4.1 → authsome-0.4.2}/assets/authsome-how-it-works-dark.svg +0 -0
  86. {authsome-0.4.1 → authsome-0.4.2}/assets/authsome-how-it-works-light.svg +0 -0
  87. {authsome-0.4.1 → authsome-0.4.2}/assets/authsome-logo-dark.svg +0 -0
  88. {authsome-0.4.1 → authsome-0.4.2}/assets/authsome-logo-light.svg +0 -0
  89. {authsome-0.4.1 → authsome-0.4.2}/docs/UBIQUITOUS_LANGUAGE.md +0 -0
  90. {authsome-0.4.1 → authsome-0.4.2}/docs/adr/0001-provider-client-record-server-scope.md +0 -0
  91. {authsome-0.4.1 → authsome-0.4.2}/docs/adr/0002-server-registered-identities.md +0 -0
  92. {authsome-0.4.1 → authsome-0.4.2}/docs/adr/0003-principal-owned-vault.md +0 -0
  93. {authsome-0.4.1 → authsome-0.4.2}/docs/adr/0003-proxy-unmatched-pass-through.md +0 -0
  94. {authsome-0.4.1 → authsome-0.4.2}/docs/agents/domain.md +0 -0
  95. {authsome-0.4.1 → authsome-0.4.2}/docs/agents/issue-tracker.md +0 -0
  96. {authsome-0.4.1 → authsome-0.4.2}/docs/agents/triage-labels.md +0 -0
  97. {authsome-0.4.1 → authsome-0.4.2}/docs/internal/authsome-design.md +0 -0
  98. {authsome-0.4.1 → authsome-0.4.2}/docs/internal/cli-design-review.md +0 -0
  99. {authsome-0.4.1 → authsome-0.4.2}/docs/internal/manual-testing.md +0 -0
  100. {authsome-0.4.1 → authsome-0.4.2}/docs/refactor.md +0 -0
  101. {authsome-0.4.1 → authsome-0.4.2}/docs/register-provider.md +0 -0
  102. {authsome-0.4.1 → authsome-0.4.2}/docs/site/README.md +0 -0
  103. {authsome-0.4.1 → authsome-0.4.2}/docs/site/changelog.mdx +0 -0
  104. {authsome-0.4.1 → authsome-0.4.2}/docs/site/compared.mdx +0 -0
  105. {authsome-0.4.1 → authsome-0.4.2}/docs/site/concepts/architecture.mdx +0 -0
  106. {authsome-0.4.1 → authsome-0.4.2}/docs/site/concepts/credential-storage.mdx +0 -0
  107. {authsome-0.4.1 → authsome-0.4.2}/docs/site/concepts/profiles-vs-connections.mdx +0 -0
  108. {authsome-0.4.1 → authsome-0.4.2}/docs/site/concepts/provider-registry.mdx +0 -0
  109. {authsome-0.4.1 → authsome-0.4.2}/docs/site/concepts/proxy-injection.mdx +0 -0
  110. {authsome-0.4.1 → authsome-0.4.2}/docs/site/concepts/the-daemon.mdx +0 -0
  111. {authsome-0.4.1 → authsome-0.4.2}/docs/site/docs.json +0 -0
  112. {authsome-0.4.1 → authsome-0.4.2}/docs/site/favicon.svg +0 -0
  113. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/custom-providers.mdx +0 -0
  114. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/headless-device-code.mdx +0 -0
  115. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/login-with-oauth.mdx +0 -0
  116. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/multiple-connections.mdx +0 -0
  117. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/profiles.mdx +0 -0
  118. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/run-agents-with-proxy.mdx +0 -0
  119. {authsome-0.4.1 → authsome-0.4.2}/docs/site/guides/use-api-keys.mdx +0 -0
  120. {authsome-0.4.1 → authsome-0.4.2}/docs/site/images/login-github-authsome.png +0 -0
  121. {authsome-0.4.1 → authsome-0.4.2}/docs/site/index.mdx +0 -0
  122. {authsome-0.4.1 → authsome-0.4.2}/docs/site/installation.mdx +0 -0
  123. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/anthropic-sdk.mdx +0 -0
  124. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/claude-code.mdx +0 -0
  125. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/codex.mdx +0 -0
  126. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/cowork.mdx +0 -0
  127. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/cursor.mdx +0 -0
  128. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/hermes.mdx +0 -0
  129. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/index.mdx +0 -0
  130. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/langchain.mdx +0 -0
  131. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/llamaindex.mdx +0 -0
  132. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/nanoclaw.mdx +0 -0
  133. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/openai-agents-sdk.mdx +0 -0
  134. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/opencode.mdx +0 -0
  135. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/agents/python.mdx +0 -0
  136. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/ahrefs.mdx +0 -0
  137. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/apollo.mdx +0 -0
  138. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/ashby.mdx +0 -0
  139. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/beehiiv.mdx +0 -0
  140. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/brevo.mdx +0 -0
  141. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/buffer.mdx +0 -0
  142. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/calendly.mdx +0 -0
  143. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/clearbit.mdx +0 -0
  144. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/dub.mdx +0 -0
  145. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/g2.mdx +0 -0
  146. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/hunter.mdx +0 -0
  147. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/index.mdx +0 -0
  148. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/instantly.mdx +0 -0
  149. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/intercom.mdx +0 -0
  150. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/keywords-everywhere.mdx +0 -0
  151. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/klaviyo.mdx +0 -0
  152. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/lemlist.mdx +0 -0
  153. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/livestorm.mdx +0 -0
  154. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/mailchimp.mdx +0 -0
  155. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/mention-me.mdx +0 -0
  156. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/openai.mdx +0 -0
  157. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/optimizely.mdx +0 -0
  158. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/postmark.mdx +0 -0
  159. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/resend.mdx +0 -0
  160. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/rewardful.mdx +0 -0
  161. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/savvycal.mdx +0 -0
  162. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/semrush.mdx +0 -0
  163. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/sendgrid.mdx +0 -0
  164. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/tolt.mdx +0 -0
  165. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/typeform.mdx +0 -0
  166. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/wistia.mdx +0 -0
  167. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/api-key/zapier.mdx +0 -0
  168. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/atlassian.mdx +0 -0
  169. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/discord.mdx +0 -0
  170. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/github.mdx +0 -0
  171. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/gitlab.mdx +0 -0
  172. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/google.mdx +0 -0
  173. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/hubspot.mdx +0 -0
  174. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/index.mdx +0 -0
  175. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/klaviyo-oauth.mdx +0 -0
  176. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/linear.mdx +0 -0
  177. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/microsoft.mdx +0 -0
  178. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/notion-dcr.mdx +0 -0
  179. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/notion.mdx +0 -0
  180. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/postiz.mdx +0 -0
  181. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/slack.mdx +0 -0
  182. {authsome-0.4.1 → authsome-0.4.2}/docs/site/integrations/oauth/x.mdx +0 -0
  183. {authsome-0.4.1 → authsome-0.4.2}/docs/site/logo/dark.svg +0 -0
  184. {authsome-0.4.1 → authsome-0.4.2}/docs/site/logo/light.svg +0 -0
  185. {authsome-0.4.1 → authsome-0.4.2}/docs/site/quickstart.mdx +0 -0
  186. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/audit-log.mdx +0 -0
  187. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/bundled-providers.mdx +0 -0
  188. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/cli.mdx +0 -0
  189. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/daemon-api.mdx +0 -0
  190. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/environment-variables.mdx +0 -0
  191. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/file-layout.mdx +0 -0
  192. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/provider-schema.mdx +0 -0
  193. {authsome-0.4.1 → authsome-0.4.2}/docs/site/reference/python-library.mdx +0 -0
  194. {authsome-0.4.1 → authsome-0.4.2}/docs/site/roadmap.mdx +0 -0
  195. {authsome-0.4.1 → authsome-0.4.2}/docs/site/security/daemon-trust-boundary.mdx +0 -0
  196. {authsome-0.4.1 → authsome-0.4.2}/docs/site/security/disclosure.mdx +0 -0
  197. {authsome-0.4.1 → authsome-0.4.2}/docs/site/security/encryption.mdx +0 -0
  198. {authsome-0.4.1 → authsome-0.4.2}/docs/site/security/hosted-deployment.mdx +0 -0
  199. {authsome-0.4.1 → authsome-0.4.2}/docs/site/security/threat-model.mdx +0 -0
  200. {authsome-0.4.1 → authsome-0.4.2}/docs/site/snippets/masked-input-note.mdx +0 -0
  201. {authsome-0.4.1 → authsome-0.4.2}/docs/site/snippets/multi-connections-cta.mdx +0 -0
  202. {authsome-0.4.1 → authsome-0.4.2}/docs/site/snippets/whats-next-apikey.mdx +0 -0
  203. {authsome-0.4.1 → authsome-0.4.2}/docs/site/snippets/whats-next-oauth.mdx +0 -0
  204. {authsome-0.4.1 → authsome-0.4.2}/docs/site/troubleshooting/auth-errors.mdx +0 -0
  205. {authsome-0.4.1 → authsome-0.4.2}/docs/site/troubleshooting/daemon-issues.mdx +0 -0
  206. {authsome-0.4.1 → authsome-0.4.2}/docs/site/troubleshooting/doctor.mdx +0 -0
  207. {authsome-0.4.1 → authsome-0.4.2}/docs/site/troubleshooting/oauth-callbacks.mdx +0 -0
  208. {authsome-0.4.1 → authsome-0.4.2}/docs/site/troubleshooting/proxy-networking.mdx +0 -0
  209. {authsome-0.4.1 → authsome-0.4.2}/docs/site/troubleshooting/token-refresh.mdx +0 -0
  210. {authsome-0.4.1 → authsome-0.4.2}/evals/.gitignore +0 -0
  211. {authsome-0.4.1 → authsome-0.4.2}/evals/evals.json +0 -0
  212. {authsome-0.4.1 → authsome-0.4.2}/evals/generate_report.py +0 -0
  213. {authsome-0.4.1 → authsome-0.4.2}/skills/authsome/references/feedback.md +0 -0
  214. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/__init__.py +0 -0
  215. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/__init__.py +0 -0
  216. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/ahrefs.json +0 -0
  217. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/apollo.json +0 -0
  218. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/ashby.json +0 -0
  219. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/atlassian.json +0 -0
  220. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/beehiiv.json +0 -0
  221. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/brevo.json +0 -0
  222. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/buffer.json +0 -0
  223. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/calendly.json +0 -0
  224. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/clearbit.json +0 -0
  225. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/discord.json +0 -0
  226. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/dub.json +0 -0
  227. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/g2.json +0 -0
  228. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/github.json +0 -0
  229. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/gitlab.json +0 -0
  230. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/google.json +0 -0
  231. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/hubspot.json +0 -0
  232. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/hunter.json +0 -0
  233. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/instantly.json +0 -0
  234. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/intercom.json +0 -0
  235. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/keywords-everywhere.json +0 -0
  236. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/klaviyo-oauth.json +0 -0
  237. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/klaviyo.json +0 -0
  238. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/lemlist.json +0 -0
  239. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/linear.json +0 -0
  240. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/livestorm.json +0 -0
  241. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/mailchimp.json +0 -0
  242. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/mention-me.json +0 -0
  243. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/microsoft.json +0 -0
  244. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/notion.json +0 -0
  245. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/notion_dcr.json +0 -0
  246. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/openai.json +0 -0
  247. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/optimizely.json +0 -0
  248. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/postiz.json +0 -0
  249. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/postmark.json +0 -0
  250. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/resend.json +0 -0
  251. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/rewardful.json +0 -0
  252. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/savvycal.json +0 -0
  253. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/semrush.json +0 -0
  254. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/sendgrid.json +0 -0
  255. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/slack.json +0 -0
  256. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/tolt.json +0 -0
  257. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/typeform.json +0 -0
  258. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/wistia.json +0 -0
  259. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/x.json +0 -0
  260. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/bundled_providers/zapier.json +0 -0
  261. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/flows/__init__.py +0 -0
  262. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/flows/api_key.py +0 -0
  263. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/flows/base.py +0 -0
  264. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/flows/dcr_pkce.py +0 -0
  265. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/flows/device_code.py +0 -0
  266. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/input_provider.py +0 -0
  267. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/models/__init__.py +0 -0
  268. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/models/enums.py +0 -0
  269. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/auth/utils.py +0 -0
  270. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/cli/__init__.py +0 -0
  271. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/cli/client_config.py +0 -0
  272. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/errors.py +0 -0
  273. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/identity/proof.py +0 -0
  274. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/identity/registry.py +0 -0
  275. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/proxy/__init__.py +0 -0
  276. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/proxy/certs.py +0 -0
  277. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/proxy/router.py +0 -0
  278. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/proxy/runner.py +0 -0
  279. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/py.typed +0 -0
  280. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/__init__.py +0 -0
  281. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/analytics.py +0 -0
  282. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/app.py +0 -0
  283. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/daemon.py +0 -0
  284. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/dependencies.py +0 -0
  285. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/hosted_auth.py +0 -0
  286. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/identity_bootstrap.py +0 -0
  287. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/ownership.py +0 -0
  288. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/proxy_catalog.py +0 -0
  289. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/registries.py +0 -0
  290. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/__init__.py +0 -0
  291. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/_deps.py +0 -0
  292. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/connections.py +0 -0
  293. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/identities.py +0 -0
  294. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/providers.py +0 -0
  295. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/routes/proxy.py +0 -0
  296. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/ui/__init__.py +0 -0
  297. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/ui/web_theme.py +0 -0
  298. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/ui_sessions.py +0 -0
  299. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/server/urls.py +0 -0
  300. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/__init__.py +0 -0
  301. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/static/app.js +0 -0
  302. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/static/style.css +0 -0
  303. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/_app_detail_shell.html +0 -0
  304. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/_layout.html +0 -0
  305. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/app_detail_apikey.html +0 -0
  306. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/app_detail_disconnected.html +0 -0
  307. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/app_detail_managed.html +0 -0
  308. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/app_detail_oauth.html +0 -0
  309. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/app_provider.html +0 -0
  310. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/applications.html +0 -0
  311. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/connections.html +0 -0
  312. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/identity.html +0 -0
  313. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/ui/templates/overview.html +0 -0
  314. {authsome-0.4.1 → authsome-0.4.2}/src/authsome/utils.py +0 -0
  315. {authsome-0.4.1 → authsome-0.4.2}/tests/__init__.py +0 -0
  316. {authsome-0.4.1 → authsome-0.4.2}/tests/auth/__init__.py +0 -0
  317. {authsome-0.4.1 → authsome-0.4.2}/tests/auth/test_flows.py +0 -0
  318. {authsome-0.4.1 → authsome-0.4.2}/tests/auth/test_models.py +0 -0
  319. {authsome-0.4.1 → authsome-0.4.2}/tests/auth/test_service.py +0 -0
  320. {authsome-0.4.1 → authsome-0.4.2}/tests/auth/test_service_provider_clients.py +0 -0
  321. {authsome-0.4.1 → authsome-0.4.2}/tests/auth/test_url_template.py +0 -0
  322. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/__init__.py +0 -0
  323. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/conftest.py +0 -0
  324. {authsome-0.4.1 → authsome-0.4.2}/tests/cli/test_helpers.py +0 -0
  325. {authsome-0.4.1 → authsome-0.4.2}/tests/common/__init__.py +0 -0
  326. {authsome-0.4.1 → authsome-0.4.2}/tests/common/test_audit.py +0 -0
  327. {authsome-0.4.1 → authsome-0.4.2}/tests/common/test_errors.py +0 -0
  328. {authsome-0.4.1 → authsome-0.4.2}/tests/common/test_logging.py +0 -0
  329. {authsome-0.4.1 → authsome-0.4.2}/tests/common/test_utils.py +0 -0
  330. {authsome-0.4.1 → authsome-0.4.2}/tests/conftest.py +0 -0
  331. {authsome-0.4.1 → authsome-0.4.2}/tests/identity/test_proof.py +0 -0
  332. {authsome-0.4.1 → authsome-0.4.2}/tests/identity/test_registry.py +0 -0
  333. {authsome-0.4.1 → authsome-0.4.2}/tests/proxy/__init__.py +0 -0
  334. {authsome-0.4.1 → authsome-0.4.2}/tests/proxy/test_proxy.py +0 -0
  335. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_analytics.py +0 -0
  336. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_auth_sessions.py +0 -0
  337. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_hosted_auth.py +0 -0
  338. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_identity_bootstrap.py +0 -0
  339. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_ownership.py +0 -0
  340. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_provider_operation_policy.py +0 -0
  341. {authsome-0.4.1 → authsome-0.4.2}/tests/server/test_ui_dashboard.py +0 -0
  342. {authsome-0.4.1 → authsome-0.4.2}/tests/vault/__init__.py +0 -0
  343. {authsome-0.4.1 → authsome-0.4.2}/tests/vault/test_crypto.py +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.4.2"
3
+ }
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.2](https://github.com/agentrhq/authsome/compare/authsome-v0.4.1...authsome-v0.4.2) (2026-05-25)
4
+
5
+
6
+ ### Features
7
+
8
+ * add device flow verification fields to auth schemas and CLI JSON output ([c24779c](https://github.com/agentrhq/authsome/commit/c24779c6df5939602f06bc3b18c5e270963cbdfc))
9
+ * auto-create env handle identities ([72e1b35](https://github.com/agentrhq/authsome/commit/72e1b350cd13cd9923eb8e2f408c599cfaf98497))
10
+ * env backed identity design ([e1662b5](https://github.com/agentrhq/authsome/commit/e1662b51963a6dac66d6d6f30f654ad04fc96736))
11
+ * improve copy-to-clipboard functionality with browser fallback and UI feedback ([02daa81](https://github.com/agentrhq/authsome/commit/02daa8182ed9d22abe75670db09286979844223d))
12
+ * restructure CLI commands under provider and admin namespaces ([7b4b31a](https://github.com/agentrhq/authsome/commit/7b4b31ad4fbc5bb8ffc2c1f60e0d69268844558e))
13
+ * restructure CLI commands under provider and admin namespaces ([a326e3f](https://github.com/agentrhq/authsome/commit/a326e3f1c43d2037124f0ba49751c8a5af0daa81))
14
+ * simplify Client ID label and implement robust cross-browser copy-to-clipboard logic ([d763f7f](https://github.com/agentrhq/authsome/commit/d763f7f7dc8bb33b7049c27be78d0cdd08195ede))
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * expose actionable session details in login --json ([87ae0b7](https://github.com/agentrhq/authsome/commit/87ae0b7aeee76b69abae13d488e9e0829031d0c8))
20
+ * normalize cli error handling for json output ([fb2754b](https://github.com/agentrhq/authsome/commit/fb2754bded00bcdea76a7433736f59ae60f01cff))
21
+ * update daemon process command to include admin subcommand ([7855c77](https://github.com/agentrhq/authsome/commit/7855c77ceec670887c1cd4947e4202aaeff3a9b2))
22
+
3
23
  ## [0.4.1](https://github.com/agentrhq/authsome/compare/authsome-v0.4.0...authsome-v0.4.1) (2026-05-25)
4
24
 
5
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: authsome
3
- Version: 0.4.1
3
+ Version: 0.4.2
4
4
  Summary: A portable local authentication library for AI agents and developer tools
5
5
  Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "authsome"
7
- version = "0.4.1"
7
+ version = "0.4.2"
8
8
  description = "A portable local authentication library for AI agents and developer tools"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -40,9 +40,9 @@ to set any auth headers.
40
40
  - Run `authsome login <provider>` via Bash yourself — do NOT ask the user to
41
41
  run this. The browser opens on their machine; they complete OAuth without touching
42
42
  the terminal.
43
- - Poll the status of the login using `authsome list` after a few seconds
43
+ - Poll the status of the login using `authsome provider list` after a few seconds
44
44
  - **If connected** — proceed normally.
45
- - **If not yet connected** — display the authentication URL to the user, ask them to complete the login in their browser, and report back once done. Once the user confirms, run `authsome list` again to verify the connection before continuing.
45
+ - **If not yet connected** — display the authentication URL to the user, ask them to complete the login in their browser, and report back once done. Once the user confirms, run `authsome provider list` again to verify the connection before continuing.
46
46
 
47
47
  ---
48
48
 
@@ -56,16 +56,16 @@ Only when uv tool install fails, use fallback: `pipx install authsome` or `uvx a
56
56
 
57
57
  ### If you get an authentication error (401, 403) follow this decision tree:
58
58
 
59
- **1. Run `authsome list` to see all providers and their connections**
59
+ **1. Run `authsome provider list` to see all providers and their connections**
60
60
 
61
61
  **2. If relevant provider exists but it has no connections → start the [login flow](#login-flow)**
62
62
 
63
- If there is a login error due to wrong client id/client secret you can delete the provider via `authsome remove <provider>` and start the [login flow](#login-flow)
63
+ If there is a login error due to wrong client id/client secret you can delete the provider via `authsome provider remove <provider>` and start the [login flow](#login-flow)
64
64
 
65
65
  **3. If relevant provider exists and it is connected**
66
66
 
67
67
  For 401 error → you need to re-login, creds have expired
68
- - revoke the creds using `authsome revoke <provider>`
68
+ - revoke the creds using `authsome provider revoke <provider>`
69
69
  - then start the [login flow](#login-flow)
70
70
 
71
71
  For 403 error → you need to re-login, with the correct scopes, or missing permissions
@@ -89,6 +89,9 @@ If you are unsure of the correct command syntax, need to check available flags,
89
89
 
90
90
  ```bash
91
91
  authsome --help
92
+ authsome provider --help
93
+ authsome connections --help
94
+ authsome admin --help
92
95
  authsome run --help
93
96
  ```
94
97
 
@@ -104,6 +107,8 @@ authsome run --help
104
107
  - **Never** suggest the user open Gmail/Calendar/GitHub in their browser
105
108
  when they ask you to read or interact with those services. You have API
106
109
  access. Use it.
110
+ - **Never** use `authsome export`, `--show-secret`, or any workflow that prints
111
+ tokens or API keys to the terminal. Use `authsome run -- ...` instead.
107
112
  - If the gateway returns a policy error (403 with a JSON body), respect
108
113
  the block. Do not retry or circumvent it.
109
114
  - If the skill fails, the goal took too many steps, the CLI behaved unexpectedly,
@@ -15,5 +15,5 @@ When the provider isn't in the bundled list, do this before writing any config:
15
15
 
16
16
  4. **Write and register the provider JSON** — follow the [provider registration guide](https://raw.githubusercontent.com/agentrhq/authsome/main/docs/register-provider.md) to write the provider JSON. Save the file to a local path (e.g. `/tmp/<provider>.json`), then register it:
17
17
  ```bash
18
- authsome register /tmp/<provider>.json
18
+ authsome provider register /tmp/<provider>.json
19
19
  ```
@@ -12,6 +12,9 @@ Usage:
12
12
  local proxy.
13
13
  """
14
14
 
15
+ from importlib.metadata import PackageNotFoundError as _PkgNotFoundError
16
+ from importlib.metadata import version as _pkg_version
17
+
15
18
  from loguru import logger as _logger
16
19
 
17
20
  from authsome.auth.models.connection import ConnectionRecord, Sensitive
@@ -39,9 +42,6 @@ from authsome.vault import Vault
39
42
  _logger.disable("authsome")
40
43
 
41
44
  try:
42
- from importlib.metadata import PackageNotFoundError as _PkgNotFoundError
43
- from importlib.metadata import version as _pkg_version
44
-
45
45
  __version__ = _pkg_version("authsome")
46
46
  except _PkgNotFoundError:
47
47
  __version__ = "unknown"
@@ -66,6 +66,7 @@ def _serialize_event(event: AuditEvent) -> str:
66
66
  return json.dumps(payload, separators=(",", ":"))
67
67
 
68
68
 
69
+ # TODO: Better to use an audit library: otel or something similar
69
70
  def log(event_type: str, **kwargs: Any) -> None:
70
71
  """Append a structured server event to the configured log file."""
71
72
  if _log_path is None:
@@ -78,6 +79,7 @@ def log(event_type: str, **kwargs: Any) -> None:
78
79
  handle.write("\n")
79
80
 
80
81
 
82
+ # FIXME: Why is there a log and alog ?
81
83
  async def alog(event_type: str, **kwargs: Any) -> None:
82
84
  """Async wrapper around structured server event logging."""
83
85
  log(event_type, **kwargs)
@@ -25,7 +25,7 @@ if TYPE_CHECKING:
25
25
  class PkceFlow(AuthFlow):
26
26
  """OAuth2 PKCE authorization code flow."""
27
27
 
28
- callback_port: int = 7999
28
+ callback_port: int = 7999 # TODO: Remove hardcoded ports, better to keep a global in config file
29
29
 
30
30
  async def begin(
31
31
  self,
@@ -7,6 +7,7 @@ from importlib.metadata import PackageNotFoundError, version
7
7
  from pydantic import BaseModel, Field
8
8
 
9
9
 
10
+ # TODO: This is generic package level function, move it there
10
11
  def current_spec_version() -> int:
11
12
  """Return the config spec version derived from authsome's minor package version."""
12
13
  try:
@@ -22,12 +23,14 @@ def current_spec_version() -> int:
22
23
  return 0
23
24
 
24
25
 
26
+ # TODO: This isn't a property of auth module
25
27
  class EncryptionConfig(BaseModel):
26
28
  """Vault encryption backend settings for the daemon."""
27
29
 
28
30
  mode: str = "auto"
29
31
 
30
32
 
33
+ # TODO: This isn't a property of auth module
31
34
  class ServerConfig(BaseModel):
32
35
  """Daemon-owned server configuration."""
33
36
 
@@ -15,7 +15,11 @@ from pydantic import BaseModel, Field
15
15
 
16
16
  from authsome.auth.models.enums import AuthType, ConnectionStatus
17
17
 
18
+ # TODO: Auth module shouldn't worry about storage. Remove all key references
19
+ # TODO: Remvoe hardcoded schema versions everywhere
18
20
 
21
+
22
+ # TODO: Pydantic as secretstr, why not just use that?
19
23
  class Sensitive:
20
24
  """Marker annotation: field contains a secret that must be redacted before display."""
21
25
 
@@ -73,8 +77,8 @@ class ProviderMetadataRecord(BaseModel):
73
77
  Stored at key: vault:<vault_id>:<provider>:metadata
74
78
  """
75
79
 
76
- schema_version: int = 2
77
- identity: str | None = None
80
+ schema_version: int = 2 # TODO: Hardcoded schema version?
81
+ identity: str | None = None # TODO: Why is identity / principal_id / vault_id in provider metadata?
78
82
  principal_id: str | None = None
79
83
  vault_id: str | None = None
80
84
  provider: str
@@ -8,6 +8,8 @@ from pydantic import BaseModel, Field
8
8
 
9
9
  from authsome.auth.models.enums import AuthType, FlowType
10
10
 
11
+ # TODO: Remove hardcoded schema versions everywhere
12
+
11
13
 
12
14
  class OAuthConfig(BaseModel):
13
15
  """OAuth2-specific provider configuration."""
@@ -34,7 +34,7 @@ class AuthSession(BaseModel):
34
34
  session_id: str
35
35
  provider: str
36
36
  identity: str | None = None
37
- principal_id: str | None = None
37
+ principal_id: str | None = None # TODO: Why is this optional ?
38
38
  connection_name: str
39
39
  flow_type: str
40
40
  state: str = AuthSessionStatus.PENDING
@@ -0,0 +1,193 @@
1
+ """Administrative CLI commands for authsome."""
2
+
3
+ import json as json_lib
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import click
9
+
10
+ from authsome.cli.context import ContextObj
11
+ from authsome.cli.daemon_control import (
12
+ DaemonAlreadyRunningError,
13
+ DaemonUnavailableError,
14
+ daemon_status,
15
+ is_daemon_responsive,
16
+ is_port_occupied,
17
+ start_daemon,
18
+ stop_daemon,
19
+ wait_for_daemon_ready,
20
+ )
21
+ from authsome.cli.helpers import auth_command
22
+ from authsome.paths import get_client_log_path, get_server_log_path
23
+
24
+
25
+ @click.group(name="admin")
26
+ def admin() -> None:
27
+ """Manage operator-facing daemon and maintenance commands."""
28
+
29
+
30
+ @admin.command(name="log")
31
+ @click.option("-n", "--lines", default=50, metavar="COUNT", help="Number of entries to show.")
32
+ @click.option("--raw", is_flag=True, help="Show raw client debug log instead of structured audit entries.")
33
+ @auth_command
34
+ async def log_cmd(ctx_obj: ContextObj, lines: int, raw: bool) -> None:
35
+ """View structured audit entries or the raw client debug log."""
36
+ home = Path(os.environ.get("AUTHSOME_HOME", str(Path.home() / ".authsome")))
37
+
38
+ if raw:
39
+ log_path = get_client_log_path(home)
40
+ try:
41
+ raw_lines = log_path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:]
42
+ except FileNotFoundError:
43
+ raw_lines = []
44
+ ctx_obj.print_json({"log_file": str(log_path), "entries": raw_lines})
45
+ return
46
+
47
+ audit_path = get_server_log_path(home)
48
+ try:
49
+ raw_lines = audit_path.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:]
50
+ except FileNotFoundError:
51
+ raw_lines = []
52
+
53
+ parsed: list[dict] = []
54
+ for line in raw_lines:
55
+ line = line.strip()
56
+ if not line:
57
+ continue
58
+ try:
59
+ parsed.append(json_lib.loads(line))
60
+ except Exception:
61
+ parsed.append({"raw": line})
62
+
63
+ ctx_obj.print_json({"log_file": str(audit_path), "entries": parsed})
64
+
65
+
66
+ @admin.group(name="daemon")
67
+ def daemon() -> None:
68
+ """Manage the local Authsome daemon."""
69
+
70
+
71
+ @daemon.command(name="serve")
72
+ @click.option("--host", default="127.0.0.1", show_default=True, metavar="HOST", help="Host interface to bind.")
73
+ @click.option("--port", default=7998, type=int, show_default=True, metavar="PORT", help="TCP port to listen on.")
74
+ @click.option("--reload", is_flag=True, help="Enable auto-reload on code changes.")
75
+ def daemon_serve(host: str, port: int, reload: bool) -> None:
76
+ """Run the daemon in the foreground."""
77
+ from authsome.server.daemon import serve
78
+
79
+ serve(host=host, port=port, reload=reload)
80
+
81
+
82
+ @daemon.command(name="start")
83
+ @auth_command
84
+ async def daemon_start(ctx_obj: ContextObj) -> None:
85
+ """Start the local daemon in the background."""
86
+ if await is_daemon_responsive():
87
+ ctx_obj.print_json({"status": "already_running", "message": "Daemon is already running."})
88
+ return
89
+
90
+ if is_port_occupied(7998):
91
+ ctx_obj.print_json(
92
+ {
93
+ "status": "port_occupied",
94
+ "message": "Port 7998 is occupied by an unrelated process. We did not start a new process.",
95
+ }
96
+ )
97
+ return
98
+
99
+ try:
100
+ start_daemon()
101
+ await wait_for_daemon_ready(timeout=5)
102
+ ctx_obj.print_json({"status": "started", "message": "Daemon started successfully."})
103
+ except DaemonAlreadyRunningError as exc:
104
+ pid_str = f" (PID: {exc.pid})" if exc.pid else ""
105
+ ctx_obj.print_json({"status": "already_running", "message": f"Daemon is already running{pid_str}."})
106
+ except DaemonUnavailableError as exc:
107
+ ctx_obj.print_json({"error": exc.__class__.__name__, "message": str(exc)})
108
+ sys.exit(1)
109
+
110
+
111
+ @daemon.command(name="stop")
112
+ @auth_command
113
+ async def daemon_stop(ctx_obj: ContextObj) -> None:
114
+ """Stop the local daemon."""
115
+ stopped, message = await stop_daemon()
116
+ status = "stopped" if stopped else "not_stopped"
117
+ ctx_obj.print_json({"status": status, "message": message})
118
+
119
+
120
+ @daemon.command(name="restart")
121
+ @auth_command
122
+ async def daemon_restart(ctx_obj: ContextObj) -> None:
123
+ """Restart the local daemon."""
124
+ stopped, message = await stop_daemon()
125
+
126
+ if await is_daemon_responsive():
127
+ ctx_obj.print_json(
128
+ {
129
+ "status": "already_running",
130
+ "message": "Daemon is already running on port 7998. We did not start a new process.",
131
+ "stop_message": message,
132
+ "stopped": stopped,
133
+ }
134
+ )
135
+ return
136
+
137
+ if is_port_occupied(7998):
138
+ ctx_obj.print_json(
139
+ {
140
+ "status": "port_occupied",
141
+ "message": "Port 7998 is occupied by an unrelated process. We did not start a new process.",
142
+ "stop_message": message,
143
+ "stopped": stopped,
144
+ }
145
+ )
146
+ return
147
+
148
+ try:
149
+ start_daemon()
150
+ await wait_for_daemon_ready(timeout=5)
151
+ ctx_obj.print_json(
152
+ {
153
+ "status": "restarted" if stopped else "started",
154
+ "message": "Daemon restarted successfully." if stopped else "New daemon started.",
155
+ "stop_message": message,
156
+ "stopped": stopped,
157
+ }
158
+ )
159
+ except DaemonAlreadyRunningError as exc:
160
+ pid_str = f" (PID: {exc.pid})" if exc.pid else ""
161
+ ctx_obj.print_json(
162
+ {
163
+ "status": "already_running",
164
+ "message": f"Daemon is already running{pid_str}.",
165
+ "stop_message": message,
166
+ "stopped": stopped,
167
+ }
168
+ )
169
+ except DaemonUnavailableError as exc:
170
+ ctx_obj.print_json({"error": exc.__class__.__name__, "message": str(exc)})
171
+ sys.exit(1)
172
+
173
+
174
+ @daemon.command(name="status")
175
+ @auth_command
176
+ async def daemon_status_cmd(ctx_obj: ContextObj) -> None:
177
+ """Show daemon status."""
178
+ status = await daemon_status()
179
+ ctx_obj.print_json(status)
180
+
181
+
182
+ @daemon.command(name="logs")
183
+ @click.option("-n", "--lines", default=80, metavar="COUNT", help="Number of lines to show.")
184
+ @auth_command
185
+ async def daemon_logs(ctx_obj: ContextObj, lines: int) -> None:
186
+ """Show daemon log output."""
187
+ from authsome.cli.daemon_control import LOG_FILE
188
+
189
+ if not LOG_FILE.exists():
190
+ ctx_obj.print_json({"log_file": str(LOG_FILE), "entries": []})
191
+ return
192
+ entries = LOG_FILE.read_text(encoding="utf-8", errors="replace").splitlines()[-lines:]
193
+ ctx_obj.print_json({"log_file": str(LOG_FILE), "entries": entries})
@@ -14,12 +14,12 @@ from urllib.parse import urlparse
14
14
  import requests
15
15
 
16
16
  from authsome.identity import (
17
- ensure_local_identity,
18
- load_private_key,
17
+ IdentitySource,
18
+ load_runtime_identity,
19
19
  mark_claimed,
20
20
  mark_registered,
21
21
  )
22
- from authsome.identity.local import IdentityMetadata
22
+ from authsome.identity.local import RuntimeIdentity, load_identity
23
23
  from authsome.identity.proof import POP_AUTH_SCHEME, create_proof_jwt
24
24
  from authsome.server.urls import DEFAULT_SERVER_BASE_URL
25
25
 
@@ -77,17 +77,6 @@ def raise_for_error(response: requests.Response) -> None:
77
77
  raise exc
78
78
 
79
79
 
80
- def _selected_identity_handle(home: Path, env: Mapping[str, str] | None = None) -> str | None:
81
- """Return the acting identity override, falling back to client config."""
82
- from authsome.cli.client_config import load_client_config
83
-
84
- values = env if env is not None else os.environ
85
- override = values.get(IDENTITY_OVERRIDE_ENV, "").strip()
86
- if override:
87
- return override
88
- return load_client_config(home).active_identity
89
-
90
-
91
80
  class AuthsomeApiClient:
92
81
  """Small typed wrapper around the daemon API."""
93
82
 
@@ -126,11 +115,16 @@ class AuthsomeApiClient:
126
115
  raise_for_error(response)
127
116
  return response.json()
128
117
 
118
+ def _runtime_identity(self) -> RuntimeIdentity:
119
+ return load_runtime_identity(self._home)
120
+
121
+ def _runtime_for_handle(self, handle: str) -> RuntimeIdentity:
122
+ return load_runtime_identity(self._home, env={IDENTITY_OVERRIDE_ENV: handle})
123
+
129
124
  async def _proof_headers(self, method: str, path: str, body: bytes) -> dict[str, str | bytes]:
130
125
  identity = await self.ensure_identity_ready()
131
- private_key = load_private_key(self._home, identity.handle)
132
126
  token = create_proof_jwt(
133
- private_key=private_key,
127
+ private_key=identity.signer,
134
128
  issuer=identity.did,
135
129
  subject=identity.handle,
136
130
  method=method,
@@ -139,16 +133,19 @@ class AuthsomeApiClient:
139
133
  )
140
134
  return {"Authorization": f"{POP_AUTH_SCHEME} {token}"}
141
135
 
142
- async def ensure_identity_ready(self) -> IdentityMetadata:
136
+ async def ensure_identity_ready(self) -> RuntimeIdentity:
143
137
  """Ensure the acting identity is registered and, in hosted mode, claimed."""
144
- identity = ensure_local_identity(self._home, active_handle=_selected_identity_handle(self._home))
138
+ runtime = self._runtime_identity()
139
+ if runtime.source is IdentitySource.ENV:
140
+ return await self._ensure_env_identity_ready(runtime)
145
141
 
146
142
  status: dict[str, Any] | None = None
143
+ identity = load_identity(self._home, runtime.handle)
147
144
  if not identity.registered:
148
145
  status = await self.register_identity(identity.handle, identity.did)
149
146
  identity = mark_registered(self._home, identity.handle)
150
147
  elif identity.claimed:
151
- return identity
148
+ return runtime
152
149
  else:
153
150
  try:
154
151
  status = await self.get_identity_status(identity.handle)
@@ -167,11 +164,33 @@ class AuthsomeApiClient:
167
164
  except Exception:
168
165
  pass
169
166
  await self._poll_claim_completion(identity.handle)
170
- return mark_claimed(self._home, identity.handle)
167
+ identity = mark_claimed(self._home, identity.handle)
168
+ return self._runtime_for_handle(identity.handle)
171
169
 
172
170
  if registration_status in {"claimed", "registered"}:
173
- return mark_claimed(self._home, identity.handle)
171
+ identity = mark_claimed(self._home, identity.handle)
172
+ return self._runtime_for_handle(identity.handle)
174
173
 
174
+ return self._runtime_for_handle(identity.handle)
175
+
176
+ async def _ensure_env_identity_ready(self, identity: RuntimeIdentity) -> RuntimeIdentity:
177
+ try:
178
+ status = await self.get_identity_status(identity.handle)
179
+ except Exception:
180
+ status = await self.register_identity(identity.handle, identity.did)
181
+
182
+ registration_status = status.get("registration_status", "registered")
183
+ if registration_status == "claim_required":
184
+ claim_url = status.get("claim_url")
185
+ if not claim_url:
186
+ status = await self.register_identity(identity.handle, identity.did)
187
+ claim_url = status.get("claim_url")
188
+ if claim_url:
189
+ try:
190
+ webbrowser.open(claim_url)
191
+ except Exception:
192
+ pass
193
+ await self._poll_claim_completion(identity.handle)
175
194
  return identity
176
195
 
177
196
  async def _poll_claim_completion(self, handle: str, *, timeout_seconds: int = 300) -> dict[str, Any]:
@@ -264,9 +283,6 @@ class AuthsomeApiClient:
264
283
  async def whoami(self) -> dict[str, Any]:
265
284
  return await self._get("/whoami")
266
285
 
267
- async def rekey(self) -> dict[str, Any]:
268
- return await self._post("/rekey", {})
269
-
270
286
  async def doctor(self) -> dict[str, Any]:
271
287
  return await self.ready()
272
288
 
@@ -54,33 +54,30 @@ class ContextObj:
54
54
  return
55
55
  if self.no_color:
56
56
  color = None
57
- click.secho(message, err=err, fg=color, nl=nl)
57
+ click.secho(message, err=err or self.json_output, fg=color, nl=nl)
58
58
 
59
59
  def emit(self, message: str, color: str | None = None, nl: bool = True) -> None:
60
60
  """Print primary data output. Never suppressed by --quiet; respects --no-color."""
61
61
  if self.no_color:
62
62
  color = None
63
- click.secho(message, fg=color, nl=nl)
63
+ click.secho(message, err=self.json_output, fg=color, nl=nl)
64
64
 
65
65
 
66
66
  pass_ctx = click.make_pass_decorator(ContextObj)
67
67
 
68
68
 
69
69
  def common_options(f):
70
- @click.option("--json", "json_output", is_flag=True, help="Output in machine-readable JSON format.")
71
70
  @click.option("--quiet", is_flag=True, help="Suppress non-essential output.")
72
71
  @click.option("--no-color", is_flag=True, help="Disable ANSI colors.")
73
72
  @functools.wraps(f)
74
73
  def wrapper(*args, **kwargs):
75
- json_output = kwargs.pop("json_output", False)
76
74
  quiet = kwargs.pop("quiet", False)
77
75
  no_color = kwargs.pop("no_color", False)
78
76
  ctx = click.get_current_context()
79
77
  if getattr(ctx, "obj", None) is None:
80
- ctx.obj = ContextObj(json_output, quiet, no_color)
78
+ ctx.obj = ContextObj(True, quiet, no_color)
81
79
  else:
82
- if json_output:
83
- ctx.obj.json_output = True
80
+ ctx.obj.json_output = True
84
81
  if quiet:
85
82
  ctx.obj.quiet = True
86
83
  if no_color:
@@ -99,7 +99,7 @@ def start_daemon() -> None:
99
99
  DAEMON_DIR.mkdir(parents=True, exist_ok=True)
100
100
  log = LOG_FILE.open("ab")
101
101
  process = subprocess.Popen(
102
- [sys.executable, "-m", "authsome.cli.main", "daemon", "serve"],
102
+ [sys.executable, "-m", "authsome.cli.main", "admin", "daemon", "serve"],
103
103
  stdout=log,
104
104
  stderr=log,
105
105
  start_new_session=True,
@@ -17,7 +17,7 @@ from authsome.utils import format_error_code
17
17
 
18
18
 
19
19
  def handle_errors(func):
20
- """Catch exceptions and print cleanly or return machine JSON."""
20
+ """Catch exceptions and return structured JSON errors."""
21
21
 
22
22
  @functools.wraps(func)
23
23
  def wrapper(ctx_obj: ContextObj, *args, **kwargs):
@@ -29,10 +29,7 @@ def handle_errors(func):
29
29
  return asyncio.run(func(ctx_obj, *args, **kwargs))
30
30
  return func(ctx_obj, *args, **kwargs)
31
31
  except Exception as exc:
32
- if ctx_obj.json_output:
33
- ctx_obj.print_json({"error": exc.__class__.__name__, "message": str(exc)})
34
- else:
35
- ctx_obj.echo(f"Error: {exc}", err=True, color="red")
32
+ ctx_obj.print_json({"error": exc.__class__.__name__, "message": str(exc)})
36
33
  sys.exit(format_error_code(exc))
37
34
 
38
35
  return wrapper
@@ -65,7 +62,7 @@ def setup_logging(verbose: bool, log_file: Path | None) -> None:
65
62
  )
66
63
 
67
64
 
68
- def _validate_provider_endpoints(definition: Any, ctx_obj: ContextObj) -> list[tuple[str, str, bool]]:
65
+ def _validate_provider_endpoints(definition: Any) -> list[tuple[str, str, bool]]:
69
66
  """Extract and validate provider endpoints for security."""
70
67
  endpoints_to_check: list[tuple[str, str, bool]] = []
71
68
  if definition.oauth:
@@ -86,21 +83,18 @@ def _validate_provider_endpoints(definition: Any, ctx_obj: ContextObj) -> list[t
86
83
  if "://" in val:
87
84
  parsed = urllib.parse.urlparse(val)
88
85
  if parsed.scheme != "https":
89
- ctx_obj.echo(f"Error: {name} must use HTTPS scheme ({val})", err=True, color="red")
90
- sys.exit(1)
86
+ raise click.ClickException(f"{name} must use HTTPS scheme ({val})")
91
87
  host = parsed.hostname
92
88
  else:
93
89
  host = val
94
90
 
95
91
  if host in ("localhost", "127.0.0.1", "::1"):
96
- ctx_obj.echo(f"Error: {name} cannot be localhost ({val})", err=True, color="red")
97
- sys.exit(1)
92
+ raise click.ClickException(f"{name} cannot be localhost ({val})")
98
93
 
99
94
  if host:
100
95
  try:
101
96
  ipaddress.ip_address(host)
102
- ctx_obj.echo(f"Error: {name} cannot be a bare IP address ({val})", err=True, color="red")
103
- sys.exit(1)
97
+ raise click.ClickException(f"{name} cannot be a bare IP address ({val})")
104
98
  except ValueError:
105
99
  pass
106
100