feat(login): appen kan logge ind og bære sin session som bearer
Første trin mod en iOS-app. Appen pakker den eksisterende flade ind og henter den fra sig selv (capacitor://localhost), så den deler aldrig origin med serveren og får aldrig cookien tilbage. Den logger derfor ind som en browser, med adgangskode og evt. kode, men får sin session i svaret i stedet for i en cookie og sender den som `Authorization: Bearer`. Det er med vilje en SESSION og ikke et API-token: den står i listen over enheder under det navn, appen giver sig selv, kan logges ud derfra, og den når 2FA og nøgler, som et token med vilje ikke gør. - `POST /auth/login` tager `client: "app"` og `device_name`. Svaret får `session_token` og ingen cookie, også mens `totp_required` er sand. - En app-session glider: hver brug flytter udløbet frem, op til `VERDANDE_APP_SESSION_TTL` (180 dage) ubrugt. En browser beholder sin faste levetid. En halvfærdig login glider ikke; den beholder sine ti minutter. - En bearer, der ikke er et API-token, slås op som session, men kun hvis den blev udstedt til appen. En browsers cookie-værdi som header må ikke blive en anden vej forbi SameSite og CSRF-låsen. - CSRF-låsen genkender appens origin. Det var prøven, der fandt det: selve login-kaldet har intet token endnu og blev afvist som cross-site. En hjemmeside kan ikke skrive `Origin`-headeren, og en app-login sætter ingen cookie, så der er ingen session for en forfalsket anmodning at ride på. Passkeys er udenfor i første omgang: RP-ID er bundet til domænet og kræver apple-app-site-association på hver instans. Migration 0037: sessions.client, device_name, idle_ttl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
95e02b567b
commit
4ef050ae04
@@ -24,8 +24,12 @@ type Config struct {
|
||||
DataDir string
|
||||
|
||||
SessionTTL time.Duration
|
||||
InviteTTL time.Duration
|
||||
ResetTTL time.Duration
|
||||
// AppSessionTTL is how long a session from the iOS app may sit unused before
|
||||
// it ends. It slides: every use moves the end forward, so a phone in daily use
|
||||
// stays signed in and one left in a drawer does not.
|
||||
AppSessionTTL time.Duration
|
||||
InviteTTL time.Duration
|
||||
ResetTTL time.Duration
|
||||
|
||||
SMTP SMTP
|
||||
|
||||
@@ -166,6 +170,9 @@ func Load() (*Config, error) {
|
||||
if c.SessionTTL, err = envDuration("VERDANDE_SESSION_TTL", 30*24*time.Hour); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.AppSessionTTL, err = envDuration("VERDANDE_APP_SESSION_TTL", 180*24*time.Hour); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if c.InviteTTL, err = envDuration("VERDANDE_INVITE_TTL", 7*24*time.Hour); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user