# 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.