OAuth 1.0 Authorization Flow — Step by Step
Walk through the complete OAuth 1.0 authorization flow from registration to protected resource access — with consistent concrete examples, callback URL mechanics, the verifier, and the browser's role at every stage.
Before We Begin
In the previous parts, you learned:
- Why OAuth exists — to eliminate password sharing.
- What the seven credentials are and what each one proves.
Now we walk through the complete protocol flow, step by step, using concrete values at every stage.
You can watch the same flow as a step-by-step simulation. It uses these credentials: photo-app-123, SECRET_APP, REQUEST_ABC, and ACCESS_123.
Our Running Example
Actors
| Entity | Role |
|---|---|
| Alice | Resource Owner (user) |
| PhotoApp | Consumer (third-party application) |
| PhotoProvider | Service Provider |
Credentials (as they are issued)
| Credential | Value |
|---|---|
consumer_key | photo-app-123 |
consumer_secret | SECRET_APP |
request_token | REQUEST_ABC |
request_token_secret | REQUEST_SECRET |
oauth_verifier | VERIFIER_XYZ |
access_token | ACCESS_123 |
access_token_secret | ACCESS_SECRET |
Complete Flow Overview
The OAuth 1.0 authorization process consists of six stages:
- Application Registration (one-time setup)
- Request Token (server-to-server)
- User Authorization (browser)
- Callback + Verifier (browser → server)
- Access Token Exchange (server-to-server)
- Protected Resource Access (server-to-server)
Now let’s examine each stage in detail.
Step 0 — Application Registration
Before any OAuth flow can happen, PhotoApp must register with PhotoProvider.
This is a one-time setup, not part of the per-user flow.
What Happens
PhotoApp’s developer visits PhotoProvider’s developer portal and registers the application. During registration, PhotoApp provides:
- Application Name: PhotoApp
- Description: Photo editing and collage application
- Callback URL:
https://photoapp.example.com/oauth/callback
PhotoProvider responds with application credentials:
consumer_key=photo-app-123consumer_secret=SECRET_APP
What Each Actor Knows After This Step
| Actor | Knowledge |
|---|---|
| PhotoApp | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP |
| PhotoProvider | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ callback_url = https://photoapp.example.com/oauth/callback |
| Alice | (nothing — she hasn’t interacted with anything yet) |
Step 1 — Obtain a Request Token
Alice clicks “Connect my PhotoProvider account” inside PhotoApp. Behind the scenes, PhotoApp starts the OAuth process.
What Happens
PhotoApp sends a signed server-to-server request to PhotoProvider:
POST /oauth/request_token HTTP/1.1
Host: photoprovider.example.com
Authorization: OAuth
oauth_consumer_key="photo-app-123",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1780000000",
oauth_nonce="7d8f3a2b",
oauth_callback="https://photoapp.example.com/oauth/callback",
oauth_signature="..."
The signature is computed using the Consumer Secret (SECRET_APP). We will cover signing in detail in Part 4.
How PhotoProvider Responds
PhotoProvider verifies:
- Is
photo-app-123a registered application? - Is the signature valid (using its copy of
SECRET_APP)?
If both checks pass, PhotoProvider creates a temporary Request Token and responds:
HTTP/1.1 200 OK
oauth_token=REQUEST_ABC
&oauth_token_secret=REQUEST_SECRET
&oauth_callback_confirmed=true
What Each Actor Knows After This Step
| Actor | Knowledge |
|---|---|
| PhotoApp | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ request_token = REQUEST_ABC (NEW) ✅ request_token_secret = REQUEST_SECRET (NEW) |
| PhotoProvider | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ request_token = REQUEST_ABC (NEW, stored, linked to photo-app-123) ✅ request_token_secret = REQUEST_SECRET (NEW) |
| Alice | (still nothing — this was server-to-server) |
The Request Token does not grant access to Alice’s photos. It is a placeholder for an authorization process that has not yet been approved.
Step 2 — User Authorization
This is the step where Alice gets involved. And it is critical to understand who logs in where.
Who Logs In Where
- CORRECT: Alice ──────► PhotoProvider (username + password)
- NOT: Alice ──────► PhotoApp ──────► PhotoProvider (password)
Alice logs in directly at PhotoProvider. PhotoApp never sees, handles, or proxies Alice’s password.
What Happens
Step 2a — PhotoApp redirects Alice’s browser.
PhotoApp constructs a URL and sends Alice’s browser there:
HTTP/1.1 302 Found
Location: https://photoprovider.example.com/oauth/authorize
?oauth_token=REQUEST_ABC
Alice’s browser navigates to PhotoProvider.
Step 2b — Alice logs in at PhotoProvider.
PhotoProvider displays its own login page. Alice enters her PhotoProvider username and password directly into PhotoProvider’s website.
PhotoProvider Login Username:
[ [email protected] ]Password:[ •••••••• ][ Log In ]
PhotoProvider authenticates Alice. This is authentication — verifying Alice’s identity.
Step 2c — Alice reviews the consent screen.
After login, PhotoProvider shows Alice what PhotoApp is asking for:
PhotoProvider PhotoApp wants permission to:
- ✓ Read your photos
- ✓ View your albums
[ Allow ] [ Deny ]
This is authorization — Alice is granting (or denying) permission.
(Note: The exact permissions shown on the consent screen are provider-specific; OAuth 1.0 does not define a universal scope mechanism like OAuth 2.0.)
Step 2d — Alice clicks “Allow”.
Alice approves. PhotoProvider now knows:
- Alice (authenticated user) has authorized
- the Request Token
REQUEST_ABC(which is linked to PhotoApp) - for the requested permissions.
The Browser’s Role
The browser is the transport mechanism, not an actor in the protocol:
PhotoApp told the browser where to go. Alice interacted with PhotoProvider through her browser. PhotoApp was not involved during the login and consent steps.
What Each Actor Knows After This Step
| Actor | Knowledge |
|---|---|
| PhotoApp | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ request_token = REQUEST_ABC ✅ request_token_secret = REQUEST_SECRET ❌ Alice’s password (never received) |
| PhotoProvider | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ request_token = REQUEST_ABC (now marked as “authorized by Alice”) ✅ request_token_secret = REQUEST_SECRET ✅ Alice’s identity = authenticated ✅ oauth_verifier = VERIFIER_XYZ (NEW, created, linked to REQUEST_ABC) |
| Alice | ✅ She knows she approved PhotoApp ❌ She does not know any OAuth credentials |
Step 3 — Callback + Verifier
After Alice approves, PhotoProvider redirects her browser back to PhotoApp.
What Is the Callback URL?
The callback URL is a URL that PhotoApp registered with PhotoProvider during application registration.
callback_url = https://photoapp.example.com/oauth/callback
| Question | Answer |
|---|---|
| What is it? | A URL on PhotoApp’s server that receives the authorization result |
| Why does it exist? | So PhotoProvider can return authorization information to PhotoApp through the browser redirect |
| Who invokes it? | PhotoProvider, by redirecting Alice’s browser to it |
| Why must it be associated with the Consumer? | To prevent an attacker from substituting a different callback and intercepting the verifier |
| What information comes back through it? | The Request Token and the OAuth Verifier |
What Happens
PhotoProvider redirects Alice’s browser:
HTTP/1.1 302 Found
Location: https://photoapp.example.com/oauth/callback
?oauth_token=REQUEST_ABC
&oauth_verifier=VERIFIER_XYZ
Alice’s browser follows this redirect and makes a request to PhotoApp’s callback URL.
PhotoApp now has the oauth_verifier = VERIFIER_XYZ.
Why the Verifier Exists
The Request Token alone is not proof that Alice approved the request. Here’s why:
Without verifier:
- PhotoApp obtains Request Token
- User authorization somehow happens
- PhotoApp exchanges Request Token for Access Token
Problem: How does PhotoProvider know the exchange request corresponds to an actual user approval?
The verifier solves this:
With verifier:
- PhotoApp obtains Request Token
- Alice approves → PhotoProvider creates
VERIFIER_XYZ VERIFIER_XYZis delivered to PhotoApp through the callback- PhotoApp presents
VERIFIER_XYZduring the exchange
PhotoProvider can verify:
REQUEST_ABCwas approvedVERIFIER_XYZwas created for that approval- The exchange request includes the matching verifier
The verifier binds the user’s approval to the token exchange. It confirms that the provider issued an authorization result for that Request Token and that the Consumer presenting it can complete the exchange.
What If the Request Token Is Stolen?
Suppose an attacker intercepts REQUEST_ABC. What can they do?
Scenario: Request Token is stolen Result: Can the attacker get an Access Token? NO. Here’s why:
- Request Token ≠ Access Token: It does not grant resource access by itself.
- User authorization is still required: The Request Token alone is insufficient to complete the Access Token exchange. The attacker would still need the required secrets and the authorization result associated with that token.
- The verifier is needed: Even if the Request Token is somehow authorized, the verifier is delivered to PhotoApp’s registered callback URL, not to the attacker.
- The exchange request must be signed: The attacker doesn’t have the Consumer Secret or the Request Token Secret to sign the exchange request.
- HTTPS protects the flow in transit: The Request Token was delivered over HTTPS, making interception much harder.
The Request Token is designed to be low-value if compromised. It is temporary, requires additional credentials and user action to be useful, and expires quickly.
What Each Actor Knows After This Step
| Actor | Knowledge |
|---|---|
| PhotoApp | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ request_token = REQUEST_ABC ✅ request_token_secret = REQUEST_SECRET ✅ oauth_verifier = VERIFIER_XYZ (NEW) |
| PhotoProvider | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ request_token = REQUEST_ABC (now authorized by Alice) ✅ request_token_secret = REQUEST_SECRET ✅ oauth_verifier = VERIFIER_XYZ (linked to REQUEST_ABC) |
| Alice | ✅ She approved the request (Her part in the flow is done) |
Step 4 — Exchange Request Token for Access Token
PhotoApp now has everything it needs: the Request Token, the Verifier, and its own secrets.
What Happens
PhotoApp sends a signed server-to-server request to PhotoProvider:
POST /oauth/access_token HTTP/1.1
Host: photoprovider.example.com
Authorization: OAuth
oauth_consumer_key="photo-app-123",
oauth_token="REQUEST_ABC",
oauth_verifier="VERIFIER_XYZ",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1780000060",
oauth_nonce="9c4e1d5f",
oauth_signature="..."
The signature for this request is computed using:
Signing Key = consumer_secret & request_token_secret
= SECRET_APP & REQUEST_SECRET
How PhotoProvider Validates
PhotoProvider performs multiple checks:
- Is
oauth_consumer_keyvalid?- Look up
photo-app-123 - ✅ Found
- Look up
- Is
oauth_tokenvalid?- Look up
REQUEST_ABC - ✅ Found, and it belongs to
photo-app-123
- Look up
- Has
REQUEST_ABCbeen authorized by a user?- ✅ Alice authorized it
- Is
oauth_verifiercorrect?- Compare
VERIFIER_XYZwith the stored verifier forREQUEST_ABC - ✅ Match
- Compare
- Is the signature valid?
- Recalculate using
SECRET_APP&REQUEST_SECRET - Compare with the received signature
- ✅ Match
- Recalculate using
All checks pass → Issue Access Token
Response
PhotoProvider creates the Access Token and responds:
HTTP/1.1 200 OK
oauth_token=ACCESS_123
&oauth_token_secret=ACCESS_SECRET
PhotoProvider also invalidates the Request Token. It can never be used again.
What Each Actor Knows After This Step
| Actor | Knowledge |
|---|---|
| PhotoApp | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ❌ request_token = REQUEST_ABC (INVALIDATED) ❌ request_token_secret = REQUEST_SECRET (INVALIDATED) ❌ oauth_verifier = VERIFIER_XYZ (USED, no longer needed) ✅ access_token = ACCESS_123 (NEW) ✅ access_token_secret = ACCESS_SECRET (NEW) |
| PhotoProvider | ✅ consumer_key = photo-app-123 ✅ consumer_secret = SECRET_APP ✅ access_token = ACCESS_123 (linked to Alice + photo-app-123) ✅ access_token_secret = ACCESS_SECRET |
Step 5 — Access Protected Resources
PhotoApp can now access Alice’s photos.
What Happens
PhotoApp constructs a signed API request:
GET /photos HTTP/1.1
Host: api.photoprovider.example.com
Authorization: OAuth
oauth_consumer_key="photo-app-123",
oauth_token="ACCESS_123",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1780000120",
oauth_nonce="b2a8c7e4",
oauth_signature="..."
The signature for this request is computed using:
Signing Key = consumer_secret & access_token_secret
= SECRET_APP & ACCESS_SECRET
How PhotoProvider Validates
- Is the Access Token valid? → Look up
ACCESS_123→ ✅ Found, linked to Alice + PhotoApp - Is the timestamp acceptable? → ✅ Within allowed window
- Has this nonce been used before? → ✅ Not seen before (no replay)
- Is the signature valid? → Recalculate using
SECRET_APP&ACCESS_SECRET→ Compare with received signature → ✅ Match - Does ACCESS_123 have permission for GET /photos? → ✅ Alice authorized photo read access
All checks pass → Return the resource
Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"photos": [
{"id": "1", "title": "Sunset", "url": "..."},
{"id": "2", "title": "Mountains", "url": "..."},
{"id": "3", "title": "Beach", "url": "..."}
]
}
PhotoApp receives Alice’s photos without ever knowing her password.
Where Each Credential Exists at Each Stage
This table tracks every credential across the entire flow:
| Credential | Reg. (0) | Req. Token (1) | User Auth (2) | Callback (3) | Token Exch. (4) | API Access (5) |
|---|---|---|---|---|---|---|
| consumer_key | ✅ | ✅ | — | — | ✅ | ✅ |
| consumer_secret | ✅ | ✅ | — | — | ✅ | ✅ |
| request_token | — | ✅ | ✅ | ✅ | ✅ | ❌ |
| request_token_secret | — | ✅ | — | — | ✅ | ❌ |
| oauth_verifier | — | — | — | ✅ | ✅ | ❌ |
| access_token | — | — | — | — | ✅ | ✅ |
| access_token_secret | — | — | — | — | ✅ | ✅ |
✅ = Active and in use, ❌ = Invalidated / no longer valid, — = Does not exist yet
The Complete Flow — Simplified Diagram
What Comes Next
You have now seen the complete OAuth 1.0 authorization flow in action — every step, every credential, every actor.
But one critical detail has been glossed over: request signing. Every OAuth request that requires Consumer authentication or access to protected resources is cryptographically signed. How does that work? Why is it necessary? What does it protect against?
In the next part, we will dive deep into the request signing mechanism — the signature base string, HMAC-SHA1, the nonce, timestamps, and replay attack protection.
Key Takeaways
- Six stages: Registration → Request Token → User Auth → Callback → Token Exchange → API Access
- Alice logs in at PhotoProvider, NOT at PhotoApp. PhotoApp never receives Alice’s password.
- The browser is a transport mechanism: PhotoApp → redirect → browser → PhotoProvider, PhotoProvider → redirect → browser → PhotoApp
- The callback URL is registered with the Provider to prevent interception of the verifier.
- The verifier binds user approval to the token exchange.
- A stolen Request Token is low-value: temporary, requires user approval, needs the verifier, and the exchange must be signed.
- After exchange, the Request Token is invalidated. Only the Access Token survives.
- Every OAuth request that requires Consumer authentication or access to protected resources is signed. Signing is covered in the next part.