How to implement single sign-on through OIDC protocol?


What is single sign-on

Let’s use an example to illustrate, suppose there is a university, there are two internal systems, one is the mailbox system, one is the class schedule query system. Now you want to achieve such an effect: log in once in the mailbox system, and then enter the website of the schedule system. There is no need to log in again, and the system of the schedule website directly jumps to the page of the personal schedule, and vice versa. Professional definitions are as follows:

Single sign-on, or SSO for short, is one of the more popular solutions for enterprise business integration. SSO is defined as “a user only needs to log in once” to “access all” trusted applications in multiple applications.

Why single sign-on

The significance of single sign-on (SSO) is that accounts and logins can be unified in different systems. Users do not need to register and log in to each system. They only need to use a unified account and log in once to access all systems.


Single sign-on (SSO) is implemented through OIDC

Create your own user directory

The term “users directory” is a good one. Your system’s total users list is like a book with “All Users” written on the cover. When you open the first page, you’ll see the contents, which are full of users’ names. If you turn to the corresponding page, you’ll see the person’s email address, cell phone number, date of birth, etc. No matter how many apps you develop, make sure you have a truth source for all the users of those apps. All registration, authentication, logout should be added to your user directory, query, delete operations. All you need to do is “create A central table for storing user information,” whether the user is from app A, app B, or app C.

What is the OIDC protocol

The OIDC family of specs and supporting specs

The full name of OIDC is OpenID Connect. It is a lightweight authentication and authorization protocol based on OAuth 2.0, and it is a superset of OAuth 2.0. It provides for other applications, such as you develop the application of A (XX mail system), application of B (XX) chat system, using C (XX) document system, how to get to your “central data table” to retrieve the user data, agreed interact, safety codes, etc., ensures that your users will be able to access all applications, only need to log in again. Instead of typing passwords over and over again, and following these guidelines, your user authentication process will be secure.

Set up your own OIDC Provider

What is OIDC Provider? Here’s an example: You’ll often see “Log in using Github” or “Log in using Google” buttons on the site’s login page. To integrate such features, you “go to Github and sign up for an OAuth App, fill out some information, and Github assigns you a pair of ids and keys.” Github acts as the OIDC Provider, and you need to transfer Github’s behavior to your own server.

A Github search for OIDC Provider yields many results:

JS:github.com/panva/node-…

Golang:github.com/dexidp/dex

Python:github.com/juanifioren…

.

Instead of enumerating, you need to select the OIDC Provider package that is appropriate for your programming language and get it running on your server. This article uses NODE-ODC-Provider in JS language.

Example code Github

The sample code for this article can be found at Github:

Github.com/Authing/imp…

Creating a folder

Let’s start by creating a folder where we can store our code:

$ mkdir demo

$ cd demo

Copy the code

Cloning of warehouse

Then we will github.com/panva/node-… Clone the warehouse to a local location

$ git clone https://github.com/panva/node-oidc-provider.git

Copy the code

Install dependencies

$ cd node-oidc-provider

$ npm install

Copy the code

Apply for a Client on the OIDC Provider

Github assigns you a pair of ids and keys. This step means you have a Client on Github. So how to apply for a pair of such IDS and keys to the OIDC Provider on our own server?

For example, the fastest way to obtain a Client is to directly write the metadata required by the OIDC Client into the configuration file of node-IDC – Provider.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986ccecbb739~tplv-t2oaga2asx-image.image

Wait, Wait, Wait, Wait, what’s the relationship between the two? First, filling out the application information on Github and submitting it sends an HTTP request to the Github server. Github servers generate a pair of ids and keys and store them, along with information about your app, in Github’s own database. Therefore, we write the metadata required by the OIDC Client directly to the configuration file, which can be interpreted as that we manually insert a data in our own database, and specify a pair of ids and keys and other OIDC Client information for ourselves.

Modifying a Configuration File

Go to the example folder under the Node-odC-provider project:

$ cd ./example

Copy the code

Edit. / support/configuration. Js, change line 16 clients configuration, we specify a for himself client_id and client_secret, including grant_types for authorization model, Authorization_code is the authorization code mode, and the redirect_URis array is the allowed service callback address. You need to fill in the Address of the Web App. The OIDC Provider sends the temporary authorization code to this address for exchanging tokens later.

module.exports = {

clients: [

{

client_id: '1'.

client_secret: '1'.

grant_types: ['refresh_token'.'authorization_code'].

redirect_uris: ['http://localhost:8080/app1.html'.'http://localhost:8080/app2.html'].

},

].

.

}

Copy the code

Start node – oidc – the provider

In the node-odc-provider /example folder, run the following command to start our OP:

$ node express.js

Copy the code

Now that we’re done, let’s take a look at the OIDC authorization code pattern before we talk about single sign-on in a Web App. Many of the terms just mentioned: “authorization code pattern”, “business callback address”, “temporary authorization code”, these concepts may be unfamiliar to you, but we’ll cover them in more detail below.

OIDC authorization code mode

The following is the interaction mode of the OIDC license mode. Your application and the OP need to use this interaction mode to obtain user information.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986d88ccdb7f~tplv-t2oaga2asx-image.image

Our OIDC Provider exposes some interfaces

Authorization interface

Each time you call this interface, it’s like saying to the OIDC Provider: I want to log in, as shown in step 1.

Then the OIDC Provider checks the login status of the current user on the OIDC Provider. If the user does not log in, the OIDC Provider displays a login dialog box to confirm the user’s identity. After successful login, a “temporary authorization code” (a random string) will be sent to your application (” business callback address “); If you are logged in, the OIDC Provider will redirect the browser directly to your application (service Callback Address) with a temporary authorization code (a random string). As shown in steps 2 and 3.

Token interface

Each time you invoke this interface, it is like saying to the OIDC Provider: Here is my authorization code, give me another Access_token. As shown in steps 4 and 5.

User information interface

Every time you call this interface, it’s like saying to the OIDC Provider: Here’s my Access_token, give me the user information. The user information is obtained.

Why so much trouble? Can’t you just return the user information?

Because of security, about the security of OIDC protocol, and can expand a lot of space, now a simple explanation: the validity of code is generally only ten minutes, and after a use of the invalid. In THE OIDC authorization code mode, only the code is transmitted through the user’s browser. Once the code is leaked, it is difficult for an attacker to use the code to change the token in the OP before the application server takes the code to change the token. However, if the access_token is transmitted through the browser, the validity period of access_token is generally about one hour. Attackers can use the Access_token to obtain user information, and it is difficult for the application server and OP to detect, let alone manually retreat. If the user information is transmitted directly, it is even less secure. In a word: Avoid letting attackers steal user information.

Write your first application

We will create an app1.html file to write our first application demo, in the demo/app directory:

$ touch app1.html

Copy the code

Write the following:


      

<html lang="en">

<head>

<meta charset="UTF-8" />

<meta name="viewport" content="Width = device - width, initial - scale = 1.0" />

<title>The first application</title>

</head>

<body>

<a href="http://localhost:3000/auth? client_id=1&redirect_uri=http://localhost:8080/app1.html&scope=openid profile&response_type=code&state=455356436">The login</a>

</body>

</html>

Copy the code

Write a second application

We will create an app2.html file to write the second application demo. Note the redirect_URI change and create it in the demo/app directory:

$ touch app2.html

Copy the code

Write the following:


      

<html lang="en">

<head>

<meta charset="UTF-8" />

<meta name="viewport" content="Width = device - width, initial - scale = 1.0" />

<title>Second application</title>

</head>

<body>

<a href="http://localhost:3000/auth? client_id=1&redirect_uri=http://localhost:8080/app2.html&scope=openid profile&response_type=code&state=455356436">The login</a>

</body>

</html>

Copy the code

Sends a login request to the OIDC Provider

Now let’s start a Web server, using http-server is recommended

$ npm install -g http-server # to install the HTTP server

$ cd demo/app

$ http-server .

Copy the code

We visited the first application: http://localhost:8080/app1.html

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986ce518be94~tplv-t2oaga2asx-image.image

Click Login to access the Authorization Interface of the OIDC Provider. Then we came to the interaction section of OIDC Provider. OIDC Provider found that the user did not log in and required the user to log in first. The Node-ODC-provider demo will give away any user name and password, but to implement single sign-on, you must use your “user directory”, or “user data in a central table”, to authenticate users. This code may involve the database adapter, custom user query logic, and so on. These are inserted in the configuration of the Node-ODC-Provider package.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986dadd45991~tplv-t2oaga2asx-image.image

Now click “Log in” and go to the confirm rights page, which shows which user rights your application needs to obtain, in this case requesting the user’s basic information.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986dd21bc29c~tplv-t2oaga2asx-image.image

Click “Continue” to finish logging in to the OP, after which the OP redirects the browser to the preset business callback address, so we’re back to app1.html.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986dd9351803~tplv-t2oaga2asx-image.image

There is a code parameter in the URL query, which is the temporary authorization code. The code ultimately corresponds to a piece of user information, so let’s see how we get the user information.

The Web App obtains user information from the OIDC Provider

In fact, code can be sent directly to the back end, which then uses code in exchange for access_token. Here I use Postman to demonstrate how to exchange an Access_token with code.

You can use the curl command to send an HTTP request:

$ curl --location --request POST 'http://localhost:3000/token' \

--header 'Content-Type: application/x-www-form-urlencoded' \

--data-urlencode 'client_id=1' \

--data-urlencode 'client_secret=1' \

--data-urlencode 'redirect_uri=http://localhost:8080/app2.html' \

--data-urlencode 'code=QL10pBYMjVSw5B3Ir3_KdmgVPCLFOMfQHOcclKd2tj1' \

--data-urlencode 'grant_type=authorization_code'

Copy the code
https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986dfe9a0e85~tplv-t2oaga2asx-image.image

After obtaining the Access_token, we can use the access_token to access the resources above the OP. The access_token is mainly used to obtain user information, that is, your application reads a user information from your user directory.

You can use curl to send an HTTP request:

$ curl --location --request POST 'http://localhost:3000/me' \

--header 'Content-Type: application/x-www-form-urlencoded' \

--data-urlencode 'access_token=I6WB2g0Rq9G307pPVTDhN5vKuyC9eWjrGjxsO2j6jm-'

Copy the code
https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e0dd0fa68~tplv-t2oaga2asx-image.image

So now that we’ve logged in to App 1, let’s see what happens when we get into App 2.

Log in to the second Web App

We opened a second application, http://localhost:8080/app2.html

Then click “Log in”.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e0edcc785~tplv-t2oaga2asx-image.image

The User has established a session with OP during App 1 login. User ←→ OP is already logged in. Therefore, OP does not ask the User to enter login credentials after checking, but directly redirects the User back to the business address and returns the authorization code.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e3faba5c1~tplv-t2oaga2asx-image.image

Similarly, App 2 uses code for access_token

Curl command:

$ curl --location --request POST 'http://localhost:3000/token' \

--header 'Content-Type: application/x-www-form-urlencoded' \

--data-urlencode 'client_id=1' \

--data-urlencode 'client_secret=1' \

--data-urlencode 'redirect_uri=http://localhost:8080/app2.html' \

--data-urlencode 'code=QL10pBYMjVSw5B3Ir3_KdmgVPCLFOMfQHOcclKd2tj1' \

--data-urlencode 'grant_type=authorization_code'

Copy the code
https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e45afaac5~tplv-t2oaga2asx-image.image

Use access_token to change user information. You can see that it is the same user.

Curl command:

$ curl --location --request POST 'http://localhost:3000/me' \

--header 'Content-Type: application/x-www-form-urlencoded' \

--data-urlencode 'access_token=I6WB2g0Rq9G307pPVTDhN5vKuyC9eWjrGjxsO2j6jm-'

Copy the code
https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e52778993~tplv-t2oaga2asx-image.image

So far, we have realized account opening and single sign-on between App 1 and App 2.

Login State Management

So far, it looks good. We have achieved the unification of accounts between the two apps, and in App 1, you need to enter a password once to log in. In App 2, you do not need to ask the user to enter a password again to log in, and you can directly return the authorization code to the business address and complete the subsequent user information acquisition.

Now let’s think about exit

Exit App 1 but not App 2

This problem is essentially “login state management problem”. We should manage “three sessions” : User ←→ App 1, User ←→ App 2, and User ←→ OP.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e52818d9c~tplv-t2oaga2asx-image.image

When OP returns code to App 1, the back end of App 1 should establish a session with the browser after obtaining user information, that is to say, App 1 and the user need to maintain their own login state. The JWT Token or cookie-session of App 1 can be signed by App 1. Same thing for App 2.

When the user logs out of App 1, App 1 only needs to clear its login status to complete the log out. However, when the user accesses App 2, he still has a session with App 2, so the user is logged in to App 2.

Exit App 1 and App 2 simultaneously

The opposite of “single sign-on” is “single sign-on”, where users can log out of all applications once and become unlogged.

The first thought is this way, we in the OIDC Provider to log out.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e6bf1aace~tplv-t2oaga2asx-image.image

And then our state looks like this:

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e750ff3cd~tplv-t2oaga2asx-image.image

Well, it doesn’t really have any effect, because the user still has a session with App 1, and the user still has a session with App 2, so the user is still logged in at App 1 and App 2.

So, is there any way to disconnect App 1 from App 2 after the user logs out of the OIDC Provider? We can solve this problem through OIDC Session management.

Simply put, the front end of App 1 needs to poll the OP, constantly asking the OP: Is the user still logged in from you? If the answer is no, App 1 actively kicks the user offline, releases the session, and lets the user log in again, and App 2 does the same.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e8cf15ea9~tplv-t2oaga2asx-image.image

When the user logs out of the OP, App 1 and App 2 poll the OP and receive the response that the user has logged out of the OP. Then, App 1 and App 2 should release their session state, kick the user out of the system and log in again.

RP IFrame Is used to send PostMessage to OP IFrame. It is used to send PostMessage to OP IFrame. It is used to send PostMessage to OP IFrame. OP iframe Queries user login status and returns it to RP iframe.

Let’s add this part of the code:

Start by opening the node – oidc – provider sessionManangement function, edit the/support/configuration. The js file, near the 42 line, make the following modifications:

.

features: {

sessionManagement: {

enabled: true.

keepHeaders: false.

},

},

.

Copy the code

Create a new rp. HTML file level with app1. HTML and app2. HTML and add the following content:

<script>

var stat = 'unchanged';

var url = new URL(window.parent.location);

// The '1' here is our client_id, previously specified in node-odC-provider

var mes = '1' + ' ' + url.searchParams.get('session_state');

console.log('mes: ')

console.log(mes)

function check_session() {

var targetOrigin = 'http://localhost:3000';

var win = window.parent.document.getElementById('op').contentWindow;

win.postMessage(mes, targetOrigin);

}



function setTimer() {

check_session();

timerID = setInterval('check_session()'.3 * 1000);

}



window.addEventListener('message', receiveMessage, false);

setTimer()

function receiveMessage(e) {

console.log(e.data);

var targetOrigin = 'http://localhost:3000';

if(e.origin ! == targetOrigin) {

return;

}

stat = e.data;

if (stat == 'changed') {

console.log('should log out now!! ');

}

}

</script>

Copy the code

Add two iframe tags to app1.html and app2.html:

<iframe src="rp.html" hidden></iframe>

<iframe src="http://localhost:3000/session/check" id="op" hidden></iframe>

Copy the code

Use Ctrl + C to close our Node-odC-Provider and HTTP-Server, and start again. Go to app1.html, open the browser console, and you will get the following information, which means that the user is currently not logged in and should do something like destroy the App’s own session

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986e93cd8fa5~tplv-t2oaga2asx-image.image

Then we click “Login” and after the OP has logged in, we call back to app1.html and the user is logged in. Note that there is an extra parameter in the address bar: session_state, which is the parameter we used to poll the OP iframe in the code above.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986eab0c73c9~tplv-t2oaga2asx-image.image

Now we try a single point out, for the node – oidc – provider of package provides oidc provider, only need the front access localhost: 3000 / session/end

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986eab014170~tplv-t2oaga2asx-image.image

Received logout success message from OP

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986eb7ae708b~tplv-t2oaga2asx-image.image

Let’s go to app1.html, and the console says the user has logged out, and now it’s time to do something like session destruction.

https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/3/27/1711986ebd0e00ef~tplv-t2oaga2asx-image.image

Do not want to maintain App 1 and user login status, App 2 and user login status

If the login states of App 1, App 2 and users are not maintained separately, the requirement of only exiting App 1 without exiting App 2 cannot be realized. All login states will completely depend on the login states between the user and the OP. In effect, the user logs in once in the OP and then accesses all applications without entering the password to realize single sign-on. The user logs out in OP, then logs out in all applications, realizing single sign-out.

Use Authing to solve single sign-on

The above is a complete single sign-on system outline, we need to maintain a directory of all users, user registration, login; We need to build an OIDC Provider and apply for an OIDC Client. We need to use code for token, token for user information; We need to constantly poll the OP’s login status in our own application.

Reading this, you may feel that the implementation of a complete set of single sign-on system is very tedious, not only to be very familiar with THE OIDC protocol, but also to set up their own OIDC Provider, and need to deal with the application, user, OP login status. Is there a login service out of the box? Authing offers an OP on the cloud, a user directory on the cloud, and an intuitive console that makes it easy to manage all users and configure the OP.

dashboard
op

Authing is very developer friendly with a rich SDK for fast integration.

sdk

If you don’t want to worry about login details, integrating Authing into your system will definitely improve development efficiency and allow you to focus more on your core business.

Welcome to experience: authing.cn

Implement single sign-on: docs. Authing. Cn/authing/qui…

reading

  1. Why should all software use single sign-on to manage users?
  2. Single sign-on in 10 minutes with Authing
  3. In case | Odoo integration Authing complete single sign-on (sso)
  4. Authing plugin is available on the official Odoo market, available via single sign-on

Add Authing enterprise wechat assistant and join the communication group

This article is formatted using MDNICE