Fallstudie · Backend-mikrotjänst
Auth Service
En tjänst för inloggning, så att mina appar inte gör säkerhetsfel på var sitt sätt
En fristående tjänst för autentisering – registrering och inloggning, inloggning med GitHub och Google, roller, verifiering av e-post och återställning av lösenord – som andra appar kan lämna över allt det till. Att bygga den lärde mig mest om de delar som ser färdiga ut men inte är det.
- Roll
- Eget projekt: API-design, säkerhet, tester och driftsättning
- När
- 2026
- Teknik
- FastAPI
- PostgreSQL
- Redis
- JWT
- OAuth2
- Docker
- pytest
- structlog

01.Problemet
Varje app jag byggt hade sin egen inloggningskod, lite olika varje gång och var och en ytterligare ett ställe för säkerhetsbuggar. Jag ville ha en enda tjänst som äger lösenord, token och OAuth, så att en app bara behöver ställa en fråga: är den här token giltig, och vems är den?
Den frågan är GET /auth/validate. Allt annat – hur token utfärdas, roteras, spärras och begränsas – finns på ett ställe där det kan testas ordentligt.
02.Viktiga beslut
01Kortlivade åtkomsttoken, roterande refresh-token
Åtkomsttoken är JWT som går ut efter 15 minuter. Refresh-token är slumpade strängar som bara sparas som SHA-256-hashar, så en kopia av databasen ger ingen tillgång till sessioner. Varje förnyelse spärrar den gamla token och utfärdar ett nytt par, och en återställning av lösenordet avslutar alla användarens sessioner.
Avvägning: Korta åtkomsttoken gör att en stulen token inte är värd mycket, men apparna förnyar ofta, så förnyelsen måste vara snabb och pålitlig.

Dashboarden i det inbyggda webbgränssnittet: roller, nedräkning för åtkomsttoken på 15 minuter, rotering av token och status för databasen och Redis. 02Redis för allt som ska gå ut
Allt med en livslängd ligger i Redis med en utgångstid: räknaren för misslyckade inloggningar (fem misslyckanden låser kontot i 15 minuter), begränsningar per IP-adress för inloggning, registrering och lösenordsåterställning, engångstoken som skyddar inloggningen med GitHub och Google mot CSRF, och en spärrlista för åtkomsttoken som spärrats innan de gått ut.
03Gör det inte lätt att ta reda på vem som har ett konto
Glömt lösenord och ny verifieringslänk svarar likadant oavsett om e-postadressen finns, och en misslyckad inloggning säger ”fel e-post eller lösenord” i båda fallen. Token för återställning och verifiering sparas hashade och fungerar exakt en gång.
Avvägning: Registreringen säger fortfarande när en e-postadress redan finns: den vanliga kompromissen mellan integritet och ett tydligt felmeddelande.
04Roller som ett beroende, inte utspridda kontroller
Användare har roller (admin, moderator, användare) som skapas av en migrering. En route anger vilken roll den kräver med ett require_role()-beroende, så kontrollen står bredvid routen i stället för inuti den. Administratörer hanterar användare och roller via API:t, och det lilla webbgränssnittet som följer med tjänsten har en adminvy ovanpå det.
Tjänsten går också att följa från början: varje svar har ett X-Request-ID som kopplas till de strukturerade loggarna, viktiga händelser skriver granskningsposter, svar som begränsats säger när man kan försöka igen, och /health kontrollerar PostgreSQL och Redis och svarar 503 om någon av dem ligger nere.

Adminvyn, bara för administratörer: sök användare, slå på och av roller och inaktivera konton.
03.Resultat
- 75 tester och ett krav på 70 % testtäckning i CI, plus en Docker-image som byggs vid varje push
- Driftsatt på Railway med PostgreSQL och Redis, med ett webbgränssnitt utan beroenden där man kan prova varje flöde
- För en app räcker två anrop: validera en token och förnya en token
04.Vad jag skulle göra annorlunda
Testa mot samma databas som i produktion
Testerna körs mot SQLite i minnet eftersom det går snabbt. Första driftsättningen mot riktig PostgreSQL misslyckades: migreringen som skapar standardrollerna skrev text till en UUID-kolumn, vilket SQLite tyst accepterar. I DeskFlow testade jag mot PostgreSQL från början, och det skulle jag göra här också.
Signera token med ett nyckelpar
Token signeras med en delad hemlighet (HS256), så andra appar kan inte kontrollera en token själva: varje förfrågan kostar ett anrop till /auth/validate. Att signera med en privat nyckel (RS256) och publicera den publika nyckeln skulle låta apparna verifiera token lokalt och bara anropa tjänsten för att förnya.
Behandla en återanvänd refresh-token som ett angrepp
En refresh-token som redan har använts avvisas, men det avslutar inte resten av sessionen, vilket är standardförsvaret när en token har stulits. På samma sätt spärrar ”logga ut överallt” alla refresh-token men stänger bara av den aktuella enhetens åtkomsttoken direkt; andra enheter fortsätter fungera tills deras token går ut, upp till 15 minuter senare. En tidsstämpel per användare för när token börjar gälla skulle avsluta dem direkt.
Flytta en riktig app till den
Den byggdes för ApplyLuma och Rostid, men båda använder fortfarande sin egen inloggningskod. Att flytta över en av dem är det riktiga testet av API:t, och nästa steg.