OAuth
OAuth client for the AT Protocol: public, confidential and loopback clients, with PAR, PKCE and DPoP as the OAuth specification requires.
- OAuthClient / AsyncOAuthClient
Starts an authorization, completes it from the callback, and restores or revokes stored sessions.
- OAuthSession / AsyncOAuthSession
The session of one account. Pass it to login_oauth.
Tip
For how to use these, covering the three kinds of client, session storage, token refresh and scopes, see the OAuth guide.
- class atproto_oauth.AsyncOAuthClient(client_metadata: Mapping[str, Any], *, keys: Iterable[Mapping[str, Any]] | None = None, state_store: AsyncStore[OAuthStateData] | Store[OAuthStateData] | None = None, session_store: AsyncStore[OAuthSessionData] | Store[OAuthSessionData] | None = None, id_resolver: AsyncIdResolver | None = None, transport: httpx.AsyncBaseTransport | None = None, allow_http: bool = False, lock: Callable[[str], AsyncContextManager[Any, bool | None]] | None = None, on_session_updated: Callable[[str, OAuthSessionData], Awaitable[None] | None] | None = None, on_session_deleted: Callable[[str, BaseException], Awaitable[None] | None] | None = None, state_ttl: float = 3600.0, timeout: float = 10.0)
OAuth client of the AT Protocol.
Use
loopback(),public()orconfidential()to create one without writing the client metadata by hand.- Parameters:
client_metadata โ Client metadata document.
keys โ Client authentication keys of a confidential client, as private P-256 JWKs with a
kid.state_store โ Storage of authorization requests in progress, synchronous or asynchronous. In memory by default.
session_store โ Storage of sessions, synchronous or asynchronous. In memory by default, which loses them on restart.
id_resolver โ Identity resolver.
transport โ
httpxtransport for requests to the PDS and the authorization server.allow_http โ Accept
httpURLs and loopback hosts. For development environments.lock โ Returns an asynchronous context manager that is exclusive for a DID across processes. Without it, concurrent token refreshes are only prevented within this client.
on_session_updated โ Called with the DID and the session data after a session is stored. Runs under the lock of the account, so it must not call this client for the same account. An exception it raises propagates; the session stays stored. May be a coroutine function.
on_session_deleted โ Called with the DID and the cause after a session is deleted. May be a coroutine function. Runs under the lock of the account as well.
state_ttl โ Seconds an authorization request may take.
timeout โ Timeout of requests to the PDS and the authorization server, in seconds.
- async authorize(identifier: str, *, state: str | None = None, redirect_uri: str | None = None, scope: str | None = None, **params: Any) str
Start an authorization and return the URL to send the user to.
- Parameters:
identifier โ Handle or DID of the account, or the URL of a PDS or an entryway.
state โ Application state to get back from
callback(). A web application must bind it to the browser session, see the OAuth guide.redirect_uri โ One of the registered redirect URIs. The first one by default.
scope โ Subset of the registered scope. The whole registered scope by default.
**params โ More authorization request parameters, such as
prompt.
- Returns:
Authorization URL.
- Return type:
- Raises:
ValueError โ The redirect URI, the scope or an extra parameter is not allowed.
atproto_oauth.exceptions.OAuthError โ The authorization could not be started.
- async callback(params: Mapping[str, str]) OAuthCallbackResult[AsyncOAuthSession]
Complete an authorization with the query parameters the user was redirected back with.
- Parameters:
params โ Query parameters of the redirect URI.
- Returns:
The session and the application state.
- Return type:
- Raises:
atproto_oauth.exceptions.OAuthCallbackError โ The authorization failed.
- async close() None
Close the HTTP client.
- classmethod confidential(client_id: str, redirect_uri: str | Sequence[str], scope: str, keys: Iterable[Mapping[str, Any]], metadata: Mapping[str, Any] | None = None, **kwargs: Unpack[_AsyncClientOptions]) Self
Create a confidential client.
- Parameters:
client_id โ URL the client metadata is published at.
redirect_uri โ Redirect URIs.
scope โ Scope the client may request.
keys โ Private P-256 JWKs with a
kid. The first one signs new sessions; keep the older ones for as long as sessions started with them are alive.metadata โ More client metadata fields, such as
client_nameorjwks_uri.**kwargs โ Other arguments of the client.
- async login_with_browser(identifier: str, *, open_url: Callable[[str], Any] | None = None, page: Callable[[Mapping[str, str]], str] | None = None, timeout: float | None = 300.0, **params: Any) AsyncOAuthSession
Authorize an account in the browser of this machine and return its session.
Runs a local HTTP server for the redirect back, so the client needs a redirect URI on
127.0.0.1or[::1], as a client made byloopback()has.- Parameters:
identifier โ Handle or DID of the account, or the URL of a PDS or an entryway.
open_url โ Called with the authorization URL. Opens the default browser by default.
page โ Returns the HTML shown in the browser afterwards, given the query parameters of the redirect. They come from the network, so escape any of them the page includes.
timeout โ Seconds to wait for the user.
Nonewaits forever.**params โ Other arguments of
authorize(), such asscope.
- Returns:
Session of the account.
- Return type:
- Raises:
ValueError โ The client has no loopback redirect URI.
atproto_oauth.exceptions.OAuthCallbackError โ The authorization failed or was not completed in time.
- classmethod loopback(redirect_uri: str | Sequence[str] | None = None, scope: str = 'atproto', **kwargs: Unpack[_AsyncClientOptions]) Self
Create a public client that needs no hosted metadata. For command line tools and development.
- Parameters:
redirect_uri โ Redirect URIs on
http://127.0.0.1orhttp://[::1]. The authorization server ignores the port, so it may be picked at run time.scope โ Scope the client may request.
**kwargs โ Other arguments of the client.
- classmethod public(client_id: str, redirect_uri: str | Sequence[str], scope: str, metadata: Mapping[str, Any] | None = None, **kwargs: Unpack[_AsyncClientOptions]) Self
Create a public client.
- Parameters:
client_id โ URL the client metadata is published at.
redirect_uri โ Redirect URIs.
scope โ Scope the client may request.
metadata โ More client metadata fields, such as
client_nameorapplication_type.**kwargs โ Other arguments of the client.
- property resolver: AsyncOAuthResolver
Resolver of authorization servers.
- async restore(identifier: str, refresh: RefreshMode = 'auto') AsyncOAuthSession
Load the stored session of an account.
- Parameters:
- Returns:
Session of the account.
- Return type:
- Raises:
atproto_oauth.exceptions.OAuthResolverError โ The handle could not be resolved.
atproto_oauth.exceptions.TokenRefreshError โ There is no usable session.
atproto_oauth.exceptions.AuthMethodUnsatisfiableError โ The client authentication key of the session is gone. The session is deleted.
atproto_oauth.exceptions.OAuthError โ The tokens could not be refreshed for now.
- class atproto_oauth.AsyncOAuthResolver(id_resolver: AsyncIdResolver, http: AsyncHttpClient, allow_http: bool = False)
Find the authorization server of an account or of a PDS.
- Parameters:
id_resolver โ Identity resolver.
http โ Client for requests to the PDS and the authorization server.
allow_http โ Accept
httpURLs. For development environments.
- async get_auth_server_metadata(issuer: str, no_cache: bool = False) AuthServerMetadata
Return the validated metadata of an authorization server.
- async get_resource_server_metadata(pds_url: str, no_cache: bool = False) AuthServerMetadata
Return the metadata of the authorization server that protects a PDS.
- async resolve(identifier: str) ResolvedServer
Resolve the authorization server of a handle, a DID, a PDS URL or an entryway URL.
- Raises:
atproto_oauth.exceptions.OAuthResolverError โ The identifier can not be resolved.
- async resolve_from_identity(identifier: str, no_cache: bool = False) ResolvedServer
Resolve the authorization server of a handle or a DID.
- Parameters:
identifier โ Handle or DID.
no_cache โ Bypass every cache.
- async resolve_from_service(url: str) ResolvedServer
Resolve the authorization server from the URL of a PDS, falling back to treating it as an issuer.
- async resolve_identity(identifier: str, no_cache: bool = False) ResolvedIdentity
Resolve a handle or a DID to the account it identifies.
- Parameters:
identifier โ Handle or DID.
no_cache โ Bypass the cache of the identity resolver.
- class atproto_oauth.AsyncOAuthSession(client: AsyncOAuthClient, data: OAuthSessionData)
Session of an account. Pass it to
atproto_client.AsyncClient.login_oauth().Sessions are created by
callback()andrestore().- property did: str
DID of the account.
- async get_token_info(refresh: RefreshMode = 'auto') TokenInfo
Describe the tokens of the session.
- Parameters:
refresh โ
'auto'refreshes the tokens when they are about to expire,Truealways refreshes them,Falsenever does.- Returns:
Description of the tokens, without the tokens.
- Return type:
- Raises:
atproto_oauth.exceptions.OAuthError โ The session is gone or could not be refreshed.
- property pds_endpoint: str
URL of the accountโs PDS, as of the last time the tokens were loaded.
- property permissions: ScopePermissionsTransition
Permissions the granted scope gives, as of the last time the tokens were loaded.
- async revoke() None
Revoke the session and delete it from the session store.
- class atproto_oauth.AuthMethod(method: str, kid: str | None = None)
How the client authenticates to the authorization server during a session.
- class atproto_oauth.AuthServerMetadata(issuer: str, authorization_endpoint: str, token_endpoint: str, pushed_authorization_request_endpoint: str, revocation_endpoint: str | None = None, token_endpoint_auth_methods_supported: Tuple[str, ...]=(), protected_resources: Tuple[str, ...] | None=None, raw: Dict[str, ~typing.Any]=<factory>)
Metadata of an authorization server that follows the AT Protocol OAuth profile.
- raw
The whole metadata document.
- Type:
Dict[str, Any]
- classmethod from_dict(data: Any, issuer: str, allow_http: bool = False) AuthServerMetadata
Validate a metadata document.
- Parameters:
data โ Decoded metadata document.
issuer โ Issuer the document was requested for.
allow_http โ Accept
httpURLs. For development environments.
- Raises:
atproto_oauth.exceptions.UnsupportedAuthServerError โ The server can not be used.
- class atproto_oauth.JsonFileStore(path: str | PathLike[str])
Storage in one JSON file. For command line tools and scripts used by a single account holder.
Values are written as returned by their
to_dict()and read back as dictionaries, which the OAuth clients accept.Warning
Sessions hold tokens and private keys. On POSIX systems the file is created readable by its owner only; on Windows it gets the permissions of its directory. Keep it out of version control. Concurrent processes are not coordinated.
- Parameters:
path โ Path of the file. Created on the first write.
- class atproto_oauth.LoopbackCallbackServer(redirect_uris: Sequence[str], page: Callable[[Mapping[str, str]], str] | None = None)
Local HTTP server that receives the redirect back from the authorization server.
Pass
redirect_uritoauthorizeand the result ofwait()tocallback.- Parameters:
redirect_uris โ Redirect URIs of the client. The first loopback one is served; without a port in it, the system picks a free one.
page โ Returns the HTML shown in the browser, given the query parameters of the redirect. The parameters come from the network, so escape any of them the page includes. The page is sent before the authorization is completed with
callback.
- Raises:
ValueError โ None of the redirect URIs is a loopback one.
- close() None
Stop the server.
- class atproto_oauth.MemoryStore(ttl: float | None = None, max_size: int | None = None)
In-memory storage. Thread-safe.
Warning
The content is lost on restart and is not shared between processes.
- Parameters:
ttl โ Seconds a value is kept for.
max_size โ Number of values to keep. The oldest are dropped first.
- class atproto_oauth.OAuthCallbackResult(session: SessionT, state: str | None = None)
Outcome of a completed authorization.
- state
Application state passed to
authorize.- Type:
str | None
- class atproto_oauth.OAuthClient(client_metadata: Mapping[str, Any], *, keys: Iterable[Mapping[str, Any]] | None = None, state_store: Store[OAuthStateData] | None = None, session_store: Store[OAuthSessionData] | None = None, id_resolver: IdResolver | None = None, transport: httpx.BaseTransport | None = None, allow_http: bool = False, lock: Callable[[str], ContextManager[Any, bool | None]] | None = None, on_session_updated: Callable[[str, OAuthSessionData], None] | None = None, on_session_deleted: Callable[[str, BaseException], None] | None = None, state_ttl: float = 3600.0, timeout: float = 10.0)
OAuth client of the AT Protocol.
Use
loopback(),public()orconfidential()to create one without writing the client metadata by hand.- Parameters:
client_metadata โ Client metadata document.
keys โ Client authentication keys of a confidential client, as private P-256 JWKs with a
kid.state_store โ Storage of authorization requests in progress. In memory by default.
session_store โ Storage of sessions. In memory by default, which loses them on restart.
id_resolver โ Identity resolver.
transport โ
httpxtransport for requests to the PDS and the authorization server.allow_http โ Accept
httpURLs and loopback hosts. For development environments.lock โ Returns a context manager that is exclusive for a DID across processes. Without it, concurrent token refreshes are only prevented within this client.
on_session_updated โ Called with the DID and the session data after a session is stored. Runs under the lock of the account, so it must not call this client for the same account. An exception it raises propagates; the session stays stored.
on_session_deleted โ Called with the DID and the cause after a session is deleted. Runs under the lock of the account as well.
state_ttl โ Seconds an authorization request may take.
timeout โ Timeout of requests to the PDS and the authorization server, in seconds.
- authorize(identifier: str, *, state: str | None = None, redirect_uri: str | None = None, scope: str | None = None, **params: Any) str
Start an authorization and return the URL to send the user to.
- Parameters:
identifier โ Handle or DID of the account, or the URL of a PDS or an entryway.
state โ Application state to get back from
callback(). A web application must bind it to the browser session, see the OAuth guide.redirect_uri โ One of the registered redirect URIs. The first one by default.
scope โ Subset of the registered scope. The whole registered scope by default.
**params โ More authorization request parameters, such as
prompt.
- Returns:
Authorization URL.
- Return type:
- Raises:
ValueError โ The redirect URI, the scope or an extra parameter is not allowed.
atproto_oauth.exceptions.OAuthError โ The authorization could not be started.
- callback(params: Mapping[str, str]) OAuthCallbackResult[OAuthSession]
Complete an authorization with the query parameters the user was redirected back with.
- Parameters:
params โ Query parameters of the redirect URI.
- Returns:
The session and the application state.
- Return type:
- Raises:
atproto_oauth.exceptions.OAuthCallbackError โ The authorization failed.
- close() None
Close the HTTP client.
- classmethod confidential(client_id: str, redirect_uri: str | Sequence[str], scope: str, keys: Iterable[Mapping[str, Any]], metadata: Mapping[str, Any] | None = None, **kwargs: Unpack[_ClientOptions]) Self
Create a confidential client.
- Parameters:
client_id โ URL the client metadata is published at.
redirect_uri โ Redirect URIs.
scope โ Scope the client may request.
keys โ Private P-256 JWKs with a
kid. The first one signs new sessions; keep the older ones for as long as sessions started with them are alive.metadata โ More client metadata fields, such as
client_nameorjwks_uri.**kwargs โ Other arguments of the client.
- login_with_browser(identifier: str, *, open_url: Callable[[str], Any] | None = None, page: Callable[[Mapping[str, str]], str] | None = None, timeout: float | None = 300.0, **params: Any) OAuthSession
Authorize an account in the browser of this machine and return its session.
Runs a local HTTP server for the redirect back, so the client needs a redirect URI on
127.0.0.1or[::1], as a client made byloopback()has.- Parameters:
identifier โ Handle or DID of the account, or the URL of a PDS or an entryway.
open_url โ Called with the authorization URL. Opens the default browser by default.
page โ Returns the HTML shown in the browser afterwards, given the query parameters of the redirect. They come from the network, so escape any of them the page includes.
timeout โ Seconds to wait for the user.
Nonewaits forever.**params โ Other arguments of
authorize(), such asscope.
- Returns:
Session of the account.
- Return type:
- Raises:
ValueError โ The client has no loopback redirect URI.
atproto_oauth.exceptions.OAuthCallbackError โ The authorization failed or was not completed in time.
- classmethod loopback(redirect_uri: str | Sequence[str] | None = None, scope: str = 'atproto', **kwargs: Unpack[_ClientOptions]) Self
Create a public client that needs no hosted metadata. For command line tools and development.
- Parameters:
redirect_uri โ Redirect URIs on
http://127.0.0.1orhttp://[::1]. The authorization server ignores the port, so it may be picked at run time.scope โ Scope the client may request.
**kwargs โ Other arguments of the client.
- classmethod public(client_id: str, redirect_uri: str | Sequence[str], scope: str, metadata: Mapping[str, Any] | None = None, **kwargs: Unpack[_ClientOptions]) Self
Create a public client.
- Parameters:
client_id โ URL the client metadata is published at.
redirect_uri โ Redirect URIs.
scope โ Scope the client may request.
metadata โ More client metadata fields, such as
client_nameorapplication_type.**kwargs โ Other arguments of the client.
- property resolver: OAuthResolver
Resolver of authorization servers.
- restore(identifier: str, refresh: RefreshMode = 'auto') OAuthSession
Load the stored session of an account.
- Parameters:
- Returns:
Session of the account.
- Return type:
- Raises:
atproto_oauth.exceptions.OAuthResolverError โ The handle could not be resolved.
atproto_oauth.exceptions.TokenRefreshError โ There is no usable session.
atproto_oauth.exceptions.AuthMethodUnsatisfiableError โ The client authentication key of the session is gone. The session is deleted.
atproto_oauth.exceptions.OAuthError โ The tokens could not be refreshed for now.
- class atproto_oauth.OAuthResolver(id_resolver: IdResolver, http: HttpClient, allow_http: bool = False)
Find the authorization server of an account or of a PDS.
- Parameters:
id_resolver โ Identity resolver.
http โ Client for requests to the PDS and the authorization server.
allow_http โ Accept
httpURLs. For development environments.
- get_auth_server_metadata(issuer: str, no_cache: bool = False) AuthServerMetadata
Return the validated metadata of an authorization server.
- get_resource_server_metadata(pds_url: str, no_cache: bool = False) AuthServerMetadata
Return the metadata of the authorization server that protects a PDS.
- resolve(identifier: str) ResolvedServer
Resolve the authorization server of a handle, a DID, a PDS URL or an entryway URL.
- Raises:
atproto_oauth.exceptions.OAuthResolverError โ The identifier can not be resolved.
- resolve_from_identity(identifier: str, no_cache: bool = False) ResolvedServer
Resolve the authorization server of a handle or a DID.
- Parameters:
identifier โ Handle or DID.
no_cache โ Bypass every cache.
- resolve_from_service(url: str) ResolvedServer
Resolve the authorization server from the URL of a PDS, falling back to treating it as an issuer.
- resolve_identity(identifier: str, no_cache: bool = False) ResolvedIdentity
Resolve a handle or a DID to the account it identifies.
- Parameters:
identifier โ Handle or DID.
no_cache โ Bypass the cache of the identity resolver.
- class atproto_oauth.OAuthSession(client: OAuthClient, data: OAuthSessionData)
Session of an account. Pass it to
atproto_client.Client.login_oauth().Sessions are created by
callback()andrestore().- property did: str
DID of the account.
- get_token_info(refresh: RefreshMode = 'auto') TokenInfo
Describe the tokens of the session.
- Parameters:
refresh โ
'auto'refreshes the tokens when they are about to expire,Truealways refreshes them,Falsenever does.- Returns:
Description of the tokens, without the tokens.
- Return type:
- Raises:
atproto_oauth.exceptions.OAuthError โ The session is gone or could not be refreshed.
- property pds_endpoint: str
URL of the accountโs PDS, as of the last time the tokens were loaded.
- property permissions: ScopePermissionsTransition
Permissions the granted scope gives, as of the last time the tokens were loaded.
- revoke() None
Revoke the session and delete it from the session store.
- class atproto_oauth.OAuthSessionData(dpop_jwk: Dict[str, Any], auth_method: AuthMethod, token_set: TokenSet)
Everything needed to resume a session. Stored by DID.
Warning
Contains the tokens and the private DPoP key of the session.
- classmethod from_dict(data: Mapping[str, Any]) OAuthSessionData
Restore from
to_dict(). Unknown keys are ignored.- Raises:
ValueError โ The data is not a session.
- class atproto_oauth.OAuthStateData(iss: str, dpop_jwk: Dict[str, Any], auth_method: AuthMethod, pkce_verifier: str, redirect_uri: str, created_at: float, did: str | None = None, app_state: str | None = None)
Authorization request in progress. Stored by
state.Warning
Contains the PKCE verifier and the private DPoP key of the session being created.
- classmethod from_dict(data: Mapping[str, Any]) OAuthStateData
Restore from
to_dict(). Unknown keys are ignored.- Raises:
ValueError โ The data is not an authorization request.
- class atproto_oauth.ResolvedIdentity(did: str, pds: str, handle: str | None = None)
Account an authorization flow is started for.
- handle
Handle of the account, when the DID document and the handle point at each other.
- Type:
str | None
- class atproto_oauth.ResolvedServer(server: AuthServerMetadata, identity: ResolvedIdentity | None = None)
Authorization server to send a user to.
- identity
Account the server is authoritative for.
Nonewhen resolved from a server URL.- Type:
- class atproto_oauth.TokenInfo(sub: str, iss: str, aud: str, scope: str, expires_at: datetime | None = None)
Description of the tokens of a session, without the tokens.
- expires_at
Expiration of the access token.
- Type:
datetime.datetime | None
- class atproto_oauth.TokenSet(iss: str, sub: str, aud: str, scope: str, access_token: str, token_type: str = 'DPoP', refresh_token: str | None = None, expires_at: float | None = None)
Tokens of a session.
- expires_at
Expiration of the access token as a Unix timestamp.
- Type:
float | None
- atproto_oauth.build_loopback_client_id(redirect_uris: Sequence[str] | None = None, scope: str | None = None) str
Build the
client_idof a loopback client.- Parameters:
redirect_uris โ Redirect URIs on
127.0.0.1or[::1]. The authorization server ignores the port.scope โ Scope the client may request.
- Returns:
http://localhostwith the metadata encoded in the query.- Return type:
Submodules
- atproto_oauth.scopes
AccountPermissionBlobPermissionIdentityPermissionIncludeScopeRepoPermissionRpcPermissionScopeMissingErrorScopePermissionsScopePermissions.allows_account()ScopePermissions.allows_blob()ScopePermissions.allows_identity()ScopePermissions.allows_repo()ScopePermissions.allows_rpc()ScopePermissions.assert_account()ScopePermissions.assert_blob()ScopePermissions.assert_identity()ScopePermissions.assert_repo()ScopePermissions.assert_rpc()
ScopePermissionsTransitionScopePermissionsTransition.allows_account()ScopePermissionsTransition.allows_blob()ScopePermissionsTransition.allows_repo()ScopePermissionsTransition.allows_rpc()ScopePermissionsTransition.has_transition_chat_bskyScopePermissionsTransition.has_transition_emailScopePermissionsTransition.has_transition_generic
ScopesSet