# Flask login with Authlib

## 1. Install

`pip install authlib python-dotenv requests flask`

## 2. Env

```
AUTH0_DOMAIN YOUR-TENANT-DOMAIN
AUTH0_CLIENT_ID [your value]
AUTH0_CLIENT_SECRET [your value]
APP_SECRET_KEY [a long random string]
```

`APP_SECRET_KEY` signs the Flask session cookie. Without it (or with the dev default) sessions break or are forgeable.

## 3. OAuth registration

```
from authlib.integrations.flask_client import OAuth

oauth = OAuth(app)
oauth.register(
    "auth0",
    client_id=[your value]
    client_secret=[your value]
    client_kwargs={"scope": "openid profile email"},
    server_metadata_url="https://YOUR-TENANT-DOMAIN/.well-known/openid-configuration",
)
```

## 4. Routes

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

@app.route("/callback")
def callback():
    tok = oauth.auth0.authorize_access_token()
    session["user"] = tok["userinfo"]
    return redirect("/dashboard")

@app.route("/logout")
def logout():
    session.clear()
    return redirect(
        "https://" + os.environ["AUTH0_DOMAIN"] + "/v2/logout?"
        + urlencode({"returnTo": url_for("index", _external=True),
                     "client_id": os.environ["AUTH0_CLIENT_ID"]})
    )
```

## 5. Register URLs

Application type: Regular Web Application. Allowed Callback URLs: the absolute `/callback` URL. Allowed Logout URLs: the absolute index URL used as returnTo. Behind a proxy, set `ProxyFix` or `url_for(_external=True)` builds the wrong scheme and the callback mismatches.

## Checklist

- authorize_access_token is called exactly once per callback (double exchange fails the second time).
- Session secret set and stable; logout clears Flask session and Auth0 session.