When adding OAuth authz on API endpoints in FastAPI, the Swagger UI that is generated at /docs also needs to have authorization enabled. To do this, we configure an OAuth scheme of OAuth2AuthorizationCodeBearer and register a dependency on the route.

from fastapi import FastAPI, Depends  
from fastapi.security import OAuth2AuthorizationCodeBearer
 
 
app = FastAPI()
oauth2_scheme = OAuth2AuthorizationCodeBearer(  
    tokenUrl="http://keycloak.kube/realms/juju/protocol/openid-connect/token",  
    authorizationUrl="http://keycloak.kube/realms/juju/protocol/openid-connect/auth",  
    refreshUrl="http://keycloak.kube/realms/juju/protocol/openid-connect/token",
    scopes={"openid": "description"}  
)
 
 
@app.get("/auth",)  
def auth_required(token: Optional[str] = Depends(oauth2_scheme)):  
  return {"Logged in"}

This will make the “Authorize” button show up in the Swagger UI.

If you use a confidential client, you will need to specify the client ID and secret in order to authenticate. A usual confidential client in Keycloak, will have Client Authentication and Authorization enabled, with Implicit flow.

After redirecting for authentication, the token will have "azp": "<client_id>" and account details of the user. Note that the token will include the allowed-origins field. This flow is useful where you need to test client credentials.

For human users, we want to avoid needing to specify the client credentials, and instead just use the user account. For this, we need to use a public client. In Keycloak, the public client will be configured with Client Authentication and Authorization disabled with Standard flow.

When a public client is then filled in Swagger UI, the client_secret form field becomes optional and can be left empty. After redirecting for authentication, the token will have the user details, but note that there is no allowed-origins field.

The Swagger UI can be customized somewhat using the swagger_ui_init_oauth property on the FastAPI app. For example, you may wish to pre-populate the client_id and use PKCE.

from fastapi import FastAPI, Depends  
from fastapi.security import OAuth2AuthorizationCodeBearer
 
 
app = FastAPI()
swagger_ui_init_oauth = {  
  "clientId": "test-swagger-client",  
  "scopes": ["openid"],  
  "appName": "TEST SWAGGER",  
  "usePkceWithAuthorizationCodeGrant": True,  
}
app.swagger_ui_init_oauth = swagger_ui_init_oauth
 
 
@app.get("/auth",)  
def auth_required(token: Optional[str] = Depends(oauth2_scheme)):  
  return {"Logged in"}