Auth module¶
Reference to the auth.py module.
auth
¶
PKCE OAuth2 flow and token storage utilities for Nextmv pkce profiles.
This module contains the core (non-CLI) authentication helpers:
- PKCE authorization-code flow (:func:
run_pkce_flow, :func:refresh_tokens) - Token persistence (:func:
load_tokens, :func:save_tokens, :func:is_token_expired, :func:token_dir)
PKCE flow overview
- Fetch the OIDC discovery document to resolve
authorization_endpointandtoken_endpoint(with a hard-coded fallback for the known user pool). - Generate a
code_verifier/code_challengepair using stdlibsecretsandhashlib. - Start a temporary local HTTP server on a fixed port to receive the OAuth2 callback.
- Open the system browser at the authorization URL.
- Wait for the redirect, extract the authorization
code. - Exchange the
code+code_verifierfor tokens via a POST to the token endpoint. - Return a token dict ready for :func:
save_tokens.
Token file schema
Tokens are stored as JSON keyed by auth session name under::
~/.nextmv/auth/<session_name>/tokens.json
The session name is resolved from the auth_session field in the profile
configuration (see :func:nextmv.config.get_auth_session). When that field
is absent the reserved "default" session is used, so all profiles without
an explicit session share a single token file.
.. code-block:: json
{
"access_token": "...",
"refresh_token": "...",
"token_type": "Bearer",
"expires_at": "2026-01-01T00:00:00+00:00"
}
Constants
OIDC_DISCOVERY_URL The OIDC discovery document URL for the Nextmv Cognito user pool. CLIENT_ID The OAuth2 client ID registered in the Cognito user pool. SCOPES Space-separated OAuth2 scopes requested during the flow.
OIDC_DISCOVERY_URL
module-attribute
¶
OIDC_DISCOVERY_URL = "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_1jHS2b9HU/.well-known/openid-configuration"
apply_system_certs
¶
Patch the Python SSL module to use the operating system's certificate store and propagate the configuration to child processes.
Calls :func:truststore.inject_into_ssl, which replaces the default
ssl.create_default_context factory so that all subsequent TLS
connections (including those made by requests) trust the OS certificate
store instead of the bundled certifi CA bundle.
Also sets UV_SYSTEM_CERTS=true in the process environment so that
uv child processes also trust the OS certificate store.
This is a global, process-wide side effect. Calling it multiple times is harmless (it is idempotent).
| RAISES | DESCRIPTION |
|---|---|
ImportError
|
If the |
Source code in nextmv-py/nextmv/nextmv/auth.py
resolve_system_certs
¶
Apply system certificates if enabled via environment variable or profile config.
Resolution order:
1. NEXTMV_SYSTEM_CERTS env var (1, true, yes → enabled).
2. system_certs flag on the given profile (or the default profile).
Returns True if system certificates were applied, False otherwise.
| PARAMETER | DESCRIPTION |
|---|---|
|
The profile name. If
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
Whether system certificates were applied. |
Source code in nextmv-py/nextmv/nextmv/auth.py
token_dir
¶
Returns the directory that holds token files for session.
| PARAMETER | DESCRIPTION |
|---|---|
|
The auth session name. The reserved value
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The directory path |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If session is empty or would escape the auth directory (e.g. path traversal). |
Source code in nextmv-py/nextmv/nextmv/auth.py
load_tokens
¶
Load stored tokens for session from disk.
| PARAMETER | DESCRIPTION |
|---|---|
|
The auth session name. Resolve this from a profile via
:func:
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, Any] | None
|
The token dict, or |
Source code in nextmv-py/nextmv/nextmv/auth.py
save_tokens
¶
Persist tokens for session to disk.
Creates any missing parent directories with mode 0o700.
| PARAMETER | DESCRIPTION |
|---|---|
|
The auth session name. Resolve this from a profile via
:func:
TYPE:
|
|
The token dict to persist. Must contain at least |
Source code in nextmv-py/nextmv/nextmv/auth.py
delete_tokens
¶
Delete stored tokens for session from disk.
Silently does nothing if no token file exists.
| PARAMETER | DESCRIPTION |
|---|---|
|
The auth session name. Resolve this from a profile via
:func:
TYPE:
|
Source code in nextmv-py/nextmv/nextmv/auth.py
is_invalid_grant_error
¶
Return True if exc represents an OAuth2 invalid_grant error.
Checks for an HTTP 400 response with {"error": "invalid_grant"} in the
body, per RFC 6749 §5.2_.
.. _RFC 6749 §5.2: https://datatracker.ietf.org/doc/html/rfc6749#section-5.2
Source code in nextmv-py/nextmv/nextmv/auth.py
is_token_expired
¶
Return True when the stored access token is expired (or will expire within the
next 30 seconds), False otherwise.
If expires_at is absent the token is treated as not expired so that tokens
without an explicit expiry still work.
| PARAMETER | DESCRIPTION |
|---|---|
|
The token dict loaded from disk. |
| RETURNS | DESCRIPTION |
|---|---|
bool
|
|
Source code in nextmv-py/nextmv/nextmv/auth.py
refresh_tokens
¶
refresh_tokens(
refresh_token: str,
token_endpoint: str | None = None,
client_id: str | None = None,
oidc_discovery_url: str | None = None,
) -> dict[str, Any]
Use a refresh token to obtain a new access token.
| PARAMETER | DESCRIPTION |
|---|---|
|
A valid refresh token previously obtained via :func:
TYPE:
|
|
The token endpoint URL. If
TYPE:
|
|
The OAuth2 client ID. When
TYPE:
|
|
The OIDC discovery document URL. Used only when token_endpoint is
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, Any]
|
The refreshed token response body augmented with an |
| RAISES | DESCRIPTION |
|---|---|
HTTPError
|
If the token endpoint returns a non-2xx response. |
Source code in nextmv-py/nextmv/nextmv/auth.py
run_pkce_flow
¶
run_pkce_flow(
oidc_discovery_url: str | None = None,
client_id: str | None = None,
force: bool = False,
identity_provider: str | None = None,
) -> dict[str, Any]
Execute the full PKCE authorization-code flow.
This function:
- Resolves the OIDC endpoints.
- Generates a PKCE pair.
- Listens for the redirect callback on the fixed port
CALLBACK_PORT(56734). - Opens the system browser at the authorization URL (or the logout URL when
force=True, which clears the identity provider session and chains into a fresh login). - Waits for the redirect callback (up to
_BROWSER_TIMEOUTseconds). - Exchanges the authorization code for tokens.
| PARAMETER | DESCRIPTION |
|---|---|
|
The OIDC discovery document URL for the identity provider backing this
profile's endpoint. When
TYPE:
|
|
The OAuth2 client ID for the identity provider. When
TYPE:
|
|
When
TYPE:
|
|
When set, adds
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict[str, Any]
|
A token dict containing at minimum |
| RAISES | DESCRIPTION |
|---|---|
TimeoutError
|
If the user does not complete the browser flow within the timeout. |
RuntimeError
|
If the provider returns an error. |
HTTPError
|
If the token exchange request fails. |
Source code in nextmv-py/nextmv/nextmv/auth.py
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 | |
fetch_organizations
¶
Fetch the list of organizations (teams) the authenticated user belongs to.
Calls GET https://<endpoint>/v1/internal/me/organization and returns
the response body as a list of organization dicts.
Each dict contains at minimum:
id(str) - the team UUID; use this for thenextmv-accountheader.name(str) - the human-readable team name; show this to the user.role(str) - the user's role in the team.pending_invite(bool) - whether the user has a pending invite.
| PARAMETER | DESCRIPTION |
|---|---|
|
A valid access token (or id_token) for the authenticated user.
TYPE:
|
|
The API endpoint hostname, e.g.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[dict[str, Any]]
|
The list of organization objects returned by the API. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If endpoint uses |
HTTPError
|
If the API returns a non-2xx response. |
Source code in nextmv-py/nextmv/nextmv/auth.py
fetch_sso_provider
¶
Check whether a third-party SSO provider is enabled for domain.
Calls GET https://<endpoint>/v1/enterprise/sso/domain?domain=<domain>
(no authentication required). Returns the domain_identifier if SSO is
enabled, or None otherwise.
| PARAMETER | DESCRIPTION |
|---|---|
|
The email domain to check, e.g.
TYPE:
|
|
The API endpoint hostname, e.g.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
The |