latch_cli.auth package#


latch_cli.auth.csrf module#

class latch_cli.auth.csrf.CSRFState[source]#

Bases: object

Context manager to hold state preventing CSRF attacks.

Outlined in detail here, this object holds a state string as a client-side protection against CSRF attacks.

Used in conjunction with PKCE verifier/challenge protection, which is a server-side security mechanism.

Example usage:

with CSRFState() as csrf:
    oauth2_flow = OAuth2(..., csrf, ...)

latch_cli.auth.oauth2 module#

class latch_cli.auth.oauth2.OAuth2(pkce: PKCE, csrf_state: CSRFState, oauth2_constants: OAuth2Constants)[source]#

Bases: object

An object to facilitate the OAuth2.0 flow.

This implementation of OAuth2.0 follows RFC5849 as gospel.

(Note we are using the PKCE extension of OAuth2, but the outline of the flow below is still a correct model if crytography is removed.)

+--------+                               +---------------+
|        |--(A)- Authorization Request ->|   Resource    |
|        |                               |     Owner     |
|        |<-(B)-- Authorization Grant ---|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(C)-- Authorization Grant -->| Authorization |
| Client |                               |     Server    |
|        |<-(D)----- Access Token -------|               |
|        |                               +---------------+
|        |
|        |                               +---------------+
|        |--(E)----- Access Token ------>|    Resource   |
|        |                               |     Server    |
|        |<-(F)--- Protected Resource ---|               |
+--------+                               +---------------+

                Figure 1: Abstract Protocol Flow

Note the correspondence between diagram letters and comments in the code example snippet below

# Note these context managers hold values critical to flows.
with PKCE() as pkce:
    with CSRFState() as csrf_state:

        # Construct our object + call each leg of the flow as a method.
        oauth2_flow = OAuth2(pkce, csrf_state, oauth2_constants)
        auth_code = oauth2_flow.authorization_request() # A + B
        token = oauth2_flow.access_token_request(auth_code) # C + D

        # With token, we can do E + F...
  • pkce – Object managing PKCE values.

  • csrf_state – Object managing state for CSRF mitigation.

  • oauth2_constants – Object holding constants to identify Latch’s authz server.

authorization_request(connection: str | None) str[source]#

Request authorization code from Latch authz server.


An authorization code to complete the first leg of 0Auth2.0.

access_token_request(auth_code: str) str[source]#

Using a valid code returned from our authz server, request token.


auth_code – Returned from our authz server if it likes us.


An access token that a user can use to access their resources on

latch (register workflows, upload files, etc.)

latch_cli.auth.pkce module#

class latch_cli.auth.pkce.PKCE[source]#

Bases: object

A Context manager to control state for PKCE flow.

The Proof Key for Code Exchange is outlined rigorously in RFC7636. The implementation in this module was written using that document as gospel. It is an extension of OAuth2.0 that adds crytographic secrets to prevent request interception.

Here is a diagram to summarize the flow (capital letters correspond to descriptions):

                                          |   Authz Server    |
+--------+                                | +---------------+ |
|        |--(A)- Authorization Request ---->|               | |
|        |       + t(code_verifier), t_m  | | Authorization | |
|        |                                | |    Endpoint   | |
|        |<-(B)---- Authorization Code -----|               | |
|        |                                | +---------------+ |
| Client |                                |                   |
|        |                                | +---------------+ |
|        |--(C)-- Access Token Request ---->|               | |
|        |          + code_verifier       | |    Token      | |
|        |                                | |   Endpoint    | |
|        |<-(D)------ Access Token ---------|               | |
+--------+                                | +---------------+ |

              Figure 2: Abstract Protocol Flow
  1. The client creates and records a secret named the “code_verifier” and derives a transformed version “t(code_verifier)” (referred to as the “code_challenge”), which is sent in the OAuth 2.0 Authorization Request along with the transformation method “t_m”.

  2. The Authorization Endpoint responds as usual but records “t(code_verifier)” and the transformation method.

  3. The client then sends the authorization code in the Access Token Request as usual but includes the “code_verifier” secret generated at (A).

  4. The authorization server transforms “code_verifier” and compares it to “t(code_verifier)” from (B). Access is denied if they are not equal.

An attacker who intercepts the authorization code at (B) is unable to redeem it for an access token, as they are not in possession of the “code_verifier” secret.

Example usage:

with PKCE() as pkce:
    oauth2_flow = OAuth2(pkce, ..)
challenge_method = 'S256'#

The challenge method used to encode the code verifier.

‘If the client is capable of using “S256”, it MUST use “S256”, as “S256” is Mandatory To Implement (MTI) on the server.’

Thus this value is hardcoded.

construct_challenge() Tuple[str, str][source]#

Construct verifier & challenge to verify a client’s identity in PKCE.

Reference RFC7636.


A cryptographically random string that is used to

correlate the authorization request to the token request.

code challenge: A challenge derived from the code verifier that is

sent in the authorization request, to be verified against later.

Return type:

code verifier

latch_cli.auth.utils module#

Authorization utilities.

Module contents#