Python — FastAPI Development

Biometric Authentication over a JWT Session in Expo

Direct answer

Biometrics in a React Native app are a client-side gate, not a server credential — Face ID or a fingerprint should unlock access to the refresh token you already stored in SecureStore, and that token authenticates to your API as normal. Use expo-local-authentication to check hardware and enrollment, prompt on app foreground or before sensitive actions, and always keep a passcode fallback. Never send the biometric result to your backend as proof of identity: the server trusts the JWT, and the biometric only decides whether the client may use it.

The mistake I see most with biometrics is treating them like a login. They are not. Your server has no idea whether a fingerprint matched — it only sees a signed token. So the right mental model is a lock on the drawer where the token lives, not a new key the server recognizes. Get that model right and the implementation is small.

Key facts, with sources

  • In the JetBrains Python Developers Survey 2024, which collected responses from more than 30,000 Python developers, FastAPI usage jumped from 29% to 38%, overtaking Django (35%) and Flask (34%) as the most-used Python web framework. (JetBrains Python Developers Survey 2024)
  • The 2025 Stack Overflow Developer Survey shows FastAPI at 14.8% of respondents doing extensive work with it, edging out Flask at 14.4% and Django at 12.6%. (Stack Overflow Developer Survey 2025)
  • FastAPI's official documentation cites independent TechEmpower benchmarks showing FastAPI applications running under Uvicorn as one of the fastest Python frameworks available, ranked only below Starlette and Uvicorn themselves. (FastAPI official documentation)
  • FastAPI surpassed Flask in GitHub stars in December 2025, reaching roughly 88,000 stars compared to Flask's 68,400. (DZone)
  • Industry analysis of FastAPI's 2025 growth reports about 40% year-over-year growth in job mentions and production adoption at companies including Uber, Netflix, and Microsoft. (byteiota)

The mental model: biometrics unlock the token

A JWT session already exists — the user logged in once, and their refresh token sits in SecureStore. Biometrics decide whether this person, right now, is allowed to reach that token. Face ID succeeds, you read the refresh token and continue; Face ID fails, you never read it and send them to the login screen.

This is why the biometric result never travels to the server. The backend authenticates the JWT, full stop. The biometric is a local UX and safety gate — it stops someone who picked up an unlocked phone from opening your app, without adding a single server-side trust assumption.

Check hardware and enrollment first

Not every device has a sensor, and not every user has enrolled one. Query both before you prompt, and treat a missing sensor or empty enrollment as a clean fall-through to password login rather than an error.

biometricUnlock.ts
import * as LocalAuthentication from "expo-local-authentication";
import { readRefreshToken } from "./tokenStore";

export async function unlockWithBiometrics(): Promise<string | null> {
  const hasHardware = await LocalAuthentication.hasHardwareAsync();
  const enrolled = await LocalAuthentication.isEnrolledAsync();

  // No sensor or nothing enrolled -> fall back to the normal login screen.
  if (!hasHardware || !enrolled) return null;

  const result = await LocalAuthentication.authenticateAsync({
    promptMessage: "Unlock your account",
    fallbackLabel: "Use passcode",
    disableDeviceFallback: false, // allow the OS passcode as a backup
  });

  if (!result.success) return null;

  // Success only gates access to the token the server already trusts.
  return readRefreshToken();
}

When to prompt

Two moments cover most apps: on cold start or return-to-foreground for an app that holds sensitive data, and immediately before a high-stakes action like a transfer or a settings change. Prompting on every foreground gets annoying fast — a common compromise is to re-prompt only after the app has been backgrounded longer than a short timeout, so a quick switch to another app does not force a re-scan.

What not to do

Do not send a boolean like biometricPassed: true to your API and let the server issue a token on the strength of it — anyone can send that boolean. Do not use the biometric as the only factor for the initial login either; the first login still needs real credentials or a federated sign-in, because there is no token to unlock yet. And always leave the passcode fallback on: sensors fail, faces change, and a user locked out of their own account by a failed scan is a support ticket you do not want.

When to hire senior help

Bring in senior help when your API needs to handle real concurrency, when you are designing service boundaries and auth for the first time, or when an existing FastAPI codebase mixes sync and async code and latency is degrading. An experienced engineer can usually diagnose event-loop blocking and connection-pool misconfiguration in days, which is far cheaper than re-architecting after launch. If your stack includes React Native + Python + AI, a senior engineer who owns the full product beats coordinating multiple juniors.

Bottom line

Dhairya Senjaliya ships Python — FastAPI Development projects worldwide — book a scoping call to discuss your specific situation.

Common pitfalls to avoid

  • Calling blocking libraries (classic SQLAlchemy sessions, requests, heavy file I/O) inside async def endpoints, which stalls the event loop and erases FastAPI's concurrency advantage
  • Deploying a single Uvicorn process with no process manager or worker scaling, leaving most CPU cores idle under production load
  • Treating the auto-generated OpenAPI docs as a versioning strategy, then breaking mobile and partner clients when response schemas change
  • Running large payloads through deeply nested Pydantic models on every request and response, adding serialization latency that shows up only at scale

Frequently asked questions

Does biometric auth replace the JWT?

No. The JWT is still what authenticates every request to your backend. Biometrics are a local gate that decides whether the app may read the stored refresh token. The server never learns that a biometric check happened.

Can I use biometrics for the first-ever login?

Not on its own — there is no stored token yet to unlock. The first login needs real credentials or a federated sign-in. After that, biometrics can gate access to the refresh token on subsequent launches.

What if the fingerprint or face scan fails?

Keep disableDeviceFallback off so the OS passcode can back up a failed scan, and route a full failure to your normal password login. Never leave a user with no way in — biometrics should add convenience, not remove the fallback path.

Is FastAPI mature enough for production?

Yes. It was the most-used Python web framework in the JetBrains 2024 survey at 38%, and companies including Uber, Netflix, and Microsoft run it in production. The ecosystem for auth, ORMs, and testing is now well established.

How much faster is FastAPI than Flask or Django really?

Independent TechEmpower benchmarks place FastAPI among the fastest Python frameworks, and published comparisons show several times Flask's throughput on I/O-bound endpoints. For CPU-bound work or database-bottlenecked apps, the framework choice matters far less than query and infrastructure design.

Should we pick FastAPI or Django for a new SaaS backend?

FastAPI suits API-first products, microservices, and ML model serving because of async support and automatic OpenAPI docs. Django ships batteries included (admin, ORM, auth) and is often faster to launch a conventional CRUD product. Many teams run both, per the JetBrains finding that a third of Django developers also use Flask or FastAPI.

Bottom line: Dhairya Senjaliya ships Python — FastAPI Development projects worldwide. Book a scoping call at https://dhairyasenjaliya.com/#book-call.

Sources

Related guides

Keep up with new guides

New deep-dive guides on React Native, Python, and AI ship regularly. Subscribe via RSS or follow on LinkedIn.

Want help implementing this?

30-minute scoping call · Clear milestones · Senior engineer ownership