pythonauthenticationfastapidigest-authentication

How do I authenticate with HTTP Digest?


I'm currently authenticating with basic, following this tutorial:

import secrets

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials,

http_basic = HTTPBasic()

def authorize_basic(credentials: HTTPBasicCredentials = Depends(http_basic)):
    correct_username = secrets.compare_digest(credentials.username, "test")
    correct_password = secrets.compare_digest(credentials.password, "test")
    if not (correct_username and correct_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Basic"},
        )

@app.get("/auth/", dependencies=[Depends(authorize_basic)])
def auth():
    return {"success": "true"}

How do I use HTTPDigest instead?


Solution

  • I know this question was asked quite a while ago but this example from the FastAPI test suite shows how to do it.

    You can rewrite the above example as follows:

    import base64
    import secrets
    
    from fastapi import Depends, FastAPI, HTTPException, Security, status
    from fastapi.security import HTTPAuthorizationCredentials, HTTPDigest
    
    http_digest = HTTPDigest()
    
    app = FastAPI()
    
    
    def authorize_digest(credentials: HTTPAuthorizationCredentials = Security(http_digest)):
        # Credentials returns the token as string.
        incoming_token = credentials.credentials
    
        # Let's say you want to generate the digest token from username and pass.
        expected_username = "test"
        expected_password = "test"
    
        # Digest tokens are encoded via base64 encoding algo.
        expected_token = base64.standard_b64encode(
            bytes(f"{expected_username}:{expected_password}", encoding="UTF-8"),
        )
    
        correct_token = secrets.compare_digest(
            bytes(incoming_token, encoding="UTF-8"),
            expected_token,
        )
        if not correct_token:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect digest token",
                headers={"WWW-Authenticate": "Digest"},
            )
    
    
    @app.get("/auth/", dependencies=[Depends(authorize_digest)])
    def auth():
        return {"success": "true"}
    
    

    You can get the token using your username and password from your shell (assuming you're using a Unix-y system):

    python -c 'import base64; h = base64.urlsafe_b64encode(b"test:test"); print(h)'
    

    This assumes that both your username and password are test. It'll print the following:

    b'dGVzdDp0ZXN0'
    

    You can use this token and send a request to this API via curl:

    curl -X 'GET' 'http://localhost:5000/auth/' \
            -H 'accept: application/json' \
            -H "Authorization: Digest dGVzdDp0ZXN0" \
            -H 'Content-Type: application/json' \
    
    

    This prints out the success response:

    {"success":"true"}