v2.1.1
Two fixes on top of v2.1.0.
OAuth sign-in on mobile browsers
The session cookie that holds OAuth state shipped without the Secure flag, because SessionMiddleware was registered with Starlette's defaults. Mobile browsers drop non-Secure cookies across the redirect out to the provider and back, so the state was gone by the time the callback ran and Authlib raised MismatchingStateError. Sign-in failed with "OAuth authentication failed", almost entirely on Android browsers, 330 times since May.
Every session option is now explicit. Secure is gated on the production environment so plain-http local development still works, same_site stays lax because the provider returns the user with a top-level cross-site GET, and max_age drops from 14 days to the OAuth state TTL. That last one matters more than it looks: Starlette uses max_age as the itsdangerous signature lifetime too, so a stale cookie previously stayed cryptographically valid for a fortnight after the state it carried had expired.
This may not account for every occurrence. A second sign-in attempt overwriting the first attempt's state is a separate cause and is not addressed here.
Meta tags: the destination fetcher was not gated
GET /api/v1/metadata required auth but not the custom_meta_tags feature, while both write paths gate on it. Any authenticated caller could use it to make the server fetch arbitrary URLs regardless of entitlement. It now returns 403 without the feature, matching its siblings, and refuses before reaching URL validation, the cache or the fetch.
Versions released before v2.1.0 remain under Apache 2.0.