# Authentication for Serverless and Edge Deployments - Part 3

> Part 3 of 3. Start with [Authentication for Serverless and Edge Deployments](https://clerk.com/articles/authentication-for-serverless-and-edge-deployments.md).

Welcome to Part 3 of our series on authentication for serverless and edge deployments. In Part 1, we covered the architectural shift to the edge and core concepts, while Part 2 focused on implementing authentication across different runtimes. In this final installment, we provide a detailed feature comparison of leading edge authentication solutions, explore critical security best practices, and offer a comprehensive implementation checklist to ensure your deployment is production-ready.

## Comparison of Serverless and Edge Authentication Solutions

### Feature comparison table

| Capability                           | Roll-your-own (`jose`) |       AWS Cognito      |       Auth0       | Supabase Auth |        Firebase Auth        |  Clerk  |
| ------------------------------------ | :--------------------: | :--------------------: | :---------------: | :-----------: | :-------------------------: | :-----: |
| Node.js serverless compatible        |           Yes          |           Yes          |        Yes        |      Yes      |             Yes             |   Yes   |
| V8 isolate / edge runtime compatible |           Yes          |   via aws-jwt-verify   | via /edge subpath |      Yes      | via next-firebase-auth-edge |   Yes   |
| Networkless JWT verification         |           Yes          |           No           |         No        |       No      |              No             |   Yes   |
| Built-in UI components               |           No           |        Hosted UI       |        Yes        |   Starter UI  |          FirebaseUI         |   Yes   |
| Organizations / RBAC                 |           No           |       User groups      |        Yes        |     Custom    |        Custom claims        |   Yes   |
| MFA                                  |           No           |           Yes          |        Yes        |      Yes      |             Yes             |   Yes   |
| M2M / service identity               |           DIY          | App client credentials |        Yes        |       No      |              No             |   Yes   |
| Documented monorepo story            |           No           |           No           |     Community     |   Community   |              No             |   Yes   |
| Managed JWKS + key rotation          |           No           |           Yes          |        Yes        |      Yes      |             Yes             |   Yes   |
| Billing model                        |       Self-hosted      |         Per-MAU        |      Per-MAU      |    Per-MAU    |        Per-MAU (+SMS)       | Per-MRU |

> MRU (Monthly Retained User) and MAU (Monthly Active User) are **not interchangeable**. MAU counts any user who signed in during the month; MRU counts users who return 24+ hours after sign-up (Clerk's definition) ([Clerk pricing page](https://clerk.com/pricing)). A given Clerk MRU count is typically lower than the MAU count for the same userbase, so `MAU × per-MAU-price` and `MRU × per-MRU-price` cannot be compared directly.

### Developer experience

- **TypeScript support** — Clerk, AWS Cognito (`aws-jwt-verify`), Auth0, Supabase, Firebase (via `firebase-admin` / community edge libs), and `jose` all publish first-class TypeScript types.
- **Edge-specific documentation for Next.js** — Clerk publishes `proxy.ts` examples in Core 3 docs; Auth0 documents an `/edge` subpath; AWS Cognito documents `aws-jwt-verify`.
- **Edge-specific documentation for Cloudflare Workers** — Clerk + Hono via `@hono/clerk-auth`; Auth0 and Firebase via community.

### Edge runtime support

- **Runs natively on V8 isolate runtimes without adapters**: `jose`, `@clerk/backend`, Supabase `getClaims()` in Deno Edge Functions.
- **Requires a Node.js runtime or edge subpath**: Auth0 (`/edge`), `firebase-admin` (not edge-compatible), `jsonwebtoken` (not edge-compatible).

### Pricing considerations

Pricing is normalized here by **billing model**, not raw dollar figures, because (a) per-MAU and per-MRU prices cannot be compared as raw numbers, and (b) vendor pricing changes frequently enough that specific tier numbers go stale quickly. Before making cost decisions, confirm every dollar figure below against the cited vendor's live pricing page.

- **Per-MAU vendors**: Auth0 (note the November 2023 restructure: B2C Essentials' entry tier moved from $23/mo for 1,000 MAU to $35/mo for 500 MAU — an effective jump from roughly $0.023 to $0.07 per MAU, though Auth0 bills in discrete MAU tiers, not a continuous per-MAU overage) ([Auth0 pricing change announcement](https://auth0.com/blog/upcoming-pricing-changes-for-the-customer-identity-cloud/), [Auth0 pricing](https://auth0.com/pricing)), AWS Cognito ([Cognito pricing](https://aws.amazon.com/cognito/pricing/)), Supabase Auth ([Supabase pricing](https://supabase.com/pricing)), Firebase Authentication ([Firebase pricing](https://firebase.google.com/pricing)).
- **Per-MRU vendor**: Clerk ([Clerk pricing page](https://clerk.com/pricing)).
- **Per-verification (M2M / API keys)**: Clerk M2M JWT verification is free (networkless); Clerk opaque M2M and API Key verifications are billed per request ([Clerk M2M JWT changelog](https://clerk.com/changelog/2026-02-24-m2m-jwt-tokens.md), [Clerk API Keys GA](https://clerk.com/changelog/2026-04-17-api-keys-ga.md)).
- **Self-hosted / roll-your-own**: no per-user fee, but shifts cost to infrastructure, UI build, CVE tracking, key rotation, and audit work.

**Entry-tier numbers as of July 2026** (confirm each against the cited vendor pricing page before making cost decisions):

- **Auth0**: Free tier up to 25,000 MAU; B2C Essentials starts at $35/mo for 500 MAU and scales by tiered MAU bands ([Auth0 pricing](https://auth0.com/pricing)).
- **AWS Cognito Essentials** (the default tier for user pools created after Nov 22, 2024): first 10,000 MAU free, then $0.015 per MAU ([Cognito pricing](https://aws.amazon.com/cognito/pricing/)). Both the "Cognito Lite" and Essentials tiers include 10,000 free MAU for new deployments; the larger 50,000 free MAU allowance is grandfathered only for eligible accounts under AWS's eligibility rules — those with active user pools (at least 1 MAU in the 12 months on or before Nov 22, 2024) — not simply for pools created on or before that date.
- **Supabase**: Free plan up to 50,000 MAU; Pro at $25/mo includes 100,000 MAU and charges $0.00325 per MAU above the included quota ([Supabase pricing](https://supabase.com/pricing)).
- **Firebase Spark** (free): 50,000 MAU for standard sign-in (limited to 50 SAML/OIDC MAU, no phone auth); Blaze is pay-as-you-go above that and phone auth is billed per SMS separately ([Firebase pricing](https://firebase.google.com/pricing)).
- **Clerk Hobby** (free): up to 50,000 MRU per application; Pro at $25/mo (or $20/mo billed annually) includes 50,000 MRU and charges $0.02 per MRU above that up to 100,000 MRU ([Clerk pricing](https://clerk.com/pricing)).

### When each option makes sense

Match your primary requirement to an option:

- **If you need managed UI + organizations/RBAC + edge-native SDK + M2M + monorepo story in one vendor** → Clerk is designed for this combined set.
- **If your backend is already Supabase or Firebase** → their native auth avoids a second identity system.
- **If you need mature enterprise SSO, Actions/Rules policies, and can absorb per-MAU pricing at scale** → Auth0.
- **If your infrastructure is AWS-native and Cognito's token shape fits your app** → Cognito.
- **If your scope is narrow (API-only, no user UI) and you can own CVE tracking, key rotation, JWKS caching, and refresh-token logic** → `jose` + your own IdP.

This maps requirements to options; it is not a ranked recommendation.

## Security Best Practices for Serverless and Edge Auth

### JWT validation checklist

- [ ] Algorithm allow-list. Never accept `alg: none` ([aquilax.ai algorithm confusion](https://aquilax.ai/blog/jwt-algorithm-confusion-auth-bypass), [OWASP JWT cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html)).
- [ ] Validate `iss`, `aud`, `exp`, `nbf`, `azp` consistently ([Clerk manual JWT verification](https://clerk.com/docs/guides/sessions/manual-jwt-verification.md)).
- [ ] Rotate JWKS correctly; cap refresh at a 5–10 minute minimum.
- [ ] Prefer asymmetric algorithms (RS256, ES256, EdDSA) for multi-service setups.
- [ ] Allow a small clock skew: 5–30 seconds ([Curity JWT best practices](https://curity.io/resources/learn/jwt-best-practices/)).

> Historical JWT CVEs to test against: CVE-2015-9235 (`jsonwebtoken` algorithm confusion — RS256→HS256 swap), CVE-2022-21449 (ECDSA psychic signatures in Java), CVE-2022-23529 (`jsonwebtoken` key-type confusion) ([OWASP JWT testing guide](https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/06-Session_Management_Testing/10-Testing_JSON_Web_Tokens), [aquilax.ai JWT confusion](https://aquilax.ai/blog/jwt-algorithm-confusion-auth-bypass)).

### Token expiry and refresh strategies

- Short access tokens: Clerk session JWTs are 60 seconds; industry norms sit at 15–60 minutes for general access tokens.
- Rotating refresh tokens: each refresh mints a new refresh token; reuse detection invalidates the entire token family ([Auth0 refresh token rotation](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation)).
- In August 2025, threat cluster UNC6395 stole OAuth access and refresh tokens from the Salesloft Drift integration and used them to exfiltrate data from hundreds of Salesforce instances, including Cloudflare, Google, Palo Alto Networks, and Proofpoint — a practical reminder that long-lived OAuth credentials are high-value ([Google Cloud Threat Intelligence on UNC6395](https://cloud.google.com/blog/topics/threat-intelligence/data-theft-salesforce-instances-via-salesloft-drift)).
- Store refresh tokens in `HttpOnly`, `Secure`, `SameSite=Lax` cookies where possible.

### Cookie and CSRF considerations

**Vendor-agnostic cookie guidance (first).**

- `SameSite`, `Secure`, `HttpOnly`, `Domain`, `Path` — set each intentionally for any session or auth cookie.
- Widening a cookie's `Domain` attribute (e.g., `Domain=.example.com`) shares it across all subdomains. That works for simple single-vendor setups but expands the XSS attack surface to every subdomain and assumes every subdomain is equally trusted. For most monorepos with a mix of marketing, app, and API subdomains, prefer a tight per-origin cookie and propagate identity to other origins via `Authorization: Bearer <token>`.
- CSRF: enforce a same-site cookie policy (`SameSite=Lax` default, `Strict` where possible), check `Origin`/`Referer` on state-changing requests, and validate the `azp` (authorized party) claim on any JWT that crosses origins.

**Clerk-specific architecture (separate, do not blur with the generic guidance above).**

- Clerk deliberately does **not** widen cookies across subdomains. Cross-subdomain cookie sharing is not Clerk's recommended pattern and the `__session` cookie is scoped to the app domain.
- `__client` is an [HttpOnly cookie](https://clerk.com/glossary/httponly-cookies.md) on Clerk's Frontend API (FAPI) domain (e.g., `clerk.yourdomain.com`). It holds the long-lived client identity and is never readable from the app.
- `__session` is an app-domain-scoped JWT cookie (not `HttpOnly` by design, with a 60-second TTL). Do not set `Domain=.example.com` on this cookie to share it across subdomains.
- For cross-subdomain or cross-origin requests (e.g., `app.example.com` → `api.example.com`), call `getToken()` from the frontend SDK and send the session JWT as `Authorization: Bearer <token>`. The receiving service verifies with `authenticateRequest()` or `verifyToken()` — no cookie crosses the origin boundary.
- For genuinely separate domains (not subdomains), Clerk provides a **satellite domains** feature that uses a handshake flow between a primary and satellite domain. This is the supported Clerk path for multi-domain auth; it is not a "widen the cookie" shortcut ([Clerk satellite domains](https://clerk.com/docs/guides/dashboard/dns-domains/satellite-domains.md)).

> Clerk's `__session` cookie is intentionally not `HttpOnly` — the 60-second TTL and proactive refresh are what keep XSS exposure tight, not the cookie flag.

> Do not set `Domain=.example.com` on Clerk cookies to share them across subdomains. Clerk does not support this pattern; use `Authorization: Bearer` headers (same-TLD subdomains) or satellite domains (separate TLDs) instead.

### Secrets management at the edge

- Platform secret stores: Cloudflare Workers Secrets ([docs](https://developers.cloudflare.com/workers/configuration/secrets/)), Vercel Sensitive Env Vars ([docs](https://vercel.com/docs/environment-variables/sensitive-environment-variables)), AWS Secrets Manager + Parameter Store ([Secrets Manager + Lambda](https://docs.aws.amazon.com/secretsmanager/latest/userguide/retrieving-secrets_lambda.html)), Netlify env vars.
- `wrangler secret put` for Cloudflare Workers. Secrets are encrypted at rest and injected as env bindings.
- Avoid baked-in secrets in bundles. Inspect `pnpm build` output for accidental string literals.
- Rotate `CLERK_SECRET_KEY`, `CLERK_MACHINE_SECRET_KEY`, and `CLERK_ENCRYPTION_KEY` on a schedule. Out-of-band auditing of who rotated, when, and via which mechanism is part of a mature posture.

### Logging, auditing, and incident response

- Log auth events with: timestamp, `jti` (token ID), `userId` or `machineId`, request ID, IP (or hashed IP), outcome (success/failure). Never log the full token.
- Tie auth events to request IDs and traces via OpenTelemetry ([OWASP logging cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html)).
- Runbooks for key rotation and auth incidents — documented, tested, and owned before they are needed.
- OWASP Top 10 2025 relevant items: A01 Broken Access Control, A07 Authentication Failures, A03 Supply Chain Failures (newly elevated) ([OWASP Top 10 2025](https://owasp.org/Top10/2025/), [OWASP Top 10 2025 A07](https://owasp.org/Top10/2025/A07_2025-Authentication_Failures/)).

### Rate limiting auth attempts at the edge

Sign-in, token exchange, and M2M token endpoints are the highest-value credential-stuffing targets in any serverless system. The per-isolate nature of V8 runtimes defeats naive in-memory counters, so edge rate limiting needs a coordination primitive.

- **Cloudflare Workers**: the platform's Rate Limiting binding for sliding-window enforcement, or a Durable Object per user/IP for strongly consistent global counters (KV is eventually consistent and not safe for rate limiting) ([CF Rate Limit binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/), [CF Hono Rate Limit middleware](https://github.com/elithrar/workers-hono-rate-limit), [Global Rate Limiter with Durable Objects](https://shivekkhurana.com/blog/global-rate-limiter-durable-objects/), [Rules of Durable Objects](https://developers.cloudflare.com/changelog/post/2025-12-15-rules-of-durable-objects/)).
- **Vercel**: Vercel Firewall / WAF supports token-bucket and sliding-window rules for login and token endpoints ([Vercel WAF rate limiting](https://vercel.com/docs/vercel-firewall/vercel-waf/rate-limiting)).
- **AWS**: API Gateway throttling + AWS Shield; Cognito has built-in brute-force protection on sign-in endpoints.
- **Pattern**: rate limit unauthenticated endpoints on IP + hashed email; rate limit authenticated M2M endpoints on the machine ID; pair with short-lived tokens so even a successful brute force hits a moving target.

### Self-hosted Next.js CVE-2025-29927 deep dive

> CVE-2025-29927 (CVSS 9.1 Critical): the `x-middleware-subrequest` header allowed skipping `middleware.ts` auth checks on self-hosted Next.js. Fixed in 12.3.5, 13.5.9, 14.2.25, 15.2.3. Vercel-, Netlify-, and Cloudflare-hosted apps were **not** affected because those platforms run Next.js routing and middleware in a separate, decoupled system, so the in-app middleware bypass never applied. Mitigation for self-hosted deployments that cannot upgrade immediately: strip the `x-middleware-subrequest` header at your reverse proxy. Always verify auth in Server Components / Route Handlers, not only in `proxy.ts` ([NVD CVE-2025-29927](https://nvd.nist.gov/vuln/detail/CVE-2025-29927), [Vercel postmortem](https://vercel.com/blog/postmortem-on-next-js-middleware-bypass), [Datadog Security Labs](https://securitylabs.datadoghq.com/articles/nextjs-middleware-auth-bypass/), [Next.js `proxy.ts` reference](https://nextjs.org/docs/app/api-reference/file-conventions/proxy)).

The deeper lesson is not about this specific CVE — it is about never relying on a single middleware-layer check as the full auth boundary. Defense in depth means middleware (fast reject) + re-verification in the handler that actually does work (correctness guarantee).

## Implementation Checklist

### Before you start

- [ ] Identify each runtime target in the repo (Node.js serverless, V8 isolate edge, mobile, background).
- [ ] Decide on a single identity provider.
- [ ] Agree on token shape (claims, audience, issuer) and document it in a shared types package.
- [ ] Define scopes for M2M calls.
- [ ] Identify where authorization decisions run (closer to data than authentication).

### During implementation

- [ ] Centralize auth config in a shared package (env vars + types, not SDK wrapper).
- [ ] Add auth at the outermost boundary (proxy / middleware / gateway), but re-verify in server code.
- [ ] Use networkless verification (`jwtKey`) where available.
- [ ] Write integration tests against real tokens from a dev environment, not mocked JWTs.
- [ ] Prefer asymmetric JWT algorithms (RS256, ES256, EdDSA).
- [ ] Validate `iss`, `aud`, `exp`, `nbf`, `azp` claims consistently.

### Production readiness

- [ ] JWKS caching verified under load (cold/warm/rotation).
- [ ] Secrets configured per environment; never baked into bundles.
- [ ] Observability: auth latency (p50/p95/p99), failure rate, token refresh rate.
- [ ] Runbooks for key rotation and auth incident response.
- [ ] Rate limiting at the edge for unauthenticated endpoints.
- [ ] Content-Security-Policy + cookie flags hardened.
- [ ] Known-CVE header stripping at the reverse proxy (e.g., `x-middleware-subrequest`).
- [ ] Document authn vs. authz boundaries explicitly so on-call engineers do not have to guess.

## Further Reading

- Clerk docs: [How Clerk works](https://clerk.com/docs/guides/how-clerk-works/overview.md), [Backend SDK overview](https://clerk.com/docs/reference/backend/overview.md), [Machine auth overview](https://clerk.com/docs/guides/development/machine-auth/overview.md), [Session tokens reference](https://clerk.com/docs/guides/sessions/session-tokens.md), [Manual JWT verification](https://clerk.com/docs/guides/sessions/manual-jwt-verification.md).
- Platform docs: [Next.js 16 `proxy.ts`](https://nextjs.org/docs/app/api-reference/file-conventions/proxy), [Cloudflare Workers platform limits](https://developers.cloudflare.com/workers/platform/limits/), [Vercel Functions limitations](https://vercel.com/docs/functions/limitations), [Netlify Edge Functions overview](https://docs.netlify.com/build/edge-functions/overview/), [AWS Lambda cold start remediation](https://aws.amazon.com/blogs/compute/understanding-and-remediating-cold-starts-an-aws-lambda-perspective/).
- Specs and standards: [RFC 7519 (JWT)](https://datatracker.ietf.org/doc/html/rfc7519), [RFC 7517 (JWK)](https://datatracker.ietf.org/doc/html/rfc7517), [RFC 6749 (OAuth 2.0)](https://datatracker.ietf.org/doc/html/rfc6749), [RFC 9068 (JWT Profile for OAuth 2.0 Access Tokens)](https://datatracker.ietf.org/doc/html/rfc9068), [RFC 9700 (OAuth 2.0 Security BCP)](https://datatracker.ietf.org/doc/rfc9700/), [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html).
- Security: [OWASP Top 10 2025](https://owasp.org/Top10/2025/), [OWASP JWT cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_Cheat_Sheet.html), [NIST SP 800-63B-4 (July 2025)](https://csrc.nist.gov/pubs/sp/800/63/b/4/final).

## Conclusion

Securing serverless and edge deployments requires a shift in how we think about authentication. By moving validation to the edge, utilizing networkless JWT verification, and adhering to strict security best practices, you can build fast, resilient, and secure applications. Whether you choose a managed solution like Clerk or build your own, the principles and checklists provided in this series will help you navigate the complexities of edge authentication.

## FAQ

### What is the best authentication for serverless and edge functions?

The best authentication solution depends on your specific requirements. For teams needing managed UI, organizations/RBAC, edge-native SDKs, and M2M support out of the box, Clerk is a strong choice. If you are already deeply integrated into the AWS ecosystem, Cognito might fit well, while Supabase or Firebase are natural fits if you use their respective backends.

### What security pitfalls are unique to serverless and edge authentication?

Unique pitfalls include relying on centralized databases for token validation (which negates edge latency benefits), failing to implement networkless JWT verification, improper JWKS caching leading to cold starts or stale keys, and overlooking edge-specific rate limiting. Additionally, edge environments require careful secrets management and strict adherence to token expiry and refresh strategies to mitigate credential theft.

### How do I handle token revocation at the edge?

Because edge functions often rely on stateless JWT verification, immediate token revocation is challenging. The best practice is to use short-lived access tokens (e.g., 60 seconds) combined with rotating refresh tokens. For critical revocations, you can maintain a distributed blocklist (using tools like Cloudflare KV or Redis) that edge functions check, though this introduces a network hop.

## In this series

1. [Authentication for Serverless and Edge Deployments](https://clerk.com/articles/authentication-for-serverless-and-edge-deployments.md)
2. [Authentication for Serverless and Edge Deployments - Part 2](https://clerk.com/articles/authentication-for-serverless-and-edge-deployments-2.md)
3. **Authentication for Serverless and Edge Deployments - Part 3** (you are here)
