Skip to main content

3 posts tagged with "sso"

View All Tags

· 3 min read
Jay Singh

This article follows my first article in which I explain the basics of SAML from the users' side. If you haven't read that one already I would recommend reading that one first here. In this article, we are going to take a look at what SAML authentication and setup look like from the solution providers' perspective.

If you are a B2B solutions provider and you plan to have enterprise customers they will likely ask that your product supports SAML SSO. This is because the customer will already be using an IDP to manage user access and security to their services. Anything outside this will be a risk and not fit into their user's workflows.

Most larger solution providers have already invested a lot of time and money into building SAML integrations with IDP providers but this leaves smaller competitors with less time and resources at a disadvantage as they often haven't been able to prioritize enterprise security features over the core product build.

The main reason why smaller companies don’t implement SAML as part of the standard build is that it traditionally takes a long time as they have to build a custom integration with each IDP provider their customers use. Well, this is now an old issue because we have created BoxyHQ which allows you to connect to our free product with one single integration that then connects to all the IDPs for you! Let's take a look at what the integrations with and without BoxyHQ look like first.

Without BoxyHQ

In the diagram above we can see what it looks like when you build a custom SAML integration with each IDP. As you can see for each IDP you have to connect all the instances of your product and build a unique integration. This can take months and take the focus away from your team building your core product. We believe that enterprise readiness should be accessible and easy for businesses of all sizes so we built BoxyHQ. Let's see what that looks like.

With BoxyHQ

As you can see from the image above with BoxyHQ you only have to connect your product with a straightforward integration to BoxyHQ and then we manage and connect you to all the IDPs! It is that simple and you can deploy SAML SSO for your clients in as little as 8 days. We are also open source and free so you don't need to worry about big maintenance bills, we will even offer you custom support during the integration.

If you are interested in becoming enterprise-ready without the hassle then let's chat! You can book a free consultation call and chat with our CEO about how we can help. Let's start the journey together.

· 5 min read
Jay Singh

I have always worked in tech, so have always needed to understand the technical nature of the products we are building. This process has always been over-complicated for me so I now always try to write a guide for non-technical people like me. It turns out that once you understand it you can explain it to other non-technical people much easier! So here we go as I try to explain SAML (Security Assertion Markup Language) SSO (single sign-on) and why BoxyHQ makes it so easy to implement. Firstly you have probably heard of not only SAML but OAuth 2.0 and OIDC, these are all protocols that achieve the same result of providing SSO. There are a few nuances but those are out of scope for this article to keep things simple.

Let's start with what SAML SSO is and what it does. An example of SAML SSO in action would be a user in your company signs into a single dashboard and inside that dashboard, they have all the icons for the external services they use such as their CRM (Hubspot) and accounting software (Xero). The user can now just log in to any of their services by clicking on them rather than logging into each one individually.

But how does this work? Well, the idea behind SAML SSO is that by centralizing your access to an external system you can better manage access and permission as well as improve security. So in our example, the dashboard that allowed the user to just click an icon and log in was SAML in action. Because the company has connected to its external servicing using SAML it can now let its users access all the services from a single point. This single point of access is known as the IdP (Identity Provider) which authenticates the access to all the other services via SAML.

The diagrams below show how this access flow would work with and without SAML: Without SAML SSO

In the diagram above we can see that the company is not using SAML so the user has to log into each of the services with an individual username and password. The username and password are managed by the service provider and access is also managed via an admin user on the service provider's side. The user must be given aces to each of the services from each of the services and remember the login details for each one.

With SAML SSO

In the image above we can see that the company is using an IdP such as Okta so the user simply has to log in once and then can access all the external services from a single dashboard. This also means that the company admins can manage access to the different services as they control the access directly from their IdP.

Now, remember that this is just a high-level overview of SAML and the technical aspects behind the scenes can get a lot more complicated.

We have been looking at SAML from a company user's perspective but it's also important to remember that these service providers also have to build a SAML integration to enable them to connect to their clients’ IdPs. This can be a very long and time-consuming process for service providers and this is where BoxyHQ comes in. Instead of service providers building a custom integration for each IdP their customers use which can take months, the service providers can use BoxyHQ and have all the connections to IdPs they need with a single integration! You can be SAML-ready in as little as 8 days! To understand how this looks check out my other blog here.

So what are the main benefits of SAML? Here are three of the most important ones I have identified.

Increased Security

SAML is at its heart a security standard and as it provides a single point of authentication that takes place in a secure environment it adds an extra layer of security to your service that most enterprise customers will ask for.

Improved user experience

As a user using SAML is very simple and pleasant to use as you only have to log in once and then you can access all your external services on a dashboard with a single click. This saves the user time and makes their overall experience of your product better.

Reduces cost

Without SAML you have to maintain account information across multiple services but when you use SAML this is all managed by the IdP.

BoxyHQ is open source and our SAML SSO product, SAML Jackson is just the first product we have built to help companies become enterprise-ready. If you are interested in discussing your authentication strategy or deploying SAML SSO you can book a call with our CEO here to discuss how we can support you.

I hope you have found this high-level explanation of SAML and its use cases helpful. If you have any questions please don't hesitate to reach out to us on our live chat on our website https://boxyhq.com/

· 9 min read
Kiran K

In this article, you'll learn how add SAML SSO login to an Express.js app. You'll use SAML Jackson with Auth0 to authenticate users and protect routes.

You can also access the full code at the GitHub repository.

Let’s get started!

Prerequisites

To follow along with this article, you’ll need the following:

  • Node.js installed on your computer
  • Basic knowledge about Node.js and Express.js

Setting up the database

For our article, we’ll create a free Postgres database on Heroku instead of setting up a local Postgres server.

  • Go to Heroku signup page, then create an account.
  • Go to Apps and click Create new app.
  • Give your app a name, and click the Create app button.
  • Go to the Resources tab.
  • Choose the Heroku Postgres from the Add-ons search box, and click Submit Order Form.
  • Click the Heroku Postgres and select Settings tab.
  • Click the View Credentials button and copy URI.

Now you have created a free PostgreSQL database and copied the database connection URI. We'll need the connection URI later.

Configure the Identity Provider

We'll use the Auth0 as our identity provider. An Identity Provider (IdP) is a service that manage user accounts for your app.

  • First, go to the Auth0 signup page, then create an account.
  • Go to Dashboard > Applications > Applications.
  • Click the Create Application button.
  • Give your new application a name.
  • Choose Regular Web Applications as an application type and the click Create.
  • Go to the app you created, then click the Addons tab.
  • In the SAML2 Web App box, click the slider to enable the Addon.
  • Go to the Usage tab and download the Identity Provider Metadata.
  • Go to the Settings tab and make below changes.
  • Add http://localhost:3000/sso/acs as your Application Callback URL that receives the SAML response.
  • Paste the following JSON for Settings, then click Enable button.
{
"audience": "https://saml.boxyhq.com",
"mappings": {
"id": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"firstName": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"lastName": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
}
}

audience is just an identifier to validate the SAML audience. More info.

Auth0 provides database connections to authenticate users with an email/username and password. These credentials are securely stored in the Auth0 user store.

Let's create one so that our users can register or login.

Now we've everything ready, let's move to the next step.

Getting started

Launch a terminal and clone the GitHub repo:

git clone https://github.com/devkiran/express-saml.git
cd express-saml

Now, install the dependencies:

npm install

Add the environment variables:

cp .env.example .env

Update the DATABASE_URL variable with your Heroku Postgres database connection URI.

Append ?sslmode=no-verify to your database connection URI otherwise Heroku won't allow you to link to the database. This is a Heroku specific configuration.

For example postgres://hcydrtasctfyth:fe001b264322d6cf794@ec2-1-2-3-4.compute-1.amazonaws.com:5432/demo?sslmode=no-verify

About the Express app

This is a simple express.js app created using express-generator. You can use any express.js app if you want.

Our express.js app has only 2 routes.

  • GET / render a home page
  • GET /dashboard render a dashboard

So, what's the plan? We'll add SAML SSO login (via Auth0) to our express.js app so that only authenticated users can access the /dashboard.

Install SAML Jackson

Run the following command to install the latest version of the SAML Jackson.

npm i --save @boxyhq/saml-jackson

Once you installed Jackson, let's initialize it.

Add the following code to the routes/index.js.

// routes/index.js

...

let apiController;
let oauthController;

const jacksonOptions = {
externalUrl: process.env.APP_URL,
samlAudience: process.env.SAML_AUDIENCE,
samlPath: '/sso/acs',
db: {
engine: 'sql',
type: 'postgres',
url: process.env.DATABASE_URL,
},
};

(async function init() {
const jackson = await require('@boxyhq/saml-jackson').controllers(jacksonOptions);

apiController = jackson.apiController;
oauthController = jackson.oauthController;
})();

Setting up Express.js routes

Add SAML Metadata

The first route you'll create is the GET /config one. This route will display a form with following fields:

  • Metadata: Enter the XML Metadata content you've downloaded from IdP.
  • Tenant: Jackson supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id.
  • Product: Jackson support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using.
// routes/index.js

router.get('/config', async (req, res) => {
res.render('config');
});

Add a view to display the form.

<!-- views/config.ejs -->

<!DOCTYPE html>
<html>
<head>
<title>SAML Config</title>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="/stylesheets/style.css" />
</head>
<body>
<h1>SAML Config</h1>
<p>Add SAML Metadata.</p>
<form action="/config" method="POST">
<div class="form-group">
<label for="tenant">Tenant</label>
<input
type="text"
name="tenant"
id="tenant"
class="form-control col-md-6"
required="required"
/>
</div>
<div class="form-group">
<label for="product">Product</label>
<input
type="text"
name="product"
id="product"
class="form-control col-md-6"
required="required"
/>
</div>
<div class="form-group">
<label for="rawMetadata">Metadata (Raw XML)</label>
<textarea
name="rawMetadata"
id="rawMetadata"
cols="30"
rows="10"
class="form-control col-md-6"
required="required"
></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</body>
</html>

Now let's add another route POST /config that will store the form data by calling the SAML Jackson config API.

This step is the equivalent of setting an OAuth 2.0 app and generating a client ID and client secret that will be used in the login flow.

// routes/index.js

router.post('/config', async (req, res, next) => {
const { rawMetadata, tenant, product } = req.body;

const defaultRedirectUrl = 'http://localhost:3000/sso/callback';
const redirectUrl = '["http://localhost:3000/*"]';

try {
await apiController.config({
rawMetadata,
tenant,
product,
defaultRedirectUrl,
redirectUrl,
});

res.redirect('/config');
} catch (err) {
next(err);
}
});

There are a few important things to note in the code above.

defaultRedirectUrl holds the redirect URL to use in the IdP login flow. Jackson will call this URL after completing an IdP login flow.

redirectUrl holds an array containing a list of allowed redirect URLs. Jackson will disallow any redirects that are not on this list.

Next, let's start the express app. The app starts a server and listens on port 3000 (by default) for connections.

npm start

Now, let's visit http://localhost:3000/config, you should see the page with a form.

SAML Config

Here you can add the metadata you've downloaded from Auth0. Fill out the form with a Tenant, Product, and paste the metadata XML content as it is.

I'll use 'boxyhq.com' for tenant and 'crm' for product.

The response returns a JSON with client_id and client_secret that can be stored against your tenant and product for a more secure OAuth 2.0 flow.

If you do not want to store the client_id and client_secret you can alternatively use client_id=tenant=<tenantID>&product=<productID> and any arbitrary value for client_secret when setting up the OAuth 2.0 flow.

Redirect the users to IdP

Now you have added the SAML metadata, you'll need a route to redirect the users to IdP to start the SAML authentication.

Let's add a new route GET /sso/authorize.

Don't forget to change the values of the tenant and product in the code.

// routes/index.js

router.get('/sso/authorize', async (req, res, next) => {
try {
const tenant = 'boxyhq.com';
const product = 'crm';

const body = {
response_type: 'code',
client_id: `tenant=${tenant}&product=${product}`,
redirect_uri: 'http://localhost:3000/sso/callback',
state: 'a-random-state-value',
};

const { redirect_url } = await oauthController.authorize(body);

res.redirect(redirect_url);
} catch (err) {
next(err);
}
});

oauthController.authorize() will returns a redirect_url. You should redirect the users to this redirect_url to start the IdP authentication flow.

Handle the SAML Response from IdP

This route becomes the Assertion Consumer Service (ACS) URL of your app. The ACS URL tells your IdP where to POST its SAML Response after authenticating a user.

The SAML Response contains 2 fields: SAMLResponse and RelayState.

// routes/index.js

router.post('/sso/acs', async (req, res, next) => {
try {
const { SAMLResponse, RelayState } = req.body;

const body = {
SAMLResponse,
RelayState,
};

const { redirect_url } = await oauthController.samlResponse(body);

res.redirect(redirect_url);
} catch (err) {
next(err);
}
});

Call to the method oauthController.samlResponse() will returns a redirect_url. You should redirect the users to this redirect_url. The query parameters will include the code and state parameters.

Code exchange

Now exchange the code for a token. The token is required to access the user profile.

Let's create a new route GET /sso/callback to handle the callback.

// routes/index.js

router.get('/sso/callback', async (req, res, next) => {
const { code } = req.query;

const tenant = 'boxyhq.com';
const product = 'crm';

const body = {
code,
client_id: `tenant=${tenant}&product=${product}`,
client_secret: 'client_secret',
};

try {
// Get the access token
const { access_token } = await oauthController.token(body);

// Get the user information
const profile = await oauthController.userInfo(access_token);

// Add the profile to the express session
req.session.profile = profile;

res.redirect('/dashboard');
} catch (err) {
next(err);
}
});

In the above code, replace the value for tenant and product with yours.

Protect the dashboard

Now is the time to fix our GET /dashboard route so that only authenticated users can access it.

Let's fix it by adding a condition to check if the profile exists in the session.

If profile is undefined, redirect the users back to the / otherwise display the profile on the dashboard.

Replace the GET /dashboard route with the below code.

// routes/index.js

router.get('/dashboard', function (req, res, next) {
const { profile } = req.session;

if (profile === undefined) {
return res.redirect('/');
}

// Pass the profile to the view
res.render('dashboard', {
profile,
});
});

Replace the views/dashboard.ejs view with the below code.

<!-- views/dashboard.ejs -->

<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<link rel="stylesheet" href="/stylesheets/style.css" />
</head>
<body>
<h1>Dashboard</h1>
<p>Only authenticated users should access this page.</p>

<p>Id - <%= profile.id %></p>
<p>Email - <%= profile.email %></p>
</body>
</html>

From the command line, let's restart the express app then visit the authorize the URL http://localhost:3000/sso/authorize.

If you've configured everything okay, it should redirect you to the Auth0 authentication page, then click on the Sign up link and register there

If the authentication is successful, the app will redirect you to the dashboard and display the id, email of the user.

Dashboard

Conclusion

Congratulations, you should now have a functioning SAML SSO integrated with your express.js app using the SAML Jackson and Auth0.

References

To learn more about SAML Jackson, take a look at the following resources:

Your feedback and contributions are welcome!