I en värld där användardata är konstant utsatt för hot, krävs fler lager av autentisering för att säkerställa att endast legitima användare får tillgång till systemet. Tvåfaktorsautentisering (2FA), särskilt genom TOTP (Time-based One-Time Password), erbjuder ett sådant lager. Men säkerhet handlar inte enbart om att kontrollera rätt kod — det handlar också om hur systemet reagerar på fel, attacker och misstänkt beteende.

När en användare försöker logga in, kontrollerar systemet först om kontot är låst. Om det är det, och spärrtiden inte har passerat, returneras omedelbart ett avvisande svar — åtkomst nekas, även om användarnamn och lösenord skulle vara korrekt. Denna kontroll sker innan lösenord ens valideras, vilket minskar attackytan.

Om kontot inte är spärrat, verifieras användarens lösenord mot det hashade värdet i databasen. Vid korrekt match fortsätter processen. Men om tvåfaktorsautentisering är aktiverad för kontot, krävs en giltig TOTP-kod. Denna kod genereras via en autentiseringsapp som Google Authenticator eller Authy, baserat på en hemlig nyckel som användaren fått vid 2FA-registrering.

När en TOTP-kod skickas in kontrolleras dess giltighet. Om den är ogiltig ökas en intern räknare för misslyckade 2FA-försök. När antalet fel når fem, spärras kontot tillfälligt i tio minuter. Detta är en kritisk mekanism för att förebygga brute force-attacker där en angripare försöker gissa TOTP-koder inom det smala tidsfönstret. Vid varje lyckat 2FA-försök nollställs räknaren och eventuell spärr tas bort.

Det är också värt att notera att 2FA-logiken ligger efter lösenordsverifiering, vilket innebär att systemet aldrig avslöjar om det är lösenordet eller 2FA-koden som var felaktig — ett medvetet säkerhetsbeslut för att försvåra angriparnas kartläggning av autentiseringsflödet.

Efter lyckad autentisering utfärdas en JWT-token (JSON Web Token) som används för vidare åtkomst till skyddade API:er i systemet. Denna token är signerad, tidsbegränsad och innehåller användaridentitet, vilket gör det möjligt att bygga skalbara, tillståndslösa backend-lösningar.

Att skapa en säker inloggning handlar inte om att lägga till en funktion, utan om att orkestrera flera delar: kontospärr, lösenordskontroll, tvåfaktorsverifiering och korrekt tokenutgivning. Varje steg bygger på föregående, och varje säkerhetsbeslut — från spärrlogik till kodverifiering — är resultatet av en noggrant avvägd balans mellan användarupplevelse och säkerhet.

För att ytterligare stärka systemet kan fallback-metoder införas: till exempel reservkoder, SMS-verifiering eller e-postbaserad TOTP. Systemet kan också utökas med notifikationer vid spärrning, till exempel via e-post eller webhookar som informerar användaren eller administratören om att misstänkta aktiviteter pågår. Det är också viktigt att logga varje inloggningsförsök, lyckat eller misslyckat, med tidsstämpel och IP-adress, för att möjliggöra granskning i efterhand.

Tokenutgivningen bör kopplas till en tydlig sessionshantering, där varje token är spårbar, och där återkallande är möjligt vid kompromettering. I komplexa miljöer kan man dessutom överväga att införa adaptiv autentisering, där systemet väger in faktorer som plats, enhet och tidpunkt för att avgöra om ytterligare verifiering krävs.

Hur bygger man en stabil och skalbar datakärna i moderna applikationer?

Grunden till varje robust och framtidssäker applikation börjar i en noggrant förberedd utvecklingsmiljö. När vi använder ett språk som Python i en modern stack, blir valet av version, verktyg och bibliotek avgörande inte bara för hastighet och underhållbarhet utan också för att kunna möta framtida krav utan att behöva bygga om från grunden. Den här boken utgår från Ubuntu 22.04 LTS och Python 3.11 – en kombination som erbjuder stabilitet, långsiktig support och ett rikt ekosystem av verktyg och dokumentation.

Genom att etablera en enhetlig och isolerad utvecklingsmiljö via virtuella miljöer skapas en förutsägbar struktur där beroenden hålls under kontroll. Denna initiala investering i miljökonfiguration förhindrar konflikter och främjar ett arbetsflöde där varje komponent byggs ovanpå en redan fungerande bas. Det minimerar felsökning och gör att utvecklarens fokus kan riktas mot det som är centralt: själva logiken och funktionaliteten i applikationen.

Vi inleder med att definiera en kärndatamodell och introducera ett servicenivåmönster som åtskiljer datalogik från presentation. Genom att använda FastAPI som vårt ramverk för webbgränssnitt får vi omedelbar tillgång till RESTful endpoints, dokumentation i realtid och en syntax som är tydlig och kraftfull. Tillsammans med Pydantic säkerställs datavalidering direkt vid modellnivå, vilket kraftigt minskar risken för buggar och inkonsistens i affärslogiken.

För att hantera stora datamängder implementeras paginering och metadatahantering, vilket inte bara förbättrar prestanda utan också gör klienternas arbete mer effektivt. Med avancerad filtrering och dynamisk sortering kan användaren göra precisa förfrågningar med minimal ansträngning – ett fundamentalt krav i dagens API-ekosystem.

Dataexport och -import, särskilt i bulkformat via CSV och JSON, är en annan pelare i ett skalbart system. Genom att införa streaminglösningar klarar systemet även riktigt stora datamängder utan att belasta minnet eller förlora integritet. Samma nivå av noggrannhet återfinns i bakgrundsjobb, där Celery och Redis samverkar för att avlasta gränssnittet från tunga uppgifter som annars hade påverkat användarens upplevelse negativt.

De bibliotek som valts är få till antalet men exceptionellt kapabla. SQLAlchemy, i kombination med Alembic, ger oss en fullständig ORM med migrationsstöd, vilket möjliggör en databasstruktur som utvecklas tillsammans med applikationen utan att tappa historik eller kontroll. Redis fungerar samtidigt som cache och meddelandemäklare, vilket tillför både snabbhet och tillförlitlighet. Jinja2 ger kraftfulla möjligheter till dynamisk dokumentgenerering – från HTML till PDF – och HTTPX hanterar alla externa integrationer med stöd för både synkron och asynkron kommunikation.

Valet att hålla sig till denna enhetliga stack är medvetet. Istället för att ständigt introducera nya beroenden för varje delkapitel, maximeras nyttan av varje enskilt bibliotek. Det leder till ett projekt som är både lätt att underhålla och enkelt att skala upp eller överföra till andra miljöer, vare sig det gäller containerisering, molndistribution eller klassisk deployment.

Det som är viktigt att förstå, är att varje funktion inte bara införs för att den är tekniskt möjlig – utan för att den svarar mot faktiska behov i moderna applikationer: från säker användarautentisering och realtidsnotifikationer till externa integrationer med betalningslösningar, tredjeparts-API:er och smarta system för övervakning och driftsättning. Allt binds samman av en metodik som bygger på verkliga projektkrav snarare än teoretiska exempel. Resultatet är en applikation som inte bara fungerar – den lever och växer.

För att bygga vidare på denna grund är det viktigt att förstå betydelsen av strukturell kontinuitet. Ett väldesignat kodbas fungerar som ett system av kontrakt – mellan tjänster, modeller och externa gränssnitt. När varje lager är tydligt definierat och väl separerat, blir hela systemet lätt att testa, ändra och expandera. I praktiken innebär det att varje ny funktion inte innebär en risk för kollaps, utan blir en naturlig förlängning av något som redan fungerar. Det är detta som skiljer hållbara projekt från snabbt hoprafsade lösningar.