Skip to main content

A lightweight and extensible Single Sign-On (SSO) authentication library for Python.

Project description

more-sso-auth — Lightweight SSO for Python

A small, easy-to-use Single Sign-On (SSO) helper for Python apps and AWS Lambda.

What it gives you

  • RS256 JWT validation using a public key fetched from a URL.
  • In-memory caching for public keys (no constant network calls).
  • A header-based decorator @auth_required for quick route protection.
  • A root_auth_required decorator suitable for Lambda handlers.
  • Programmatic and environment-variable configuration.
  • An extensible permission system via BasePermission so you can write custom rules.

Quick start (3 minutes)

  1. Install
pip install more-sso-auth
pip install PyJWT
pip install cryptography
  1. Configure (either method)

Programmatic

from more_sso import init_sso_config

init_sso_config(
    public_key_uri="<your-kms-id>",
    audience="<your-app>"
)

Environment variables

export PUBLIC_KEY_URI="<your-kms-id>"
export AUDIENCE="<your-app>"
  1. Protect a function
from more_sso import auth_required

@auth_required(permission="pma.role", value="admin")
def my_func(event, *args, **kwargs):
    user = event["requestContext"]["user"]
    return {"ok": True}

The decorator will validate the bearer JWT from the Authorization header and inject the decoded payload consistently into event["requestContext"]["user"].


Core Concepts

Token validation

Use validate_token(token) to validate a JWT programmatically. It raises JWTValidationError on invalid tokens.

from more_sso import validate_token, JWTValidationError
try:
    user = validate_token(token)
except JWTValidationError as e:
    # handle unauthenticated
    print("Invalid token:", str(e))

validate_token performs usual checks: signature (RS256), audience (the AUDIENCE you configured), and token expiry.

Decorators

  • @auth_required(...) — decorator for fine-grained route enforcement. It supports either a simple permission check or a custom permission class. After validation it injects the decoded token into event["requestContext"]["user"].
  • @root_auth_required — a simple decorator for Lambda handlers that enforces authentication at the top level and injects the decoded user into event["requestContext"]["user"]. If authentication fails, the decorator returns a 401 response (for AWS Lambda-style handlers).

Example: root-level Lambda

from more_sso import root_auth_required

@root_auth_required
def lambda_handler(event, context):
    user = event["requestContext"]["user"]
    return {"statusCode": 200, "body": f"Hello {user['sub']}"}

Permissions

There are two ways to enforce authorization with auth_required:

  1. Simple claim check — pass permission and value.

    • permission is a dotted path into the decoded JWT payload (for example: pma.role will look up user['permissions']["pma"]["role"]).
    • value is the expected value.
    • the user claims will also contain the permissions as a json with app specific roles and permisson attributes
@auth_required(permission="my_app.role", value="admin")
def handler(event, *args, **kwargs):
    user = event["requestContext"].get("user", {})
    # ...
  1. Custom permission class — extend BasePermission and implement has_access().
from more_sso import BasePermission, auth_required, AccessDeniedError

class CustomPermission(BasePermission):
    def __init__(self,*args,**kwargs):
        super.__init__(*args,**kwargs)
        self.extras = kwargs

    def check_something(self )
        if self.extras['id'] == self.user['permissions']['id']
            return "something"
        ...
    # to be implemented
    def has_access(self) -> bool:

        # example: allow only admins
        if self.check_something() =='something' 
            return self.user['permissions'].get("role") == "admin"


@auth_required(permission_class=CustomPermission,**kwargs)
# kwargs are stored in self.extras of permission class which can be accessed in has_access 
def admin_only(event, *args, **kwargs):
    return {"ok": "admin access granted"}

# caller example
try:
    admin_only()
except AccessDeniedError:
    # return 403
    pass

Behavior: when permission check fails the decorator raises AccessDeniedError (or returns an appropriate 403 when used as a top-level Lambda decorator if configured that way).


AWS Lambda patterns

Top-level enforcement (recommended for simple APIs):

from more_sso import root_auth_required

@root_auth_required
def lambda_handler(event, context):
    user = event["requestContext"]["user"]
    # authorized
    return {"statusCode": 200, "body": "ok"}

Function-level enforcement (fine-grained):

from more_sso import auth_required, AccessDeniedError

@auth_required(permission="my_app.role", value="admin")
def admin_action(event, *args, **kwargs):
    return {"ok": True}

def lambda_handler(event, context):
    try:
        return admin_action(event)
    except AccessDeniedError:
        return {"statusCode": 403, "body": "Access denied"}

Note: Both auth_required and root_auth_required inject the decoded token consistently into event["requestContext"]["user"].


API reference (quick)

  • init_sso_config(public_key_uri: str, audience: str) — initialize the library programmatically.
  • validate_token(token: str) -> dict — validate token and return decoded payload. Raises JWTValidationError on failure.
  • auth_required(permission: str = None, value: Any = None, permission_class: Type[BasePermission] = None) — decorator to protect functions. Injects user into event["requestContext"]["user"].
  • root_auth_required — decorator for Lambda handlers.
  • BasePermission — extend this and implement has_access(self) -> bool for custom checks. The class has access to self.user.
  • JWTValidationError — raised for invalid JWTs.
  • AccessDeniedError — raised when permission checks fail.

Security notes

  • Always validate aud (audience) and exp (expiry). more-sso-auth checks these by default when configured.
  • Rotate keys at the Identity Provider (IdP) and ensure the IdP exposes the new public key at the configured PUBLIC_KEY_URI.

Troubleshooting & FAQ

Q: Where does the library read the token from? A: From the Authorization: Bearer <token> header in incoming requests.

Q: How do I check complex permissions (lists, nested claims)? A: Use a BasePermission subclass and implement has_access() — you have full access to the decoded payload and can evaluate arbitrarily complex logic.


Contributing & License

  • Source: https://github.com/more-retail/moresso
  • License: MIT

Contributions are welcome via PRs. Please follow the repository's contribution guidelines for tests and code style.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

more_sso_auth-1.4.0.tar.gz (9.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

more_sso_auth-1.4.0-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file more_sso_auth-1.4.0.tar.gz.

File metadata

  • Download URL: more_sso_auth-1.4.0.tar.gz
  • Upload date:
  • Size: 9.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for more_sso_auth-1.4.0.tar.gz
Algorithm Hash digest
SHA256 a7e95749c85993e91fea12935c3c19962767a9245984c2c21c5be5c6082464e6
MD5 6587ae13ff1d66cf6dfb425b03a4688c
BLAKE2b-256 c823d462950dafe78fd1ae61362f3d74a938d01dec9d26eea96df18c6572f366

See more details on using hashes here.

Provenance

The following attestation bundles were made for more_sso_auth-1.4.0.tar.gz:

Publisher: workflow.yml on more-retail/moresso

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file more_sso_auth-1.4.0-py3-none-any.whl.

File metadata

  • Download URL: more_sso_auth-1.4.0-py3-none-any.whl
  • Upload date:
  • Size: 8.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for more_sso_auth-1.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ef875640ce99fc83e4af8e7f1efa8e522bd4388e0db1a218bce2665aad3c1290
MD5 f57fa6201dda3786da6016541eb40961
BLAKE2b-256 8a01f7afa9a4cac0f35aad4e47a6da1cdf3063cdfab728a2b234c0e62f56a6f4

See more details on using hashes here.

Provenance

The following attestation bundles were made for more_sso_auth-1.4.0-py3-none-any.whl:

Publisher: workflow.yml on more-retail/moresso

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page