Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

API Authentication: Keys, JWT, OAuth

By Kokil Thapa | Last reviewed: September 2026

Every production REST API needs a clear answer to one question: who is calling, and what are they allowed to do? API Authentication: Keys, JWT, OAuth are the three patterns you will encounter on almost every integration—mobile apps, partner portals, payment webhooks, and internal microservices. Pick the wrong one and you either ship insecure endpoints or add weeks of unnecessary complexity. This guide compares all three with real request flows, security trade-offs, and copy-paste patterns for Laravel API development on PHP 8.3+.

What is API authentication and why do keys, JWT, and OAuth matter?

Authentication proves identity. Authorisation decides permissions. Many teams blur the two and regret it later.

On a legal-tech portal I built, a mobile app needed document upload while a partner CRM needed read-only case status. Same API, different trust models. Keys worked for the CRM. OAuth fit the mobile app because users logged in with their own credentials.

Modern APIs sit behind gateways, load balancers, and CDN edges. Your auth scheme must survive retries, clock skew, token expiry, and leaked credentials. That is why understanding JWT vs session vs API keys before you write middleware saves painful refactors.

API Authentication: Keys, JWT, OAuthAPI KeysShared secretServer-to-serverJWTSigned claimsStateless tokensOAuth 2.0Delegated accessUser consentYour REST API Resource ServerValidate credential, enforce scopes, rate limitLog audit trail, return 401 or 403
Three API authentication patterns—keys, JWT, and OAuth—all terminate at your resource server for validation and authorisation.

Each pattern solves a different trust boundary. Keys trust the holder of the secret. JWT trusts the signature from a known issuer. OAuth trusts an authorization server that the user already knows.

None of these replace transport security. Always terminate TLS at the edge. Never send raw credentials over plain HTTP.

How do API keys work for REST API authentication?

API keys are opaque strings tied to a client record in your database. The client sends the key on every request. Your API looks it up, checks status, and applies scopes.

Common transmission methods

Three header patterns dominate production APIs:

  • Authorization header: Authorization: Bearer sk_live_abc123 — familiar to HTTP clients.
  • Custom header: X-API-Key: sk_live_abc123 — keeps keys separate from user JWTs.
  • Query string: discouraged; keys leak into logs, referrer headers, and browser history.

Key lifecycle you should implement

  1. Generate cryptographically random keys (32+ bytes, base64url-encoded).
  2. Store only a hashed value in the database—never the plaintext key after creation.
  3. Attach metadata: owner, scopes, rate-limit tier, created date, last-used timestamp.
  4. Support rotation: issue a new key, overlap grace period, revoke the old one.
  5. Audit every authentication failure and suspicious usage spike.
GET /api/v1/orders HTTP/1.1
Host: api.example.com
Authorization: Bearer sk_live_7f3a9c2e
Accept: application/json

Keys excel when both sides are servers you control. Payment gateway callbacks, internal cron jobs, and partner B2B feeds fit this model well.

Keys fail when you need per-user permissions inside a third-party app. A leaked key grants full client access until rotation. That is why public mobile apps should not embed long-lived API keys.

API Key Request FlowClient AppAPI GatewayResource API1. Request + API key2. Forward request3. Hash lookup + scopes4. JSON response or 401Never log full keys — mask after 4 chars
API key authentication flow: the resource server hashes the incoming key and matches it against stored credentials before authorisation.

Pair keys with rate limiting strategies from day one. A stolen key without throttling becomes an expensive denial-of-wallet attack.

How does JWT authentication work in APIs?

A JSON Web Token is a compact, signed payload. The issuer signs it. The resource server verifies the signature without calling the issuer on every request.

That stateless property makes JWT popular in microservices and SPAs. It also creates footguns if you treat JWT like a session cookie with extra steps.

JWT structure

Three base64url segments separated by dots: header, payload, signature.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0Iiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzM1NjgwMDAwfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Decoded payload example:

{
  "sub": "1234",
  "iss": "https://auth.example.com",
  "aud": "https://api.example.com",
  "exp": 1735680000,
  "scope": "orders:read orders:write"
}

Always validate iss, aud, exp, and nbf if present. Reject tokens with unexpected algorithms—algorithm confusion attacks are still common. See the JWT specification (RFC 7519) for registered claim definitions.

Access vs refresh tokens

Short-lived access tokens (5–15 minutes) limit blast radius. Refresh tokens live longer but must be stored securely and revocable.

On production Laravel applications I maintain, Redis-backed deny lists handle emergency revocation. You cannot rely on expiry alone when an employee leaves or a device is lost.

JWT Validation PipelineIncoming Authorization: Bearer <JWT>ParseHeader + payloadVerifySignature + algValidateiss aud expAuthorizeScopes200 OKAttach user contextProcess request401 UnauthorizedInvalid or expiredDo not leak reason
JWT validation pipeline: parse, verify signature, validate standard claims, then enforce scopes before serving the request.

Read JWT security common vulnerabilities before shipping. Storing sensitive PII inside JWT payloads is a design smell—claims are base64-decodable by anyone holding the token.

Debug payloads with the JSON formatter tool during development. Never paste production tokens into public tools.

When should you use OAuth 2.0 instead of API keys or JWT?

OAuth solves delegated authorisation. A user grants a third-party app limited access without sharing their password with that app.

Think "Login with Google" or a Shopify app requesting order read access. The user consents. The authorization server issues tokens. Your API trusts that server.

OAuth 2.1 authorization code flow with PKCE

OAuth 2.1 consolidates best practices from years of real-world deployments. For browser and mobile apps, authorization code with PKCE is the default choice. The OAuth 2.0 framework (RFC 6749) defines the core roles: resource owner, client, authorization server, resource server.

  1. Client generates a code verifier and code challenge (PKCE).
  2. User redirects to the authorization server login and consent screen.
  3. Authorization server returns an authorization code to the registered redirect URI.
  4. Client exchanges the code plus verifier for access and refresh tokens.
  5. Client calls your API with the access token until expiry.

Machine-to-machine flows use client credentials instead. That pattern resembles API keys but adds standard token expiry and scope negotiation through the authorization server.

OAuth 2.1 Code + PKCE FlowClient AppAuth ServerLogin + consentResource APIUser1. Auth redirect2. User login3. Auth code4. Code exchange5. Access token6. API call with Bearer token
OAuth 2.1 authorization code flow with PKCE: user consent happens at the authorization server, not at your API.

OpenID Connect adds an identity layer on top of OAuth. It returns an ID token with user profile claims. Read OAuth 2.1 vs OpenID Connect explained if your product needs single sign-on.

For public API products, OAuth also enables scoped third-party integrations. Partners register clients, you approve scopes, and audit token usage centrally.

How do API keys, JWT, and OAuth compare in practice?

Teams often ask for a single winner. There isn't one. The right choice depends on who holds the credential and whether a human user is in the loop.

CriteriaAPI KeysJWTOAuth 2.0
Best forServer-to-server, webhooks, internal jobsSPAs, microservices, mobile backendsThird-party apps, SSO, user-delegated access
StateStateful lookup (DB or cache)Stateless verificationTokens + authorization server state
RevocationInstant (delete or disable key)Hard without deny list or short TTLRefresh token revoke + short access TTL
User consentNot applicableUsually first-party loginBuilt-in consent screens
ComplexityLowMediumHigh
Leaked credential riskFull client access until rotationScoped until expiryScoped + revocable refresh tokens

Many production systems combine all three. A gateway validates API keys for partners. First-party apps get JWT access tokens from your auth service. External integrations use OAuth client registration.

Which Auth Pattern?Who calls your API?Your serverUse API KeysEnd user appThird-party app?No — first partyUse JWTYesUse OAuth 2.0Always: HTTPS, rate limits, audit logs, least privilegeReview /blog/oauth-security-best-practices before launch
Decision tree for API authentication: keys for trusted servers, JWT for first-party apps, OAuth when third parties act on user behalf.

How do you implement API authentication in Laravel?

Laravel 13 (PHP 8.3+) and Laravel 12 (PHP 8.2+, supported to February 2027) ship first-class API tooling. Pick Sanctum for SPA and mobile token auth. Pick Passport when you need a full OAuth 2.0 authorization server.

See Laravel Passport vs Sanctum for the full decision matrix. Most apps I build start with Sanctum and only add Passport when external OAuth clients are a product requirement.

Sanctum for API tokens and SPA auth

composer require laravel/sanctum

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Issue a personal access token:

$token = $user->createToken('mobile-app', ['orders:read'])->plainTextToken;

return response()->json(['token' => $token]);

Protect routes:

Route::middleware('auth:sanctum')->group(function () {
    Route::get('/orders', [OrderController::class, 'index']);
});

Full walkthrough: build a REST API with Laravel Sanctum authentication.

Passport for OAuth 2.0 clients

When partners need registered OAuth clients with scoped access, Passport provides authorization codes, refresh tokens, and client credentials grants. Configure token lifetimes in AppServiceProvider or the Passport config file.

On client portals like Mijar Law Associates, Sanctum tokens power document upload from authenticated users. Partner integrations would move to Passport if the firm opened an external API.

Custom API key middleware

For webhook receivers and B2B feeds, a lightweight middleware often beats pulling in OAuth:

public function handle(Request $request, Closure $next)
{
    $key = $request->bearerToken() ?? $request->header('X-API-Key');

    if (! $key || ! ApiKey::verify($key)) {
        return response()->json(['message' => 'Unauthorized'], 401);
    }

    return $next($request);
}

Hash keys with hash('sha256', $plainKey) before storage. Show the plaintext once at creation—same pattern Stripe uses for secret keys.

Follow Laravel API best practices for versioning, pagination, and consistent error envelopes alongside auth.

What are common API authentication security mistakes?

Authentication bugs become breach headlines. These patterns show up repeatedly in audits and post-incident reviews.

  • Long-lived tokens in mobile binaries: reverse-engineering exposes them. Use OAuth with PKCE or short-lived tokens plus secure refresh storage.
  • Missing scope checks: validating identity without authorisation lets any authenticated user hit admin routes.
  • JWT in localStorage: XSS steals tokens. Prefer HttpOnly cookies for browser apps or secure enclave storage on mobile.
  • Ignoring clock skew: allow 30–60 seconds leeway on exp and nbf validation.
  • Logging Authorization headers: your log aggregator becomes a credential vault. Strip sensitive headers at the edge.
  • No idempotency on mutating endpoints: auth does not prevent duplicate charges. Pair with idempotency keys on POST and PATCH.

Run through the API security complete checklist before every production launch. Test with Base64 encoder/decoder locally when inspecting JWT segments—never in shared channels.

Payment integrations on Nepal-facing platforms often mix API keys (gateway callbacks) with user JWTs (customer dashboards). I've seen Khalti and eSewa webhooks fail because teams rotated keys without updating server config. Treat key rotation as a deployment step, not a database edit.

Document your auth scheme in OpenAPI. External developers integrate faster and misconfigure less. See API documentation with Redoc and Swagger UI and SDK design for your public API for downstream tooling.

For broader auth architecture—including password flows and MFA—read the ultimate guide to building secure authentication systems. For greenfield products, custom software development engagements should define auth requirements before schema design.

The Nepal Divorce Services portal combines session auth for the web UI with token-backed AJAX calls. That hybrid is normal: cookies for browsers, bearer tokens for API consumers.

Key Takeaways

  • Use API keys for trusted server-to-server calls; hash at rest, rotate regularly, and never pass keys in query strings.
  • Use JWT for stateless first-party access; keep TTLs short, validate iss/aud/exp, and plan revocation with deny lists or refresh-token rotation.
  • Use OAuth 2.0 when third-party apps need scoped, user-consented access—authorization code with PKCE for public clients.
  • Laravel Sanctum covers most token needs; add Passport only when you must issue OAuth clients to external partners.
  • Combine auth with rate limiting, HTTPS, audit logging, and scope checks—authentication alone is not authorisation.
  • Document flows in OpenAPI and test failure paths (expired token, wrong scope, revoked key) before launch.

People Also Ask

Is JWT better than API keys?

Neither is universally better. API keys suit fixed server integrations with instant revocation via database lookup. JWT suits distributed services that need stateless verification. Choose based on who holds the credential and how quickly you must revoke access.

Does OAuth replace JWT?

No. OAuth is a framework for obtaining tokens. Access tokens are often JWTs, but they can also be opaque strings. OAuth defines how a client gets a token; JWT defines how you encode and verify token contents.

How long should API tokens last?

Access tokens: 5–15 minutes for high-sensitivity APIs, up to one hour for low-risk read endpoints. API keys: no expiry by default, but schedule rotation every 90 days. Refresh tokens: days to weeks, stored securely and revocable server-side.

What is the difference between authentication and authorisation in APIs?

Authentication answers "who are you?"—via key, JWT signature, or OAuth token. Authorisation answers "what may you do?"—via scopes, roles, or policies applied after identity is established. Both must pass for a request to succeed.

Ship API authentication that survives production

API Authentication: Keys, JWT, OAuth is not a pick-one-and-forget decision. Start with the simplest pattern that matches your trust boundary. Add OAuth when external developers need user-delegated access. Harden every path with TLS, rate limits, and scoped permissions.

If you are designing a new API or untangling auth debt on an existing Laravel or Symfony codebase, I can help you choose and implement the right model. Review related work in the portfolio, explore building RESTful APIs with Laravel, or contact us to discuss your integration requirements.

Frequently Asked Questions

Authentication answers who is calling—via an API key lookup, a verified JWT signature, or a valid OAuth access token. Authorisation decides what that caller may do, enforced through scopes, roles, or policies after identity is confirmed. The article stresses that many teams blur the two and regret it when any authenticated user can hit admin routes. On a legal-tech portal, a partner CRM needed read-only case status while a mobile app needed document upload under the user's own credentials. Same API, different trust models. Validate identity first, then enforce permissions on every protected route.

Neither is universally better. API keys suit fixed server integrations with instant revocation via database lookup. JWT suits distributed services needing stateless verification. Choose based on who holds the credential and how quickly you must revoke access.

No. OAuth is a framework for obtaining tokens. Access tokens are often JWTs but can also be opaque strings. OAuth defines how a client gets a token; JWT defines how you encode and verify token contents.

Access tokens: 5–15 minutes for high-sensitivity APIs, up to one hour for low-risk read endpoints. API keys: no expiry by default, but schedule rotation every 90 days. Refresh tokens: days to weeks, stored securely and revocable server-side.

API keys are opaque strings tied to a client record in your database. The client sends the key on every request—typically via Authorization Bearer or an X-API-Key header, never in query strings where keys leak into logs and referrer headers. Your API hashes the incoming key, matches it against stored credentials, checks status and scopes, then applies rate limits. Generate cryptographically random keys of 32+ bytes, store only hashed values, attach metadata such as owner and last-used timestamp, and support rotation with a grace period. Keys excel for server-to-server calls like payment webhooks and partner B2B feeds.

A JSON Web Token is a compact, signed payload with three base64url segments: header, payload, and signature. The issuer signs it; the resource server verifies the signature without calling the issuer on every request. That stateless property suits microservices and SPAs, but treat validation seriously. Always validate iss, aud, exp, and nbf if present, and reject unexpected algorithms to prevent algorithm confusion attacks. Pair short-lived access tokens of 5–15 minutes with longer refresh tokens stored securely. Never put sensitive PII in payloads—claims are base64-decodable by anyone holding the token. Plan emergency revocation with Redis-backed deny lists because expiry alone is insufficient when a device is lost.

Use OAuth when a third-party app needs scoped, user-consented access without sharing the user's password—think Login with Google or a Shopify app requesting order read access. The user consents at the authorization server, which issues tokens your API trusts. For browser and mobile apps, OAuth 2.1 authorization code flow with PKCE is the default. Machine-to-machine integrations use client credentials, which resembles API keys but adds standard token expiry and scope negotiation. OAuth fits public API products where partners register clients, you approve scopes, and audit token usage centrally. It is the wrong choice for simple internal cron jobs where a hashed API key suffices.

There is no single winner. API keys suit server-to-server webhooks and internal jobs with low complexity and instant revocation via database lookup, but a leaked key grants full client access until rotation. JWT suits SPAs, microservices, and mobile backends with stateless verification, though revocation requires deny lists or short TTLs. OAuth suits third-party apps, SSO, and user-delegated access with built-in consent screens and revocable refresh tokens, at the cost of higher complexity. Many production systems combine all three: a gateway validates API keys for partners, first-party apps get JWT access tokens, and external integrations use OAuth client registration. Match the pattern to who holds the credential and whether a human user is in the loop.

Laravel 13 on PHP 8.3+ and Laravel 12 on PHP 8.2+ ship first-class API tooling. Start with Sanctum for SPA and mobile token auth: install via Composer, publish the provider, migrate, then issue scoped personal access tokens and protect routes with auth:sanctum middleware. Add Passport only when external partners need registered OAuth clients with authorization codes, refresh tokens, and client credentials grants. For webhook receivers and B2B feeds, lightweight custom middleware that reads Bearer or X-API-Key headers and verifies against hashed keys often beats pulling in full OAuth. On client portals, Sanctum tokens power authenticated document upload; partner integrations would move to Passport if the firm opened an external API.

Embedding long-lived tokens in mobile binaries exposes them via reverse-engineering—use OAuth with PKCE or short-lived tokens with secure refresh storage instead. Validating identity without checking scopes lets any authenticated user reach admin routes. Storing JWT in localStorage invites XSS theft; prefer HttpOnly cookies for browsers or secure enclave storage on mobile. Ignoring clock skew breaks exp validation—allow 30–60 seconds leeway. Logging Authorization headers turns your log aggregator into a credential vault; strip sensitive headers at the edge. Authentication alone does not prevent duplicate charges; pair mutating endpoints with idempotency keys. On Nepal-facing payment integrations, Khalti and eSewa webhooks fail when teams rotate keys without updating server config.

Two header patterns dominate production APIs. The Authorization header using Bearer sk_live_abc123 is familiar to HTTP clients and works well when keys are the only credential on the request. A custom X-API-Key header keeps keys separate from user JWTs when both may appear in the same system. Never pass keys in query strings—they leak into server logs, referrer headers, and browser history. Whichever header you choose, always terminate TLS at the edge and never send raw credentials over plain HTTP. Pair key transmission with rate limiting from day one so a stolen key cannot become an expensive denial-of-wallet attack.

Most applications should start with Sanctum and add Passport only when external OAuth clients are a product requirement. Sanctum covers SPA auth, mobile personal access tokens with scopes, and simple bearer-token APIs without the overhead of a full authorization server. Passport is warranted when partners need registered OAuth clients, authorization code flows, refresh token management, and client credentials grants for machine-to-machine access. Configure token lifetimes in AppServiceProvider or the Passport config file. The decision is about product scope, not package popularity—if no third party will ever request user-consented access to your API, Sanctum alone is sufficient and easier to maintain.

JWT verification is stateless, so you cannot rely on expiry alone when an employee leaves or a device is lost. Issue short-lived access tokens of 5–15 minutes to limit blast radius, then maintain a Redis-backed deny list for emergency revocation that your validation pipeline checks after signature verification. Longer-lived refresh tokens must be stored securely and revocable server-side—rotating or deleting a refresh token cuts off new access tokens without waiting for access TTL to pass. On production Laravel applications, this hybrid of short TTL plus deny lists is the practical pattern. Document and test expired-token and revoked-token failure paths before launch.

OAuth 2.1 makes authorization code flow with PKCE the default for browser and mobile apps. The client generates a code verifier and code challenge, redirects the user to the authorization server login and consent screen, receives an authorization code at a registered redirect URI, then exchanges the code plus verifier for access and refresh tokens. PKCE prevents authorization code interception on public clients that cannot store a client secret. OpenID Connect adds an identity layer returning an ID token with user profile claims when your product needs single sign-on. Avoid implicit flows and never embed long-lived secrets in mobile binaries—public clients must use PKCE, not shared secrets.

Yes, and many production systems do exactly that because each pattern solves a different trust boundary. A gateway might validate API keys for partner B2B feeds and payment gateway callbacks, while first-party mobile and SPA clients receive JWT access tokens from your auth service, and external third-party integrations register OAuth clients with scoped, user-consented access. The Nepal Divorce Services portal uses session auth for the web UI with token-backed AJAX calls—a hybrid where cookies serve browsers and bearer tokens serve API consumers. Design each endpoint's auth scheme based on who holds the credential, not a single project-wide rule. Document every flow in OpenAPI so external developers integrate faster and misconfigure less.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: