from flask import Flask, request, redirect
from grantex import (
Grantex,
CreateSsoConnectionParams,
SsoEnforcementParams,
SsoLoginParams,
SsoOidcCallbackParams,
SsoSamlCallbackParams,
)
import os
app = Flask(__name__)
client = Grantex(api_key=os.environ["GRANTEX_API_KEY"])
# Step 1: Create SSO connections (one-time setup)
client.sso.create_connection(CreateSsoConnectionParams(
name="Okta Production",
protocol="oidc",
issuer_url="https://mycompany.okta.com",
client_id=os.environ["OKTA_CLIENT_ID"],
client_secret=os.environ["OKTA_CLIENT_SECRET"],
domains=["mycompany.com"],
jit_provisioning=True,
default_role="member",
))
client.sso.create_connection(CreateSsoConnectionParams(
name="Azure AD SAML",
protocol="saml",
metadata_url=os.environ["AZURE_METADATA_URL"],
assertion_consumer_service_url="https://yourapp.com/sso/saml/callback",
entity_id="https://yourapp.com/saml/metadata",
domains=["contoso.com"],
jit_provisioning=True,
))
# Step 2: Enforce SSO for the organization
client.sso.set_enforcement(SsoEnforcementParams(
enforced=True,
exempt_roles=["owner"],
))
# Step 3: Redirect user to SSO login based on email domain
@app.route("/sso/login")
def sso_login():
domain = request.args["domain"]
login = client.sso.get_login_url(SsoLoginParams(
domain=domain,
redirect_uri="https://yourapp.com/sso/callback",
))
return redirect(login.authorize_url)
# Step 4a: Handle OIDC callback
@app.route("/sso/callback")
def sso_callback():
result = client.sso.handle_oidc_callback(SsoOidcCallbackParams(
code=request.args["code"],
state=request.args["state"],
))
print(f"Welcome, {result.name} ({result.email})")
if result.provisioned:
print("New user provisioned via JIT")
return redirect("/dashboard")
# Step 4b: Handle SAML callback
@app.route("/sso/saml/callback", methods=["POST"])
def sso_saml_callback():
result = client.sso.handle_saml_callback(SsoSamlCallbackParams(
saml_response=request.form["SAMLResponse"],
relay_state=request.form.get("RelayState"),
))
print(f"Welcome, {result.name} ({result.email})")
return redirect("/dashboard")
# Admin: List active sessions
@app.route("/admin/sso/sessions")
def sso_sessions():
sessions = client.sso.list_sessions()
return {"sessions": [s.__dict__ for s in sessions.sessions]}