Unveiling the SAML SSO Magic with AWS IAM Identity Center
Tags: iam, aws, web
Published: 2023-12-14 12:51:32

---
title: Unveiling the SAML SSO Magic with AWS IAM Identity Center
published: true
date: 2023-12-10 16:30:00 UTC
tags: IAM, AWS, Web
canonical_url: https://imandrea.me/blog/saml-under-the-hood/
---

If you've ever wondered about how the magic of **SAML** works behind the scenes, you might be in the right place. In this blog post, we'll analyze **requests** and **responses** of the **SAML federation** that we set up in the [previous episode of this series](/blog/saml-iam-ic). 

_**Note:** this post is part of a **series** dedicated to AWS IAM Identity Center (a.k.a. **IAM IC**) and related integrations. Check out all the "episodes" following the tag [**#aws-auth-series**](https://www.imandrea.me/tags/aws-auth-series/)._

## 0 - The trust

First things first: we need to establish **trust** between **IAM Identity Center** and our **app**. Let's start by configuring the IAM Identity Center as described in the [previous blog post](/blog/saml-iam-ic). After that, clone [this repo](https://github.com/floatingpurr/sso-iam-ic), and follow the [instructions](/blog/saml-iam-ic/#setting-up-our-application-sp) to get it up and running.

Next, you can download a **browser extension** for isolating the **SAML traffic**, such as:

- [SAML-tracer](https://chromewebstore.google.com/detail/saml-tracer/mpdajninpobndbfcldcmbpnnbhibjmch)
  (Chrome)
- [SAML-tracer](https://addons.mozilla.org/it/firefox/addon/saml-tracer/)
  (Firefox)

While this extension is not a strict requirement, using a SAML-oriented extension can help filter SAML traffic and gather relevant information. It's much more convenient than inspecting all the network traffic with the browser. Just remember to open the extension before you start the SAML authentication process.

Ok, cool: we are ready to start!

## 1. The user tries to access the app

The SP-initiated process begins with a user who wants to access to our Node app, namely the Service Provider. The user requests a protected app URL with her browser, such as http://localhost:3000. Our app receives this request, and sends back a **redirection** to the local login page. The user's browser follows the redirection information, and it tries to get the URL http://localhost:3000/login.

## 2. The user is redirected to AWS

When the user's browser requests the `/login` path, a **fundamental redirection** happens. Let's look inside it with `curl`:

```bash
$ curl -I http://localhost:3000/login
HTTP/1.1 302 Found X-Powered-By:
Express Location:
https://<IAM_IDENTITY_CENTER_ENTRYPOINT_URL>?SAMLRequest=<SAMLRequest>
...
```

Our app has just generated a **SAML authentication request**, and it is nothing but a **redirection to the AWS URL** we set for our Service Provider with a **URL-encoded SAML Request**, that is, in turn, encoded into `XML`. You can inspect the XML request with the SAML-tracer. Alternatively, you can decode it manually with tools like [this](https://toolbox.googleapps.com/apps/encode_decode/).

Here's what a `SAMLRequest` looks like:

```xml
<samlp:AuthnRequest
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  ID="_eb921ccc0cfdd887bf248173a9440ca09cd13840"
  Version="2.0"
  IssueInstant="2023-12-10T11:03:55.909Z"
  ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
  Destination="https://portal.sso.eu-central-1.amazonaws.com/saml/assertion/foo"
  AssertionConsumerServiceURL="http://localhost:3000/login/callback">

  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
    http://localhost:3000/myDemoSAMLAudience
  </saml:Issuer>

  <samlp:NameIDPolicy
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  AllowCreate="true"
  Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>

  <samlp:RequestedAuthnContext
  xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
  Comparison="exact">
    <saml:AuthnContextClassRef
      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
      urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
    </saml:AuthnContextClassRef>
  </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>
```

Let's go over the elements of that request:

- **`ID`**: unique identifier for the request generated by our Node app
- **`Version`**: SAML version used (2.0 in this case)
- **`IssueInstant`**: the timestamp of this request
- **`Destination`**: specifies the endpoint where the request should be sent
  - **`IAM Identity Center sign-in URL`** on the AWS side
- **`AssertionConsumerServiceURL`**: is the callback URL of the SP intended to handle the SAML response from the IAM IC
  - **Application ACS URL** on the AWS side
- `<saml:Issuer>`: is the predefined string that we set in the trust process
  - **Application SAML audience** on the AWS side

From the user's perspective, she is just redirected to the log in page of the IAM Identity Center

![IAM IC login page](https://www.imandrea.me/assets/images/saml-iam-ic/iam-ic-login.png)

## 3. The IdP Response

If the user logs in correctly to IAM IC with her username and password, the IdP generates a **SAML response** with information about the user and the authentication process. The XML of the SAML response is more complex than the requests. Moreover, part of the information needs to be **signed**. It couldn't be easy to grasp relevant parts at the first sight. The response, among many other things, contains:

- **`_id`**: unique identifier for the response generated by IAM Identity Center
- **`InResponseTo`**: a reference to the request `ID`
- **`Assertion`**: an element containing data about the user
  - **`Subject`**: a reference to the user that can be used by our App to
    identify the user who wants to log in (in our case the user email, see the
    [attribute mappings](/blog/saml-iam-ic/#mapping-attributes) in IAM IC)
  - **`AttributeStatement`**: a wrapper element containing the other user
    attributes defined in the
    [attribute mappings](/blog/saml-iam-ic/#mapping-attributes) in IAM IC
  - **`Conditions`**: the validity period of this SAML response

For the sake of convenience, we can inspect a quick summary under the **Summary tab** of the SAML-tracer. Still curious? We can explore the full XML under the **SAML tab**. I recommend again ["A Developer's Guide to SAML"](https://youtu.be/l-6QSEqDJPo?feature=shared&t=764) as a reference for an in-depth analysis.

This response is **routed back to the callback URL** of our app. In this case, there is not a redirection at the HTTP level, but IAM IC uses a mechanism similar to an HTML form submission, with some custom JavaScript kicking in. The final result is an HTTP POST request to `http://localhost:3000/login/callback`, with the SAML response in the body.

## 4. Logged in

Finally, the SP receives and **validates** the SAML response. If everything looks fine to our toy app, the user is logged in, and a dedicated session is established. In the last part of our example, the user is redirected once again to the requested protected content:

```bash
$ curl -v 'http://localhost:3000/login/callback' \
-H 'Content-Type: application/x-www-form-urlencoded' \
... \
--data-raw 'SAMLResponse=<SAMLResponse>

< HTTP/1.1 302 Found
< X-Powered-By: Express
< Location: /
...
```

## Wrapping up

In this example, we have explored what happens under the hood when we use IAM Identity Center as the Identity Provider for our custom app.

Note that, usually, **the entire process takes place within the user's browser**. The **communication** between the IdP and the SP is kind of like **indirect** and involves the user's browser as an intermediary, routing information back and forth. This means that our SP can be hosted in a **private network**, without being directly reachable by the Identity Provider over the Internet.

The following picture (credit: [IBM](https://www.ibm.com/docs/en/was-liberty/core?topic=authentication-saml-20-web-browser-single-sign#cwlp_saml_web_sso__title__3)) summarizes well the SAML dance steps we have just executed.

![SAML Web Browser SSO Scenarios by IBM](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4qp4lrdlmixyrst7a2zu.png)

There are many other flavors of SAML out there. I hope that this example can help you understand the actors involved and their responsibilities.

Cheers!

^..^