WamISSO Documentation

Python Integration

Integrate WamISSO into a Python app using Flask and the requests library.

Before you start: Complete developer registration and create an OAuth client in the developer portal to get your client_id and client_secret.

Install dependencies

pip install flask requests python-dotenv

Environment variables (.env)

SSO_BASE_URL=https://wamisso.rendovations.com
SSO_CLIENT_ID=your-client-id
SSO_CLIENT_SECRET=your-client-secret
SSO_REDIRECT_URI=http://localhost:5000/callback

Complete Flask example

import os
import secrets
from urllib.parse import urlencode

import requests
from dotenv import load_dotenv
from flask import Flask, redirect, request, session, jsonify

load_dotenv()

app = Flask(__name__)
app.secret_key = os.environ["FLASK_SECRET_KEY"]

SSO_BASE_URL = os.environ["SSO_BASE_URL"]
CLIENT_ID = os.environ["SSO_CLIENT_ID"]
CLIENT_SECRET = os.environ["SSO_CLIENT_SECRET"]
REDIRECT_URI = os.environ["SSO_REDIRECT_URI"]


@app.get("/login")
def login():
    state = secrets.token_urlsafe(32)
    session["oauth_state"] = state

    params = urlencode({
        "client_id": CLIENT_ID,
        "redirect_uri": REDIRECT_URI,
        "response_type": "code",
        "scope": "openid profile email",
        "state": state,
    })

    return redirect(f"{SSO_BASE_URL}/oauth/authorize?{params}")


@app.get("/callback")
def callback():
    if request.args.get("state") != session.get("oauth_state"):
        return "Invalid state", 403

    code = request.args.get("code")
    if not code:
        return "Missing code", 400

    token_response = requests.post(
        f"{SSO_BASE_URL}/oauth/token",
        data={
            "grant_type": "authorization_code",
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "redirect_uri": REDIRECT_URI,
            "code": code,
        },
        headers={"Accept": "application/json"},
        timeout=15,
    )
    token_response.raise_for_status()
    tokens = token_response.json()

    user_response = requests.get(
        f"{SSO_BASE_URL}/api/user",
        headers={
            "Accept": "application/json",
            "Authorization": f"Bearer {tokens['access_token']}",
        },
        timeout=15,
    )
    user_response.raise_for_status()
    user = user_response.json()

    session["user"] = user
    session["access_token"] = tokens["access_token"]
    return jsonify(user)


@app.get("/me")
def me():
    return jsonify(session.get("user", {}))


if __name__ == "__main__":
    app.run(port=5000, debug=True)

Refresh token

def refresh_access_token(refresh_token: str) -> dict:
    response = requests.post(
        f"{SSO_BASE_URL}/oauth/token",
        data={
            "grant_type": "refresh_token",
            "refresh_token": refresh_token,
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
        },
        headers={"Accept": "application/json"},
        timeout=15,
    )
    response.raise_for_status()
    return response.json()

Run locally

# Register http://localhost:5000/callback as a redirect URI first
python app.py

# Open http://localhost:5000/login

Logout

@app.post("/logout")
def logout():
    access_token = session.get("access_token")

    if access_token:
        try:
            requests.post(
                f"{SSO_BASE_URL}/api/sso/logout",
                headers={
                    "Accept": "application/json",
                    "Authorization": f"Bearer {access_token}",
                },
                timeout=15,
            )
        except requests.RequestException:
            pass  # still clear local session

    session.clear()
    return redirect("/")