Propelauth: Authentication Built for B2B SaaS Products
PROGRAMMING LANGUAGES April 17, 2026, 11:30 p.m.

Propelauth: Authentication Built for B2B SaaS Products

When you’re building a B2B SaaS platform, authentication isn’t just about logging users in – it’s about managing multi‑tenant security, handling SSO, and scaling without turning your dev team into a security ops unit. Propelauth was born to solve exactly those pain points, offering a developer‑first API that plugs into any stack while keeping compliance and auditability front‑and‑center.

Why Propelauth Over Traditional Auth Solutions?

Traditional auth services like Firebase or Auth0 excel in consumer‑facing apps, but they often lack native support for multi‑tenant data isolation, granular role‑based access, and flexible billing models required by B2B SaaS. Propelauth fills the gap by treating each organization as a first‑class tenant, exposing a simple REST/GraphQL interface for permissions, and providing built‑in audit logs.

Another win is the “no‑code” admin UI. Non‑technical admins can invite users, assign roles, and configure SSO without touching your codebase. This reduces the support burden and speeds up onboarding for enterprise customers.

Core Concepts You Need to Know

Tenant

A tenant represents a distinct customer organization. All users, roles, and permissions are scoped to a tenant, ensuring data never leaks across company boundaries.

Roles & Permissions

Roles are collections of permissions. For example, a “Billing Admin” role might include view_invoices and manage_payment_methods. Permissions are atomic strings that your application checks at runtime.

API Keys & Service Accounts

Propelauth issues API keys for backend services and service accounts for inter‑service communication. These keys carry tenant context, so a microservice can act on behalf of a specific organization without hard‑coding tenant IDs.

Getting Started: A Quick Integration Walkthrough

Step 1: Install the SDK

pip install propelauth-sdk

Step 2: Initialize the Client

Initialize the client with your secret and the base URL of your Propelauth instance. The SDK handles token refresh and retries out of the box.

from propelauth import PropelauthClient

client = PropelauthClient(
    api_key="YOUR_PROPelauth_API_KEY",
    base_url="https://api.propelauth.com"
)

Step 3: Protect an Endpoint

Suppose you have a FastAPI endpoint that returns a list of projects for the current tenant. Use the decorator provided by the SDK to enforce authentication and automatically inject the tenant context.

from fastapi import FastAPI, Depends
from propelauth import requires_auth

app = FastAPI()

@app.get("/projects")
@requires_auth
def list_projects(user=Depends()):
    # user contains tenant_id, user_id, roles, permissions
    tenant_id = user.tenant_id
    # Fetch projects scoped to this tenant
    projects = db.get_projects_for_tenant(tenant_id)
    return {"projects": projects}

The requires_auth decorator validates the JWT from the Authorization header, checks its signature against Propelauth’s JWKS endpoint, and raises a 401 if anything is amiss.

Step 4: Role‑Based Access Control (RBAC)

To enforce granular permissions, you can inspect user.permissions directly or use a helper function.

from propelauth import requires_permission

@app.post("/invoices")
@requires_permission("create_invoice")
def create_invoice(invoice_data, user=Depends()):
    # Only users with the "create_invoice" permission can reach this point
    db.save_invoice(user.tenant_id, invoice_data)
    return {"status": "created"}

This pattern keeps your business logic clean – the decorator does the heavy lifting, and your function can assume a trusted user context.

Advanced Features for B2B SaaS

Single Sign‑On (SSO) with SAML & OIDC

Propelauth supports SAML 2.0 and OpenID Connect out of the box. After configuring your IdP, you simply enable SSO in the admin UI, and Propelauth will handle the assertion flow, mapping IdP attributes to your user model.

  • Step‑up authentication: Require MFA for privileged actions without affecting the entire session.
  • Just‑in‑time provisioning: New users are auto‑created the first time they log in via SSO, inheriting default roles you define per tenant.

Audit Logs & Compliance

Every auth event – login, token refresh, role change – is recorded in immutable audit logs. You can query these logs via a GraphQL endpoint or stream them to a SIEM.

audit_events = client.query_audit_logs(
    tenant_id="tenant_123",
    event_type="role_change",
    limit=50
)
for ev in audit_events:
    print(ev.timestamp, ev.actor_user_id, ev.details)

This feature is a lifesaver during SOC 2 or ISO 27001 audits, as you can produce a full trail of who did what and when.

Multi‑Factor Authentication (MFA)

Propelauth offers TOTP, SMS, and push‑notification MFA. You can enforce MFA globally, per tenant, or only for high‑risk actions using the requires_mfa decorator.

@requires_mfa
def delete_account(user=Depends()):
    # Critical operation – MFA already verified
    db.remove_user(user.id)
    return {"status": "deleted"}

Real‑World Use Cases

1. Multi‑Tenant Project Management Tool

Imagine a SaaS that lets companies manage internal projects. Each tenant has its own set of users, roles like “Project Manager” and “Contributor”, and can integrate with their corporate SSO. Propelauth lets you:

  • Isolate data per tenant automatically.
  • Allow admins to invite users via email or SSO.
  • Enforce “only Project Managers can archive projects” using permissions.

2. Billing & Subscription Platform

A billing service needs to expose invoices only to users with the “Billing Admin” role, and must log every access for compliance. With Propelauth you can:

  • Assign role‑based permissions at the tenant level.
  • Leverage built‑in audit logs to track who viewed or exported invoices.
  • Require MFA for any export operation to meet PCI DSS requirements.

3. API‑First SaaS Marketplace

When you expose a public API that third‑party developers call on behalf of their customers, you need service accounts. Propelauth’s API keys are scoped to a tenant, so a partner can only act on data belonging to their own customers. This eliminates the risk of cross‑tenant data leakage.

Pro Tips & Common Pitfalls

Tip 1 – Cache JWKS Locally. While the SDK handles key rotation, caching the JSON Web Key Set (JWKS) for a few minutes reduces latency on high‑traffic endpoints.
Tip 2 – Use “Just‑in‑Time” Role Assignment. Instead of pre‑creating every possible role, define a “default” role per tenant and let admins promote users as needed. This keeps onboarding friction low.
Pitfall – Hard‑Coding Tenant IDs. Avoid embedding tenant identifiers in your code or environment files. Always derive the tenant ID from the authenticated user context to prevent accidental data cross‑talk.

Testing & Debugging Strategies

Propelauth provides a sandbox environment with a mock IdP. Use it to spin up end‑to‑end tests that cover login flows, token expiration, and permission checks.

def test_project_access(client, mock_user):
    # mock_user is automatically injected with tenant_id="tenant_test"
    response = client.get("/projects", headers={"Authorization": f"Bearer {mock_user.token}"})
    assert response.status_code == 200
    assert response.json()["projects"] == []

Integrate these tests into your CI pipeline. A failing auth test early on prevents costly security regressions later.

Performance Considerations

Because Propelauth validates JWTs locally, the only network call during request processing is the optional permission lookup (if you use dynamic permissions). Cache permission sets per tenant in Redis for sub‑second lookups.

from redis import Redis
cache = Redis()

def get_permissions(tenant_id):
    cached = cache.get(f"perm:{tenant_id}")
    if cached:
        return json.loads(cached)
    perms = client.fetch_permissions(tenant_id)
    cache.setex(f"perm:{tenant_id}", 300, json.dumps(perms))
    return perms

This pattern reduces latency while still allowing you to update permissions centrally – the cache expires after a few minutes, pulling fresh data from Propelauth.

Migration Path from Legacy Auth

If you’re already using a custom auth system, you can migrate incrementally. Start by protecting new routes with Propelauth while keeping legacy routes untouched. Then, gradually refactor existing endpoints, using a dual‑auth middleware that accepts both the old token and the new Propelauth JWT.

def dual_auth_middleware(request, call_next):
    token = request.headers.get("Authorization", "").replace("Bearer ", "")
    try:
        user = client.verify_jwt(token)
    except InvalidTokenError:
        user = legacy_verify(token)  # fallback
    request.state.user = user
    return call_next(request)

Once all traffic flows through Propelauth, decommission the legacy system and enjoy the unified security model.

Best Practices for Scaling

  • Stateless Services: Rely on JWT claims for user identity; avoid session stores.
  • Tenant‑Aware Caching: Prefix cache keys with the tenant ID to prevent bleed‑through.
  • Rate‑Limit Auth Calls: Even though token verification is local, calls to fetch permissions or audit logs should be throttled.
  • Monitor Token Expiry: Implement a background job to alert when a large percentage of tokens are nearing expiration, indicating a potential key rotation issue.

Conclusion

Propelauth abstracts away the complexities of multi‑tenant authentication while giving you fine‑grained control over roles, permissions, and compliance. Its developer‑first SDK, built‑in SSO, audit logs, and service‑account model make it a natural fit for B2B SaaS products that need to scale securely. By following the integration steps, leveraging the advanced features, and adhering to the pro tips outlined above, you can ship a robust auth layer faster, reduce operational overhead, and focus on delivering core product value.

Share this article