How to implement SAML SSO in Python (Flask, Django, or FastAPI)
SAML in Python: getting started
If you’re here, you probably need to set up SAML single sign-on. And if you’re like most software developers, you’ve never worked with SAML before.
So what is SAML?
SAML’s pretty weird and pretty tough to work with. You might find it helpful to start with one of our general explanations of SAML:
- A gentle introduction to SAML: a quick and simple introduction to SAML, written for software developers to get an intuitive feel before digging deeper
- SAML, a technical primer: a deeper, more technical treatment of all the relevant details that a software developer should know
Broadly speaking, you’ll use SAML to log users in indirectly. Instead of, say, having your users present usernames and passwords, you’ll instead rely on claims that you receive from a centralized authentication service (called an identity provider) that your customer controls.
Exactly how that works can be pretty convoluted, but here’s what it looks like in a sequence diagram:
What is SSOReady?
SSOReady makes an open source middleware that you can use to radically simplify your SAML implementation. It abstracts away all the messy XML stuff behind a simple API and takes care of some important security details for you. You just have to set up two really simple endpoints.
SAML example apps written in Python
You may just want to get SAMl into production as quickly as possible. To that end, you might want to check out these ultra-simple example apps that we put together using SSOReady:
SSOReady Python SAML SDK
You can use SSOReady’s Python SDK to call our SAML API. It’ll help keep things maximally simple.
You can get started like this:
pip install ssoready
Then pull our library into your Python app:
from ssoready.client import SSOReady
And initialize an SSOReady client like this:
client = SSOReady() # loads your API key from the env var SSOREADY_API_KEY
Note that you’ll need an API key. Our example apps (linked above) actually come with hardcoded API keys, but you’ll eventually want your own. You can get API keys at app.ssoready.com. (Don’t worry, API calls don’t cost anything – you get unlimited use of the SAML API for free.)
Implementing SAML SSO in a Flask app using SSOReady’s Python SDK
I’ll be really brief here, but you can find a more detailed tutorial on GitHub here. You can run this app locally by running the following:
git clone https://github.com/ssoready/ssoready-example-app-python-flask-saml
cd ssoready-example-app-python-flask-saml
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt
flask run
If you get confused, you’ll want to read our docs.
So what’s going on in this app? We start with a few dependencies:
from flask import Flask, redirect, request, session
from ssoready.client import SSOReady
And then we initalize our Flask app and the SSOReady client:
# please do not actually handle your secrets like this!
ssoready = SSOReady(api_key="ssoready_sk_ephref548qglzv0cmybrnihg3")
app = Flask(__name__)
app.secret_key = b'this is just a demo'
We have one endpoint that we’ll call a redirect endpoint. It looks like this:
@app.route("/saml-redirect")
def saml_redirect():
redirect_url = ssoready.saml.get_saml_redirect_url(
organization_external_id=request.args["email"].split("@")[1]
).redirect_url # this app uses domains as customer IDs
return redirect(redirect_url)
It really does only two things:
- It asks SSOReady for a redirect URL. (Every customer that wants to log in with SAML will need its own redirect URL.)
- It redirects the user to the URL it gets from SSOReady. This sends the user to their corporate identity provider (e.g., Microsoft Entra ID, Okta, etc.)
Once a user lands at their identity provider (following the redirect we were just looking at), they’ll authenticate. And then the identity provider needs to send the user back to your application.
If you’re using SSOReady to handle SAML, the identity provider actually sends the user to SSOReady first (although the user doesn’t see this), and SSOReady passes the user along to your callback endpoint with a simple saml_access_code
query parameter.
You have to write the callback endpoint, but it’s pretty simple. It looks like this:
@app.route("/ssoready-callback")
def ssoready_callback():
email = ssoready.saml.redeem_saml_access_code(
saml_access_code=request.args["saml_access_code"]
).email
session["email"] = email
return redirect("/")
It’s just doing two things:
- Sending the query parameter back to SSOReady to get a user’s details – you’re basically asking who is this user?
- Given trusted user details from SSOReady, you establish a session using your preferred tools – here, we’re using Flask’s built-in
session
object.
Once you’re successfully initiating SAML logins and setting up sessions, you’re pretty much done! Now, there are a few details to pay attention to, but this is the core of the work you’d need to do.
Implementing SAML SSO in a Django app using SSOReady’s Python SDK
Let’s see what things look like in Django. If you just want to check out our example app on GitHub, you can find it here. (It has its own README that’s honestly better than this blog post.)
You can get started in a second or two by running this:
git clone https://github.com/ssoready/ssoready-example-app-python-django-saml
cd ssoready-example-app-python-django-saml
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt
python manage.py runserver
There’s a bit more going on in the Django app than in the Flask app – as you might expect – but the important stuff is pretty much identical.
Let’s go into urls.py
. As with the Flask app, we have a SAML redirect endpoint and a callback endpoint. Here’s what it looks like:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("saml-redirect", views.saml_redirect, name="saml_redirect"),
path("ssoready-callback", views.ssoready_callback, name="ssoready_callback"),
]
And if we go into views.py
, we can see what’s going on in some more detail. We start by pulling in some standard Django stuff and the SSOReady Python SDK.
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.contrib.auth import get_user_model, login
from ssoready.client import SSOReady
And then we set up the SSOReady client with an API key:
# don't hardcode your API key like this!
ssoready = SSOReady(api_key="ssoready_sk_3hb8m7tr22zqcg0sx9f0gg3e3")
Here, we set up the SAML redirect endpoint. It’s pretty simple:
def saml_redirect(request):
redirect_url = ssoready.saml.get_saml_redirect_url(
organization_external_id=request.GET.get("email").split("@")[1]
).redirect_url # this app pretends that you use domains as company IDs
return redirect(redirect_url)
This endpoint just does two things:
- It asks SSOReady for a redirect URL for a given user. This points to the user’s company’s corporate identity provider (e.g. Entra, Okta, etc.)
- It redirects the user to the URL it gets from SSOReady.
Once the user authenticates in their corporate identity provider, they’ll need to come back to your application. SSOReady actually handles this part for you. You’ll just get a saml_access_code
in the query parameter at your callback endpoint. (If this sounds like nonsense to you, please check out the links I shared earlier in this blog post!)
Here’s what your callback endpoint looks like:
def ssoready_callback(request):
email = ssoready.saml.redeem_saml_access_code(
saml_access_code=request.GET.get("saml_access_code")
).email
user, _ = get_user_model().objects.get_or_create(email=email, defaults={'username': email})
login(request, user)
return redirect("/")
The callback endpoint’s not doing that much. It exists to receive a saml_access_code
from SSOReady (in the query parameter), then exchange the saml_access_code
for user details from SSOReady, then finally log the user in. Here, we’re using some of Django’s built-in auth tools, but you could use whatever you prefer.
Once you have these two endpoints set up, you’re pretty much done! Of course, there’s a little bit more work involved to get SAML into production, but this is conceptually everything you need to get SSOReady working!
Implementing SAML SSO in a FastAPI app using SSOReady’s Python SDK
Let’s take a look at FastAPI. We have an example app on GitHub here. If you want to get started in just a few seconds, you can run the following:
git clone https://github.com/ssoready/ssoready-example-app-python-fastapi-saml
cd ssoready-example-app-python-fastapi-saml
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt
fastapi dev main.py
Everything we need to look at lives in main.py
.
As with the Flask and Django apps, we start by importing some FastAPI modules and the SSOReady SDK. Then we initalize our app and an SSOReady client.
from typing import Annotated
from fastapi import Cookie, FastAPI, Response
from fastapi.responses import HTMLResponse, RedirectResponse
from ssoready.client import SSOReady
# please do not hardcode your API key like this!
ssoready = SSOReady(api_key="ssoready_sk_af40kyk3bi23hzquee78vswxg")
app = FastAPI()
And then we need to implement two endpoints that interface with SSOReady: a SAML redirect endpoint and a callback endpoint. Let’s start with the SAML redirect endpoint:
@app.get("/saml-redirect")
def saml_redirect(email: str):
redirect_url = ssoready.saml.get_saml_redirect_url(
organization_external_id=email.split("@")[1]
).redirect_url # this app pretends that you use domains as company IDs
return RedirectResponse(redirect_url)
This endpoint just does two things:
- It requests a redirect URL from SSOReady. This points to your customer’s identity provider.
- It redirects the user to that URL. This enables your user to authenticate using their identity provider.
(If this feels lacking in detail or confusing, please check out the links I provided at the top of this blog post!)
And then we have the callback endpoint. Once a user authenticates in their corporate identity provider, they’ll get redirected to this callback endpoint with a saml_access_code
query parameter.
@app.get("/ssoready-callback")
def ssoready_callback(saml_access_code: str):
email = ssoready.saml.redeem_saml_access_code(
saml_access_code=saml_access_code
).email
response = RedirectResponse("/")
response.set_cookie(key="email", value=email) # for demo purposes only!
return response
The callback endpoint just collects the saml_access_code
, passes it to SSOReady in exchange for a user’s login details, and then establishes a session for the user. (Note that SSOReady doesn’t handle sessions for you; you’ll use whatever tools you prefer.)
Once you have those endpoints functional, you’re all set! You have a working SAML implementation using SSOReady’s Python SDK with FastAPI.
Wrapping up
We’ve just gone over – very briefly – example apps in three common backend Python frameworks: Flask, Django, and FastAPI. All of them work pretty much exactly the same way. You’ll just import the SSOReady SDK and write two simple endpoints: one to initiate SAML logins and another to accept them.
If you need to implement SAML SSO in your Python app, this is about as easy at it gets.
Please visit https://ssoready.com/docs to learn more about how this works.