OAuth 2.0 — Before You Start: Pick the Right Flow for Your Website, SPA, Mobile App, TV App, and CLI
We learned how OAuth 2.0 works in general in What on Earth is OAuth? and learned how to securely store access tokens in the front end. In this post, we’ll learn which OAuth 2.0 flow you should use based on what you’re building.
OAuth 2.0 Recap:
In general, the OAuth 2.0 flow looks like this diagram below (if you’re not familiar with the OAuth 2.0 Flow below, check our explanation here).
- Step 1: The website requests authorization for Albert. Albert is being redirected to Google’s site to log in.
- Step 2: Google’s site returned with an Authorization Grant. This is the part that has several different cases based on which flow you’re using.
- Step 3–4: Depending on the flow, the client will have a way to exchange this Authorization Grant with an access token, and sometimes a refresh token
- Step 5–6: The website uses the access token to access resources.
Common OAuth 2.0 Flows
As mentioned above, there are 4 common OAuth 2.0 Flows:
- Authorization Code Flow
- Authorization Code Flow with Proof Key for Code Exchange (PKCE)
- Client Credentials Flow
- Device Code Flow
Which Flow Should I Use?
Different apps should use different flows based on whether or not the app can hold secrets securely.
- Web Server Apps and Command Line Scripts: Use Authorization Code Flow
- Single Page Apps and Mobile Apps: Use Authorization Code Flow with PKCE
- Server-to-Server API Calls: Use Client Credentials Flow
- TV Apps and other apps on input-constrained devices: Use Device Code Flow
Web Server Apps and Command Line Scripts
→ Use Authorization Code Flow
Web Server Apps are apps that are running on a server where the source code is not publicly exposed.
Requirements: Your app needs to be able to hold a Client Secret securely in the back end server.
For example:
- ✅ Your app runs on a server (Node.js, PHP, Java, .NET): Your server code is not publicly exposed and you can put secret keys in environment variables without it being visible to users of the application.
- ❌ React-only website: React is a SPA framework, your code is publicly exposed, and therefore cannot hold secrets securely, even if you put secrets in .env files.
Authorization Code Flow
- Step 1–4: User clicks Sign in with Google, and get redirected to Google’s Site to authenticate.
- Step 5: When the user successfully authenticated, Google will redirect the user back to your website, and include an
authorization_code
in the redirect URL. For example:
https://mysite.com/redirect
?code=ABCDEFGHIJ12345
&state=abcde123abc
- Step 6–9: With the code above and a Client ID + Client Secret that you get from Google when registering an application, you can request for an
access_token
for the user that you can then use to fetch data.
See the full spec at RFC 6749 Section 4.1
How do I do this from the command line?
- On step 3, show the URL that the user should go to in their browser.
- Get your script to listen to a local port, for example,
http://127.0.0.1:8000
and set the redirect URL to behttp://127.0.0.1:8000/redirect
- On step 5, the user’s browser will redirect to
https://127.0.0.1:8000/redirect
?code=ABCDEFGHIJ12345
&state=abcde123abc
- Your script should then handle this
GET
request, parse thecode
andstate
and proceed to step 6-9.
Single Page Apps & Mobile Apps
→ Use Authorization Code Flow with PKCE
Single Page Apps (SPA) and Mobile Apps are not able to hold secrets securely because their source code is publicly exposed or can be decompiled.
How does the PKCE flow work without a Client Secret?
The PKCE flow requires the app to generate a secret on the fly. This secret is generated at the beginning of the flow when the user started the login flow and then checked when exchanging authorization code with an access token.
This makes sure that the entity that is requesting to exchange the authorization code with an access token is still the same entity where the user requested to authenticate.
Authorization Code Flow with PKCE
- Step 1: User clicks the login button in your app
- Step 2: Generate a
code_verifier
andcode_challenge
, then make an authorization request by sending thecode_challenge
.
code_verifier = "a cryptographic random string"
code_challenge = base64url_encode(sha256(ascii(code_verifier)))
- Step 3–5: The Authorization Server will save the
code_challenge
for later and redirect the user to log in, then redirect to your app with anauthorization_code
- Step 6: Your app then sends the
code_verifier
,client_id
, andauthorization_code
to get an access token. - Step 7: The Authorization Server will check if the original
code_challenge == base64url_encode(sha256(ascii(code_verifier)))
. This is where it determines whether the entity that started this flow is the same one as the one that is currently requesting an access token. If yes, it returns the access token. - Step 8–9: Your app can now fetch data using the access token.
See the full spec at RFC 7636.
Here are some resources to help you generate a code challenge and verifier:
- Generate
code_verifier
andcode_challenge
online. - See how to generate
code_verifier
andcode_challenge
using JavaScript, Java, or Swift 3.
Server-to-Server API calls
→ Use Client Credentials Flow
For example, your back end server wants to call an API endpoint at Stripe to retrieve a list of payments. This is a machine-to-machine authorization, and there’s no end-user authorization. In this case, Stripe is only trying to authorize your server to access the API endpoint. Since your server can also hold secrets securely, all you need for accessing the data is a Client ID and Client Secret.
Client Credentials Flow
- Step 1: Your server authenticates itself using its Client ID and Client Secret. Notice that this doesn’t involve any user. This is because your server is acting as itself. (For example, your server is acting as Hello Merchant that you registered to Stripe).
- Step 2: If the Client ID and Client Secret checks out, you’ll receive an access token.
- Step 3: Use the access token to fetch data.
See the full spec at RFC 6749 Section 4.4
TV Apps and other apps on input-constrained devices
→ Use Device Code Flow
It’ll be horrible if you have to input your super-secure Google password to watch YouTube on your brand new smart TV, right? OAuth 2.0 Device Code Flow is designed so that you can authorize apps on an input constraint device by opening a URL and entering a code on your browser (on your phone/laptop).
Requirements: Your app needs to be able to display a URL and a User Code to the user. This can also be done by showing a QR Code.
Device Code Flow
- Step 1: User requests to log in on your TV App.
- Step 2–3: Your TV App makes an authorization request to the Authorization Server (Google Accounts in this case) with your app’s Client ID, and receive 3 things: a
device_code
, auser_code
, and averification_uri
. - Step 4: Your TV App now asks the user to go to the
verification_uri
and enter theuser_code
. You can optionally do this by asking the user to scan a QR Code that encodes both theverification_uri
and theuser_code
. - Step 5: Your TV App now requests an access token to the Authorization Server using the
device_code
andclient_id
. If the user hasn't authenticated and allowed access to your app yet (they haven't gone to theverification_uri
), the Authorization Server will respond with an errorauthorization_pending
. Your TV App should keep on requesting until you get an access token. - Step 6: The user typed in the
verification_uri
on their phone or laptop, and entered theuser_code
. - Step 7–8: The user is now redirected to Google’s Login page where they can authenticate and allow your TV App to access certain data.
- Step 9: Google accounts now mark that your user has authenticated and allowed your app to access their data. The next time your app requested for an access token with the
device_code
, Google Accounts will return an access token. - Step 10–11: Use the access token to fetch data.
See the full spec at RFC 8628 Section 3.4
That’s It!
This should help you pick which OAuth 2.0 flow you need for different use cases. We didn’t go into the specific HTTP Request parameters that you should use, we will cover that next time.
This post is written by the team at Cotter — we are building lightweight, fast, and passwordless login solution for websites and mobile apps. If you’re building a website, we have a ready-made solution that implements the flows above for you.
Sign in with Magic Link via Email, SMS, or WhatsApp on:
References
We referred to these articles and specs to write this post:
Questions & Feedback
If you need help or have any feedback, ping us on Cotter’s Slack Channel! We’re here to help.
Ready to use Cotter?
If you enjoyed this post and want to integrate Cotter into your website or app, you can create a free account and check out our documentation.
Originally published at https://blog.cotter.app on August 4, 2020.