Skip to content

feat(auth): add OAuth2 client and secure token stores (#68) - #98

Open
jpsiddharth2008 wants to merge 1 commit into
nitrocloudofficial:developfrom
jpsiddharth2008:feature/issue-68-oauth-client
Open

jpsiddharth2008 wants to merge 1 commit into
nitrocloudofficial:developfrom
jpsiddharth2008:feature/issue-68-oauth-client

Conversation

@jpsiddharth2008

Copy link
Copy Markdown
Collaborator

Summary

Implements #68 by introducing a reusable OAuth2 client and token-storage APIs, adapted from the unmerged implementation in PR #4.

The client handles discovery, authorization-code exchanges, client-credentials grants, refresh, revocation and client registration. Successfully acquired or refreshed tokens are saved before returning to the caller.

What changed

Token records and storage

  • Added immutable StoredToken records and an asynchronous TokenStore protocol.
  • Added MemoryTokenStore as the client’s default storage.
  • Added FileTokenStore with atomic replacement, process-local locking, symlink rejection and POSIX 0600 permissions.
  • Preserved the previous optional encryption format and exposed encryption through nitrostack[token-encryption].
  • Retained expired records so their refresh credentials remain available.
  • Added expiry helpers using millisecond timestamps and second-based durations.
  • Preserved the one-hour fallback when expires_in is missing or None; explicit zero expires immediately.

OAuth2 client

  • Added typed configuration and public snake_case APIs.
  • Added authorization-code flows using the existing S256 PKCE implementation.
  • Added client-credentials acquisition, refresh, revocation and dynamic client registration.
  • Coalesced concurrent refreshes for the same token key into one upstream request.
  • Isolated individual waiter cancellation from the shared refresh operation.
  • Preserved refresh tokens, scopes and resource associations when omitted from refresh responses.
  • Serialized same-key refresh and revocation to prevent an in-progress refresh from restoring credentials after logout.

Discovery and security

  • Added protected-resource and authorization-server metadata discovery.
  • Kept explicitly configured endpoints authoritative over discovered values.
  • Reused CIMD’s SSRF checks and DNS-pinned connections, preserving TLS hostname verification, SNI and non-default ports.
  • Allowed generic root resource URLs while retaining CIMD’s existing non-root client-ID requirement.
  • Used standard-library urllib with worker threads, configurable timeouts, bounded responses and redirect rejection.
  • Added sanitized errors and redacted representations for credential-bearing objects.

Documentation and exports

  • Exported the client, configuration, stores, token model, helpers and error types.
  • Added usage examples, an implementation walkthrough and a verification report.
  • Documented callback-state validation, storage-key selection, encryption and concurrency boundaries.

Validation

Added 78 feature tests covering:

  • Token round trips, expiry boundaries and refresh-credential retention.
  • Plaintext/encrypted persistence, atomic-write failures and concurrent saves.
  • OAuth request encoding, client authentication and token persistence.
  • Refresh rotation, shared failures, cancellation isolation and retry.
  • Revocation, registration and discovery validation.
  • DNS pinning, TLS identity, response limits, blocked redirects and secret-safe errors.

The complete suite collects 967 tests. Full-suite runs used MCP 2.2.0, without exclusions or newly added skips/xfail markers.

Platform Python Result Coverage
Linux/WSL 3.10.21 967 passed 86.38%
Linux/WSL 3.11.16 967 passed 86.36%
Linux/WSL 3.12.14 967 passed 86.36%
Windows 3.10.21 967 passed 86.37%
Windows 3.11.16 967 passed 86.35%
Windows 3.12.14 966 passed, 1 failed 86.35%

Windows 3.12 limitation

An unchanged live localhost OAuth discovery test failed with WinError 10053. The same socket error reproduced on unchanged develop when running the existing OAuth/authentication modules together, although complete baseline runs and isolated repetitions passed.

The Windows 3.12 suite is therefore not reported as green. Reproduction commands and comparison results are recorded in docs/oauth-client-verification.md.

Additional checks passed:

  • git diff --check
  • Compilation and AST checks
  • Public-export verification
  • uv lock --check

Linux results are local WSL compatibility runs; hosted CI remains to be verified.

Boundaries

  • No new runtime HTTP client dependency.
  • No browser automation, callback listener or automatic API-request interception.
  • Applications remain responsible for validating callback state.
  • File-write coordination is process-local; refresh coordination requires a shared client instance.
  • Windows credential-file privacy relies on directory ACLs.
  • Based directly on upstream develop, without PR fix: unify HTTP factory and migrate tests to official MCP transport #36 or spillover changes.

@manish-wekan

Copy link
Copy Markdown
Collaborator

If the expires_at value is not set from the environment, then we set it as 3600 by default. And by passing 0 or null the value will not be considered/set.

@manish-wekan
manish-wekan requested a review from ROHIT-JR October 28, 2026 12:18

This branch has not been deployed

No deployments
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