# Python web application (Flask)

> Add OneiD to a Python application with Authlib with Flask, step by step.

Source: https://oltinid.com/docs/quickstarts/python/ · Section: Quickstarts · All OneiD documentation: https://oltinid.com/llms.txt

This quickstart adds OneiD to a server web application with **Authlib with Flask**. Every file is complete and runs as it is.

> **Tip:** Using an AI coding agent? Give it this page as Markdown (add `.md` to the address) together with the [Connector specification](https://oltinid.com/docs/ai/connector-specification/). See [Build with AI coding agents](https://oltinid.com/docs/ai/build-with-ai/).

## Before you start

- A OneiD address, for example `https://YOUR_ONEID`. The code below uses the demonstration instance `https://auth.oltinid.com`; replace it with your own.
- A client registered for this application (step 1). The code uses the client ID `quickstart`; replace it with yours.
- A user who can sign in to your OneiD. For the demonstration instance, [ask for a demo account](https://oltinid.com/contact/?topic=demo).

## 1. Register the application

Ask your OneiD administrator to register a client with these settings, or register it yourself in the admin console. See [Register an application](https://oltinid.com/docs/get-started/register-an-application/).

| Setting | Value |
|---|---|
| Client type | `public` (no secret) |
| Grant types | `authorization_code` (add `refresh_token` if you request `offline_access`) |
| Redirect URI | `http://localhost:3000/callback` |
| Post-logout redirect URI | `http://localhost:3000` |
| Allowed scopes | `openid profile email` |

## 2. Install

```bash
pip install flask authlib requests
```

## 3. Add the code

`app.py`

```python
from authlib.integrations.flask_client import OAuth
from flask import Flask, redirect, session, url_for

app = Flask(__name__)
app.secret_key = "change-me"  # signs the session cookie

oauth = OAuth(app)
oauth.register(
    name="oneid",
    # Authlib reads the endpoints and signing keys from OneiD.
    server_metadata_url="https://auth.oltinid.com/.well-known/openid-configuration",
    client_id="quickstart",
    client_kwargs={
        "scope": "openid profile email",
        "code_challenge_method": "S256",       # PKCE
        "token_endpoint_auth_method": "none",  # a public client without a secret
    },
)


@app.route("/")
def home():
    user = session.get("user")
    if user is None:
        return '<a href="/login">Sign in with OneiD</a>'
    return f'Hello, {user["name"]}. <a href="/logout">Sign out</a>'


@app.route("/login")
def login():
    return oauth.oneid.authorize_redirect(url_for("callback", _external=True))


@app.route("/callback")
def callback():
    token = oauth.oneid.authorize_access_token()  # exchanges the code and checks the ID token
    session["user"] = token["userinfo"]           # sub, name, email
    return redirect("/")


@app.route("/logout")
def logout():
    session.clear()
    return redirect("/")


if __name__ == "__main__":
    app.run(host="localhost", port=3000)
```

## 4. Run it

Run: python app.py.

The example uses a public client so that it runs without a secret. Replace the session secret key "change-me" with a random value before you use the code anywhere else.

> **Checkpoint:** Open http://localhost:3000 and select Sign in with OneiD. After you sign in, the page shows Hello, followed by the user’s name, and a Sign out link.

## Common issues

- **OneiD shows an error page about the redirect address** (`invalid_request`). The redirect URI the code sends is not registered on the client exactly as written. Register it, including scheme and port.
- **`invalid_grant` from the token endpoint.** The code was used before or expired. Start the sign-in again; do not reload the callback page.
- More errors and fixes: [Errors and troubleshooting](https://oltinid.com/docs/reference/errors/).

## Learn more

- [Authorization code flow with PKCE](https://oltinid.com/docs/guides/authorization-code-pkce/)
- [Sign-out](https://oltinid.com/docs/guides/logout/)
- [Scopes, claims and roles](https://oltinid.com/docs/guides/scopes-claims-roles/)
- [Refresh tokens](https://oltinid.com/docs/guides/refresh-tokens/)
