🔐 OAuth 2.0 Authentication Guide
Earth Miles uses OAuth 2.0 with PKCE (Proof Key for Code Exchange) for secure authentication. This guide covers the complete authentication flow.
Authorization Flow
The OAuth 2.0 authorization flow consists of the following steps:
- Create and open the authorization URL in browser
- User logs in or registers and grants permissions
- After it's done, user clicks a button, which redirects to your redirect URL (It can be your deeplink)
- Your backend exchanges the code for access and refresh tokens
- Your backend requests a WebApp token using the access token
- Display the EarthMiles WebApp in a webview (see Web App Integration)
- Use the access token to make API requests when needed
- (optional) Refresh the token when it expires
sequenceDiagram
participant User as 👤 User
participant PApp as 📱 Partner App
participant PBackend as ⚙️ Partner Backend
participant Browser as � Browser/WebView
participant EMWebApp as 🖥️ EarthMiles WebApp
participant EMBackend as 🌍 EarthMiles Backend
Note over User, EMBackend: OAuth 2.0 with PKCE Authorization Flow
%% Step 1: Initialize OAuth Flow
User->>PApp: Clicks on the "Connect" button
PApp->>PBackend: Request starting the process
PBackend->>PBackend: Generate URL including 'client_id',<br/> 'code_verifier', 'code_challenge' & 'state'<br/>
PBackend->>PApp: Return authorization URL<br/>with PKCE parameters
PApp->>Browser: Open WebView/Browser<br/>and navigate to authorization URL
%% Step 2: User Authorization
Browser->>EMWebApp: Open and show the EarthMiles WebApp
EMWebApp->>Browser: Display login/registration page
User->>EMWebApp: Enter credentials & grant permissions<br/>(login or register)
EMWebApp->>EMBackend: Validate user credentials<br/>Process authorization request
EMBackend->>EMBackend: Authenticate user<br/>Generate authorization code
%% Step 3: Authorization Response
EMWebApp->>Browser: Display "See Rewards" button
User->>Browser: Click button to redirect
Browser->>PApp: Redirect to redirect_uri with code & state parameters
PBackend->>PBackend: Verify state parameter<br/>(CSRF protection)
%% Step 4: Token Exchange
PBackend->>EMBackend: POST /oauth/token
EMBackend->>EMBackend: Validate code_verifier<br/>against code_challenge
EMBackend->>PBackend: Return access and refresh token
PBackend->>PBackend: Store tokens securely
%% Step 5: Get WebApp Token & Display WebView
PBackend->>EMBackend: POST /oauth/webapp-token<br/>(with access token)
EMBackend->>PBackend: Return webapp token (1-hour expiry)
PBackend->>PApp: Return webapp token
PApp->>PApp: Inject token into WebView<br/>Load EarthMiles webapp
%% Step 6: API Calls
Note over PApp, EMBackend: Making Authenticated API Calls
PApp->>PBackend: Request user data/operations
PBackend->>EMBackend: GET /api/partner-api/me
EMBackend->>PBackend: Return user data
PBackend->>PApp: Return user data
PApp->>PApp: Display user's Earth Miles balance
Prerequisites
Before starting, ensure you have:
- Partner account with Earth Miles
- Client credentials (
client_id,client_secret) - Registered redirect URIs
Step 1: Authorization Request
Redirect users to the authorization endpoint to start the flow:
Required Parameters
| Parameter | Required | Description |
|---|---|---|
client_id |
✅ | Your registered client ID |
redirect_uri |
✅ | Must match registered redirect URI |
scope |
✅ | Space-separated scopes: miles:read miles:write |
state |
✅ | Random string to prevent CSRF attacks |
response_type |
✅ | Must be code |
code_challenge |
✅ | PKCE code challenge (see PKCE Guide) |
code_challenge_method |
✅ | Must be S256 |
Example Authorization URL
Once the parameters are generated, redirect the user to:
https://auth.earthmiles.app/oauth/authorize?
client_id=your_client_id&
redirect_uri=https://your-app.com/callback&
scope=miles:read%20miles:write&
state=random_state_string&
response_type=code&
code_challenge=CODE_CHALLENGE&
code_challenge_method=S256
Step 2: Handle Authorization Response
After the user authorizes, they will see a button to redirect back. When clicked, the user is redirected to your
redirect_uri with either an authorization code or an error.
Success Response
If authorized, clicking the button redirects to your redirect_uri with:
Error Response
If authorization fails:
https://your-app.com/callback?
error=access_denied&
error_description=The%20user%20denied%20the%20request&
state=random_state_string
Always verify the state parameter matches what you sent to prevent CSRF attacks.
Step 3: Exchange Code for Tokens
Use the authorization code to get access and refresh tokens:
Request Body
{
"grant_type": "authorization_code",
"code": "AUTHORIZATION_CODE",
"client_id": "your_client_id",
"client_secret": "your_client_secret",
"code_verifier": "ORIGINAL_CODE_VERIFIER"
}
Success Response
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "refresh_token_value",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "miles:read miles:write"
}
Step 4: Display EarthMiles WebApp
After successfully exchanging the authorization code for tokens, you must:
-
Request a WebApp token using the access token:
-
Display the EarthMiles WebApp in a webview within your application, injecting the webapp token for authentication.
For detailed implementation instructions, see the Web App Integration Guide.
User Experience
The user should seamlessly transition from the authorization flow directly into the EarthMiles webapp within your application. This provides a unified experience without requiring the user to navigate to a separate app.
Step 5: Making Authenticated Requests
Include the access token in the Authorization header:
curl https://backend.earthmiles.app/api/partner-api/award-points \
-H "Authorization: Bearer ACCESS_TOKEN"
Step 6: Refreshing Tokens
When the access token expires, use the refresh token to get a new one:
Request Body
{
"grant_type": "refresh_token",
"refresh_token": "refresh_token_value",
"client_id": "your_client_id"
}
Response
{
"access_token": "new_access_token",
"refresh_token": "new_refresh_token",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "miles:read miles:write"
}
Security Considerations
- Always use HTTPS in production
- Store tokens securely - never in localStorage or client-side storage
- Implement PKCE correctly (see PKCE Implementation Guide)
- Validate state parameter to prevent CSRF attacks
- Handle token expiration gracefully with refresh tokens