Let’s Talk Single Sign On — OAuth — OpenID — RHSSO
Imagine logging into Gmail, providing your username and password. Pressing the buttons, investing the time and effort of remembering and typing the long password you have created for your account; You are logged into Gmail now, you have read your emails, you decide that you need to log into Google Drive to check on some photos you have saved there a while back. Somehow, without any questions or prompts, you are logged into Google Drive. You have not provided any password, you have not provided any username or authentication method; Somehow, by some kind of magic, the credentials you have provided for Gmail were passed to your Google Drive, and they will keep passing to every application Google supports. Some people call this magic, but some call it Single Sign On.
In this blog I’m going to go through the basics of Single Sign On (SSO), OAuth2 and Open ID Connect (OIDC) using Red Hat Single Sign On (RHSSO) and it’s upstream project, Keycloak.
Intro
As mentioned before, the main idea of single sign on is to have a single authority that controls the authentication and authorization process to all of the applications in an organization; Working without an SSO source means that every application has to manage its own authentication methods, its own authorization techniques and its own users database — Working in such manner could prove both insecure and inefficient.
Security
Moving forward with an SSO platform would probably be more secure than trying to manage the sign-in mechanism by yourself. The SSO platform secures the connection between the user and the application, while providing a secure authentication process using techniques like OIDC or SAML.
Creating your own authentication mechanism, together with your own DB and your own user validation process could be open to security breaches and leaks. Following a standard like OIDC in this case is more secure.
Efficiency
Having a single source of truth in an organization is better than having many unreliable application developers that try to implement their own way of authenticating users; Each application would have a different implementation of authentication, and therefore each time you would like to move from one application to another, you would have to provide some sort of credentials again.
Cloud Native
In general usage, “cloud-native” is an approach to building and running applications that exploits the advantages of the cloud computing delivery model.
Some people might say “I have an Active Directory in my organization, I can manage authentication through domain protocols, like Kerberos“. That’s a correct statement, but it does not correspond with the fast moving world of cloud native applications; Most applications nowadays do not rely on some kind of domain to manage authentication or authorization. Let’s take Google for example again, you are probably using Google’s single sign on mechanism right now, while your laptop, or phone, is not connected directly to Google’s directory service.
Many organizations changed their model of work in the past years and started to include public or private cloud applications in their environment. Therefore, these organizations needed to include Single Sign On mechanisms in their environment to coexist with the cloud environment to create an authentication and authorization authority which is not dependent on the organization’s structure and internal services.
OAuth2 and OpenIDC
Lets talk about the two standards that the SSO mechanism follows — OAuth and OIDC (OpenID Connect).
People tend to mix OAuth and OIDC up, some people think that they are the same thing, some people think that they are some sort of magic protocols and some, don’t even take the time to understand them. Therefore, in this short section, I’m going to try to dive as deep as possible into these standards, while keeping it simple.
OAuth2
OAuth is an open standard for access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords. — Wikipedia
As stated in the quote above, OAuth is a standard that allows users to delegate control over resources from one application to another, without letting the “client” application know the password or credentials of the user involved in the process.
Let’s take Gmail as an example for OAuth on the internet. Currently I’m writing an application that involves sending emails from my account to accounts of my teammates using my Gmail profile. Providing my Google’s account credentials in plain text in the application would not be safe, but using OAuth solves this issue perfectly, as mentioned before, when you use OAuth, you do not pass your user’s credentials to your application!
Let’s follow this example to understand the OAuth flow.
OAuth Terminology
Before I start with OAuth’s acces delegation flow, lets understand some of the terminology and components of OAuth.
API client ID and secret
When you start using Gmail’s API you need to register your application to Gmail. After you enable the API, Google will provide a Client ID and a Client Secret for your application.
The Client ID and Client Secret will be used to identify your application against Gmail. These two pieces of information will be implemented in the application’s code and will be passed to Gmail’s authorization server when Gmail’s API will be invoked in the application.
Auth Flows
There are different ways in which an application could authenticate a user and gain an access token from the authorization server, these flows have different requirements and operate in different ways. The most common flows are:
- Authorization Code Flow
- Implicit Flow
- Direct Grants
- Client Credentials Grant
In my demonstration I’m going to follow and describe the Authorization Code Flow. Information regarding the rest of the Flows could be found at the OAuth Documentation.
Scopes
When you let an application access your account, in this case, your Gmail account, you want to “scope” the access which the application has. In some cases, you would want an application to only read mails from your inbox, and in some cases you would want an application to only send mails on behalf of your account.
Scopes were invented exactly for this reason. By specifying scopes you limit the access which the application has. In my case, I want my application to only compose mails on behalf of my Gmail account, so I specify the gmail.compose scope.
SCOPES = ['https://www.googleapis.com/auth/gmail.compose']
OAuth Flow
After understanding some of the terminology of OAuth, let’s start understanding the flow of OAuth in my mail sending application.
Step 1
The user starts using my web application, and presses the send mail button. By pressing this button, the application user invokes the Gmail API and starts the OAuth Authorization Code Flow.
My web application redirects the browser to Gmail’s authorization endpoint, and requests an authorization code.
Authorization code — Is a crucial code which the authorization server hands the application. It is used to validate the application and grant it an access token in the next steps. The authorization code is very short lived and is valid for one use only.
The next arguments are passed together with the GET request -
- Redirect URI — The URI which Gmail’s authorization server will need to redirect the browser to after it finishes validating the user and producing the authorization code.
- Scope — The authorization scope that is wanted by the application. As described in the previous section, since I only want to compose an email, my scope will be gmail.compose.
- Client ID — The application will pass the client ID which was generated by Gmail’s authorization server in the previous section.
- Response Type — The application will also specify that the wanted response from the authorization server in the request is the authorization code.
Step 2
After the request has been sent, Google pops up a windows in which I have to log into my account, and consent to the application to send emails on my behalf.
With the permission granted, the authorization server redirects the browser back to the Redirect URI I have specified in the GET request, and sends the authorization code to the application.
Step 3
So far, all of the data has been transmitted using the browser and redirects. The browser is not considered to be a safe channel to transport sensitive data on. Therefore, the application needs to make one more step, and validate the authorization code it got from the Authorization server together with the client secret against Google’s authorization server on a safe back channel network (outside of the browser’s reach).
Reminder: the client secret is the code that Google has generated for me when I registered my application.
The application send a POST request to the autherization server’s token endpoint, and requests an access token.
Access tokens are the thing that applications use to make API requests on behalf of a user. The access token represents the authorization of a specific application to access specific parts of a user’s data. — oauth.com
Step 4
The Authorization server evaluates the information gained from the application. it validates the client id and secret. It checks the Authorization code and validates that it hasn’t been used before.
If everything checks out, the authorization server generates an access token, and passes it back to the application on the secure back channel network.
Step 5
Now that the application has an Access Token, it is able to start accessing Gmail’s API. The application will attach the Access Token to the authorization header in the requests it sends over to the API server, and the API server will validate the Access Token. It will check the integrity of the token, the scopes of the application, and whether it is trying to make an illegal request. If everything checks out, the access is granted to the API of the requested service, in our case, Gmail.
OpenID Connect
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server. — openid.net
So far, we have covered the OAuth flow. As you can see, OAuth’s purpose is authorization, the Gmail application did not get any information about the user I have used to log in into Gmail’s authorization server. OAuth just validates whether an application is allowed to make a certain action with the API or not.
Some applications require information about the user that has been authenticated via the authorization server. And for this reason OpenID has been created. OpenID adds another layer on top of OAuth and passes the application another piece of information alongside the access token - an ID token.
ID tokens are JSON Web Tokens (JWT) containing information about the authenticated user.
JWT — An open, industry standard RFC 7519 method for representing claims securely between two parties. — auth0.com
Applications use the contents of ID tokens to understand who is the user that has logged in and customize its experience. The application could extract information such as the first name of the authenticated user, and created a customized welcome screen for it.
OpenID Flow
The OpenID Flow is not much different than the OAuth flow, since it is just another layer on top of it. Let’s cover the flow and understand the differences.
The user accesses the application using a browser. So far, not that different.
Just like with the OAuth flow, the application will redirect the browser to the authorization server to generate an authorization code, but this time, an openid scope will be added to request, indicating that an OpenID process needs to be initialized.
The application will return an authorization code.
Now, the application will use the back channel to reach to the authorization server, and generate the tokens.
Now, in addition to the standard Access Token that the authorization server produces in the OAuth flow, the authorization server will return an ID Token as well.
The application will be able to parse the ID token, and extract the needed values from it in order to customize each logged in user’s experience differently.
By inspecting the ID token, I can find information about the user that initiated the authentication process against the authorization server.
"name": "Michael Kotelnikov",
"preferred_username": "michael",
"given_name": "Michael",
"family_name": "Kotelnikov",
"email": "mkotelni@redhat.com"
Example
Let’s take a simple look of the ID token implementation. I have a simple application that is connected to my custom authorization server. The purpose of this application is to redirect me to the authorization server as soon as I press “Login”. After the authentication process completes, the application will redirect me to a welcome screen with my name printed on it.
Using my browser, I have entered the welcome page of my application and pressed on the Login button.
The Login button has redirected me to my custom authorization server to provide my user’s credentials.
After I’ve provided my credentials, the authorization server completes the OAuth and OpenID flow, and generates an access and ID token. The application is now able to parse the ID token and extract my name from it.
Red Hat Single Sign On — RHSSO
Now you know the basics of OpenID Connect and OAuth, and you would certainly like to implement these protocols in your organization. It does not matter if your organization is connected or disconnected from the internet, Red Hat Single Sign On (RHSSO) is able to provide OpenID services to your environment.
RHSSO acts as an authorization server which controls the authentication and authorization between users and applications in the environment. Using RHSSO in your organization could secure applications, control the scopes of the users, and control access of users to certain resources.
RHSSO can run as a container on OpenShift or as a virtual machine. Further documentation regarding RHSSO deployment can be found at: RHSSO Documentation.
RHSSO demonstration and terminology
To demonstrate RHSSO on my laptop, I’m going to run a container of the upstream project that stands behind it, Keycloak. Keycloak can be deployed free of charge and has the same features as RHSSO, but it does not have any support behind it.
To run Keycloak on my RHEL laptop, I run the next command:
podman run -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -e DB_VENDOR=H2 jboss/keycloak
RHSSO clients
When using RHSSO, each application connected to it will be represented as a Client, and each department in the organization will be represented as a Realm. For example, the “quality-checker” client will be created in the “QA” realm for the “quality-checker” app in the QA department.
When inspecting the “quality-checker” client, I will be able to find information like, the client ID and client secret which will be used by the application, the scopes that are configured for the application, and even valid redirect URIs.
Valid redirect URI — A URI pattern that the browser is allowed to redirect to after a successful login. This stops the browser from passing confidential information to malicious sources.
Using RHSSO you will be able to see the open sessions for your applications -
And you can easily import the client configuration from RHSSO into your application by moving to the “Installation” screen —
RHSSO users
For each Realm, or department in the organization there will be a different user source. The users will be used to authenticate against the clients which are registered in the same realm. The users can be created locally on the RHSSO server —
The users can be imported from a different OpenID source, like GitHub, Google or even Instagram —
And, the users can be even imported for an Active Directory, or an Identity Management server.
By combining both user management and application registration, RHSSO allows every application to implement a simple but safe authentication process, and to have control over the users trying to use it.
Conclusion
Modern organizations require modern solutions, and RHSSO is an essential part of many organizations path towards success. Modern applications do not need to create their own way of authenticating users when they can just implement an OpenID server.
As described in the beginning of the blog, going with OpenID is more secure, more efficient and enables a whole new world of access control management, auditing and modernization.
Allow users to compose mails with Gmail API, authenticate users from GitHub in your own application and control the data your applications extract from ID tokens. Do all of that with OAuth2, OpenID Connect and Red Hat Single Sign On.
Thank you for reading!