What Is OAuth?
Jinhua Luo
November 18, 2022
Creating new accounts for all different websites has always been troublesome. Most of them are redundant work, as they all contain the same user information, such as name and phone number.
“Is it possible to allow an app to access my data without necessarily giving it my password?”
OAuth is a standard that tries to solve this problem by providing centralized authorization.
OAuth, which stands for “Open Authorization,” is an open standard for access delegation. It allows you (resource owners) to share information between applications and websites without exposing your passwords. It is widely used, and you probably use OAuth services daily. For example, to log on to GeeksforGeek, you can opt to log on using your Google account. By doing so, you authorize GeeksforGeek to access some of the information on your Google accounts, such as username, profile picture, etc.
History of OAuth
OAuth 1.0 protocol was published as RFC 5849, an informational Request for Comments, in April 2010.
OAuth 2.0 protocol was published as RFC 6749, and OAuth 2.0 Bearer Token Usage was published as RFC 6750, in October 2012.
Albeit being built on the OAuth 1.0 deployment experience, OAuth 2.0 is a complete rewrite of OAuth 1.0 from the ground up, sharing only overall goals and general user experience. OAuth 2.0 is not backwards compatible with OAuth 1.0.
How OAuth 2.0 Works
In the OAuth protocol, instead of using the resource owner’s username and password to access protected resources, the client uses an access token. The client obtains the access token from an authorization server upon the approval of the resource owner. For the resource owner to grant authorization to the client, he has to be authenticated on the application first. And since the authentication was only between the resource owner and the application, the third-party client is unable to know any private information of the resource owner.
We can see that implementing the OAuth protocol will significantly simplify the third-party client’s authentication process. All it needs to do is get authorization from the user, request the access token, use it, and get the user information (protected resource). It will not require new users to register accounts or expose their credentials, thus reducing the attack surface and increasing network security.
It is worth noting that OAuth is not authentication. The Auth here is authorization. The user doesn't log in to the application. It only authorizes the third-party application to obtain some of his information.
OAuth’s Authorization Process
Roles
OAuth defines four roles:
Client - The application that wants to access your (resource owner) data and make protected resource requests on behalf of the resource owner and with its authorization.
Resource owner - A user that owns the data in the resource server, wants to use the client’s service and has an account on the authorization server. For example, I am the resource owner of my Facebook profile, and I want to use GeeksforGeeks' service.
Authorization server - The main engine of OAuth. Issues access tokens to the client after successfully authenticating the resource owner and obtaining authorization.
Resource server - The server that stores data the client wants, capable of accepting and responding to protected resource requests using access tokens.
OAuth Protocol Flow
Step A: The third-party application requests authorization from the user
Step B: The third-party application receives an authorization grant, which is a credential representing the resource owner’s authorization
Step C: The third-party application requests an access token using the authorization grant
Step D: The authorization server authenticates the client and validates the authorization grant, if valid, it issues an access token to the third-party application
Step E: The third-party application uses the access token to request the protected resources from the resource server
Step F: The resource server validates the access token and serves the request if valid
Authorization Code and Access Token
There are four types of authorization grant to obtain access tokens from authorization servers. We will only talk about the Authorization Code method here, as it is the safest and most common method.
Step A: The third-party application lets the user choose an authorization method, such as GitHub, and then redirects the user to the authorization server with parameters such as client_id
and redirect_uri
Request sample:
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
Step B: The user logs in and authorizes
Step C: The authorization server redirects the user back to the backend of the third-party application according to the redirect_uri
, providing the authorization code
Response sample:
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
Step D: The third-party application uses the authorization code to exchange for the access token from the authorization server
Request example:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
Step E: The authorization server validates and returns the access token
Sample response from the authorization server:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
A Concrete Example
Bob wants to pretty print out his Amazon orders using some software called Rabbit.
Resource owner -> Bob
Client (third-party application) -> Software Rabbit
Authorization Server -> Amazon’s authorization server
Resource Server -> Amazon’s databases for storing order information
Protected Resources -> Bob’s order information on Amazon
Why Should the Authorization Code and Access Token Be Obtained Separately?
The authorization code and access token are obtained separately to ensure security measures.
In the OAuth2 protocol, the authorization code is a temporary code that the client will exchange for an access token. The code is obtained from the authorization server, where the user (resource owner) has a chance to see what information the client requests and approve or deny the request.
Once the user logs in and authorizes successfully, they are redirected back to the application with a temporary authorization code in the URL.
This authorization code is generally valid for ten minutes and one time only. The short validity period reduces the risk of leaking user information if it gets stolen. In contrast, the validity period of access_token is relatively long, usually 1 to 2 hours. If it leaks, it may impose greater danger to users’ data security.
Moreover, to exchange for an access token, the client will need to provide client ID
and client secret
in addition to the authorization code. The authorization server needs these parameters to authenticate the client and check that the one requesting the access token is trustworthy. If the authorization code is misfortunately leaked, but the hacker doesn’t have the client ID
and client secret
, he still wouldn’t be able to obtain the access code. Even if he somehow has the client ID
and client secret
, he will still need to race with the client-server, because the authorization code is one time only. This mechanism significantly increases the difficulty of potential attacks. If we skip the step of obtaining the authorization code and return the access token directly, the attacker may use the access token to steal user information easily.
OIDC (OpenID Connect)
What is the purpose of using OAuth for authorization? It is to obtain all kinds of information about the user. Why can’t we standardize the output so third-party applications can use it directly?
OIDC does this standardization.
How does OIDC do it? Simply put, it returns an additional JWT
format id_token
containing the basic user information with the access token
. Third-party applications can obtain user information by checking the signing algorithm and verifying the signature on the id_token
with a public key.
In addition, OIDC provides the UserInfo endpoint. Third-party services can use the access token to access this endpoint to obtain additional information about the user.
Another feature of OIDC is Single Sign On (SSO) and Single Log Out (SLO). SSO improves usability by enabling the user to have authenticated sessions with different clients without having to provide credentials every time. As long as the user successfully logs in to one application, there is no need to enter the password again when he logs in to other applications.
SLO improves security by ensuring no active sessions are left from an SSO session after the user initiates a single logout. Users only need to log out once and get all sessions terminated, preventing them from being hijacked or misused.
It is worth noting that OIDC is not standardizing a specific authentication method, such as passwords or facial recognition. Instead, it specifies how to delegate authentication to a centralized authentication provider, what we get after authentication - id token
, how this token gets verified - JWT
format, and what user information this id token
contains. So, third-party applications do not need to reinvent the wheel anymore.
APISIX’s Support for OAuth/OIDC
Apache APISIX is an open-source cloud-native API gateway. It is a dynamic, real-time, high-performance API Gateway and you can use it to handle traditional north-south traffic, as well as east-west traffic between services. It can also be used as a k8s ingress controller.
Since APISIX is an API gateway that acts as a proxy for multiple upstream application servers, it is most natural to place centralized authorization and authentication on the API gateway.
APISIX's OpenID Connect (OIDC) plugin supports the OpenID Connect protocol. Users can use this plugin to connect APISIX with many identity providers (IdP), such as Okta, Keycloak, Ory Hydra, Authing, etc., and deploy it as a centralized authentication gateway. OIDC is a superset of OAuth, so this plugin also supports OAuth.
Deployment diagram:
Configuration Sample: Integrate Keycloak for Authentication with Apache APISIX
Configure Keycloak
Parameter | Value |
---|---|
keycloak address | http://127.0.0.1:8080/ |
Realm | myrealm |
Client Type | OpenID Connect |
Client ID | myclient |
Client Secret | e91CKZQwhxyDqpkP0YFUJBxiXJ0ikJhq |
Redirect URI | http://127.0.0.1:9080/anything/callback |
Discovery | http://127.0.0.1:8080/realms/myrealm/.well-known/openid-configuration |
Logout URI | /anything/logout |
Username | myuser |
Password | myrealm |
Realm | mypassword |
Sample code
curl -XPUT 127.0.0.1:9080/apisix/admin/routes/1 -H "X-API-KEY: edd1c9f034335f136f87ad84b625c8f1" -d '{
"uri":"/anything/*",
"plugins": {
"openid-connect": {
"client_id": "myclient",
"client_secret": "e91CKZQwhxyDqpkP0YFUJBxiXJ0ikJhq",
"discovery": "http://127.0.0.1:8080/realms/myrealm/.well-known/openid-configuration",
"scope": "openid profile",
"bearer_only": false,
"realm": "myrealm",
"redirect_uri": "http://127.0.0.1:9080/anything/callback",
"logout_path": "/anything/logout"
}
},
"upstream":{
"type":"roundrobin",
"nodes":{
"httpbin.org:80":1
}
}
}'
When you visit http://127.0.0.1:9080/anything/test after the API is created successfully, you will be directed to Keycloak's login page because you have not logged in:
Enter myuser as username and mypassword as password, and you will be directed to the following page.
Visit http://127.0.0.1:9080/anything/logout to log out:
Summary
In short, the OAuth standard is a popular solution for both applications and users. It provides convenience and security by allowing users to utilize services across multiple platforms without sharing their credentials. Apache APISIX is a popular API Gateway that supports the integration of various identity providers (Keycloak, Ory Hydra, Okta, Auth0, etc.) to protect your APIs.
Read more sessions: