Understanding OAuth2 Authentication: A Complete Guide for Web, Mobile, and Desktop Apps
Overview: Introduction · Why OAuth2 exists · Key terms · Flows · Grant types · Tokens · Web & native implementation · Security best practices · OAuth2 vs OIDC · FAQ
Introduction to OAuth2: what it is and why it matters
OAuth2 is the industry-standard authorization framework that allows applications to obtain limited access to a user’s data without asking for passwords. Instead of sharing credentials, applications receive short-lived tokens that grant specific, revocable permissions (scopes). OAuth2 powers “Sign in with” and “Connect to” experiences from major platforms like Google, GitHub, and Microsoft.
This guide covers the concepts, step-by-step flows, grant types, token strategies, implementation tips for web/mobile/desktop applications, and security best practices you should follow when integrating OAuth2.
Why OAuth2 exists and the problems it solves
Limitations of traditional authentication
Apps that required usernames/passwords to access APIs created problems: password exposure, lack of fine-grained access control, inability to revoke only a specific app’s access, and poor user experience.
Delegated access made safe
OAuth2 introduces a model of delegated authorization — the user (resource owner) grants limited scopes to an app (client). The app receives tokens it can use to access the resource server without ever seeing the user’s password.
Key concepts and terminology
Resource Owner
The end user who owns the data.
Client
The application requesting access (web server, SPA, native app).
Authorization Server
The server that authenticates the user and issues tokens (for example, accounts.google.com for Google APIs).
Resource Server
The API hosting protected resources (for example, Google Drive API).
Access Token & Refresh Token
An access token is short-lived and used for API calls. A refresh token is long-lived and used to obtain new access tokens without further user interaction.
Scopes
Scopes are fine-grained permission strings (e.g., profile, email, files.read) that limit what an access token can do.
How OAuth2 works — high-level flow
The common Authorization Code flow (used by secure server-side apps) looks like this:
- Your app redirects the user to the authorization server.
- The user authenticates and consents to scopes.
- An authorization code is returned to the app callback.
- The app exchanges the code at the token endpoint for an access token (and optional refresh token).
- The app uses the access token to call the resource server.
OAuth2 grant types and when to use each
Authorization Code (server-side)
Use for web applications with a secure backend that can keep a client secret. Most secure and common for server-hosted apps.
Authorization Code + PKCE (mobile, desktop, SPA)
Use PKCE for public clients (cannot hold secrets). PKCE prevents code interception attacks by adding a code verifier/challenge pair.
Client Credentials (machine-to-machine)
Use when your service calls another service without a user (server-to-server).
Device Code (TVs, IoT)
For devices with limited input — the device shows a code and asks the user to authenticate on another device.
Refresh Token
Used to renew access tokens without user interaction. Store refresh tokens securely and rotate them where possible.
Access tokens vs refresh tokens — purpose and storage
Access token characteristics
Short-lived (minutes to an hour), presented on every API call in the Authorization: Bearer <token> header. Can be JWTs or opaque strings.
Refresh token characteristics
Longer-lived, used only at the token endpoint to obtain fresh access tokens. Must be stored securely and should not be exposed to the browser/JavaScript where possible.
Recommended expiration strategy
- Access tokens: typically 5–60 minutes
- Refresh tokens: days to months (or rotated frequently)
- Rotate refresh tokens on use to reduce risk
Implementing OAuth2 in a web application (step-by-step)
Register your client
Register the application with your identity provider to obtain a client_id and client_secret (web backends only). Configure redirect URIs exactly.
Redirect the user to authorize
Build the authorization URL with parameters:
// Example authorization URL (pseudo)
GET https://auth.example.com/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fcallback
&scope=profile%20email%20files.read
&state=RANDOM_CSFR_TOKEN
Exchange code for tokens
On the backend, exchange the authorization code at the token endpoint:
POST https://auth.example.com/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https%3A%2F%2Fyourapp.example.com%2Fcallback
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
Call protected APIs
// Example API call with access token
GET https://api.example.com/userinfo
Authorization: Bearer <access_token>
OAuth2 in native, mobile, and desktop apps
Use PKCE for public clients
PKCE (Proof Key for Code Exchange) ensures code exchanges are tied to the original client by including a code challenge & verifier pair.
Secure token storage
- Android: use Android Keystore
- iOS: use Keychain
- Desktop (Windows/macOS/Linux): use OS-provided secure storage (Keyring, Keychain, credential manager)
- For JavaFX, store tokens in OS secure storage (do not write plaintext files)
JavaFX example pattern (brief)
Open the authorization URL in the system browser, run a local loopback (on a random free port) to receive the redirect, exchange the code on a backend or directly if using PKCE, then persist tokens in secure storage.
Common security best practices for OAuth2 integrations
Always use HTTPS
Never send tokens or codes over plain HTTP.
Avoid implicit flow
Implicit flow is deprecated — favor Authorization Code + PKCE or proper server-side flows.
Minimal scopes
Request the smallest set of scopes necessary for the feature.
Token rotation & revocation
Rotate refresh tokens on each use and provide a way for users to revoke client access in case of compromise.
Store tokens securely
On web servers: use HttpOnly cookies or secure server-side storage. On clients: use platform keystores.
OAuth2 vs OpenID Connect: authorization vs authentication
OAuth2 is primarily an authorization framework — it grants access to resources. OpenID Connect (OIDC) is an authentication layer built on top of OAuth2 that standardizes how identity (ID Token) and user info are returned. Use OIDC when you need federated login (who the user is) in addition to access delegation.
Final summary
OAuth2 provides a secure, flexible, and scalable way for applications to access protected resources without exposing user credentials. By using authorization codes, PKCE, scopes, access tokens, and refresh tokens, developers can build authentication flows that work across web, mobile, desktop, and devices without browsers. Implement OAuth2 carefully — focus on secure token storage, HTTPS, scope minimization, and token rotation — and you’ll enable safe integrations with major platforms while protecting users’ data.
FAQ — quick answers to common OAuth2 questions
What grant type should I use for a single-page application?
Use Authorization Code with PKCE. Do not use the implicit flow.
Where should I store access and refresh tokens?
Access tokens: short-lived and acceptable in memory for SPAs; prefer to keep them out of localStorage. Refresh tokens: if possible keep them on a secure backend or, for mobile, in platform keystores (Keychain/Keystore).
Is OAuth2 the same as OpenID Connect?
No — OAuth2 is authorization; OpenID Connect is an authentication layer built on top of OAuth2 (it adds ID tokens and standardized user info).
