Starlette Integration

Starlette is a lightweight ASGI framework/toolkit, which is ideal for building high performance asyncio services.

This documentation covers OAuth 2.0 and OpenID Connect Client support for Starlette. Because all the frameworks integrations share the same API, it is best to:

Read Web Clients at first.

The difference between Starlette and Flask/Django integrations is Starlette is async. We will use await for the functions we need to call. But first, let’s create an OAuth instance:

from authlib.integrations.starlette_client import OAuth

oauth = OAuth()

The common use case for OAuth is authentication, e.g. let your users log in with Twitter, GitHub, Google etc.

Register Remote Apps

oauth.register is the same as Web Clients:

oauth.register(
    'google',
    client_id='...',
    client_secret='...',
    ...
)

However, unlike Flask/Django, Starlette OAuth registry uses HTTPX AsyncOAuth2Client as the OAuth 2.0 backend. While Flask and Django are using the Requests version of OAuth2Session.

Routes for Authorization

Just like the examples in Web Clients, but Starlette is async, the routes for authorization should look like:

@app.route('/login/google')
async def login_via_google(request):
    google = oauth.create_client('google')
    redirect_uri = request.url_for('authorize_google')
    return await google.authorize_redirect(request, redirect_uri)

@app.route('/auth/google')
async def authorize_google(request):
    google = oauth.create_client('google')
    token = await google.authorize_access_token(request)
    # do something with the token and userinfo
    return '...'

Starlette OpenID Connect

An OpenID Connect client is no different than a normal OAuth 2.0 client, just add openid scope when .register. The built-in Starlette OAuth client will handle everything automatically:

oauth.register(
    'google',
    ...
    server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
    client_kwargs={'scope': 'openid profile email'}
)

When we get the returned token:

token = await oauth.google.authorize_access_token()

There should be a id_token in the response. Authlib has called .parse_id_token automatically, we can get userinfo in the token:

userinfo = token['userinfo']

RP-Initiated Logout

To implement OpenID Connect RP-Initiated Logout, use the logout_redirect method to redirect users to the provider’s end session endpoint:

@app.route('/logout')
async def logout(request):
    # Retrieve the ID token you stored during login
    id_token = request.session.pop('id_token', None)
    redirect_uri = request.url_for('logged_out')
    return await oauth.google.logout_redirect(
        request,
        post_logout_redirect_uri=str(redirect_uri),
        id_token_hint=id_token,
    )

@app.route('/logged-out')
async def logged_out(request):
    state_data = await oauth.google.validate_logout_response(request)
    return PlainTextResponse('You have been logged out.')

The logout_redirect method accepts:

  • request: The Starlette request object (required)

  • post_logout_redirect_uri: Where to redirect after logout (must be registered with the provider)

  • id_token_hint: The ID token previously issued (recommended)

  • state: Opaque value for CSRF protection (auto-generated if not provided)

  • client_id: OAuth 2.0 Client Identifier (optional)

  • logout_hint: Hint about the user logging out (optional)

  • ui_locales: Preferred languages for the logout UI (optional)

Note

You must store the id_token during login to use it later for logout. The id_token is available in token['id_token'] after calling authorize_access_token().

Examples

We have Starlette demos at https://github.com/authlib/demo-oauth-client

  1. Starlette Google login