SSO Capabilities

Canvas supports SAML 2.0 single sign-on, and exposes hooks that let plugins participate in the post-login flow. Use these hooks to capture data from the identity provider’s SAML response, or to send a user to a custom landing page after they authenticate.

Both hooks fire after the SAML assertion has been validated and the user has been logged in. The user’s identity is available as self.event.actor; the SAML response data is available in self.event.context.

Hooks at a glance #

HookTypePurpose
SSO__PROCESS_ADDITIONAL_REQUEST_DATAEventRead-only access to the SAML response so a plugin can capture IdP attributes (group memberships, employee ID, etc.).
SSO__GET_POST_LOGIN_REDIRECTEventOverride the URL the user lands on after SSO login.
REDIRECT_CONTEXTEffectThe effect returned from SSO__GET_POST_LOGIN_REDIRECT to set the post-login destination.

SSO__PROCESS_ADDITIONAL_REQUEST_DATA #

Fires once per successful SAML login, immediately after the user is authenticated. The event is read-only: any effects a handler returns are discarded. Use it for side-effects such as syncing IdP attributes onto a Staff record, writing an audit log, or notifying an external system that a user signed in.

Context #

KeyTypeDescription
session_infodictThe validated SAML response data from pysaml2. Common keys include name_id (the SAML NameID), issuer (IdP entity ID), ava (a dict of IdP-supplied user attributes keyed by attribute name with list-valued entries), session_index, not_on_or_after, and authn_info.

Target #

The Canvas user that just logged in. self.event.target resolves to a Staff or Patient via self.event.actor.instance.person_subclass.

Example #

import json

from canvas_sdk.events import EventType
from canvas_sdk.handlers.base import BaseHandler
from logger import log


class CaptureSSOAttributes(BaseHandler):
    """Log the IdP-supplied group memberships for every SSO login."""

    RESPONDS_TO = EventType.Name(EventType.SSO__PROCESS_ADDITIONAL_REQUEST_DATA)

    def compute(self):
        session_info = json.loads(self.event.context)["session_info"]
        groups = session_info.get("ava", {}).get("groups", [])
        log.info(f"SSO login for {session_info['name_id']} with groups={groups}")
        return []

SSO__GET_POST_LOGIN_REDIRECT #

Fires once per successful SAML login, right before Canvas decides where to send the user. A plugin that returns a REDIRECT_CONTEXT effect sets the destination URL; if no plugin returns one (or the value is falsy), Canvas falls back to its default post-login redirect.

Only the first REDIRECT_CONTEXT effect returned is used. If multiple plugins register a handler, ordering between them is not guaranteed — coordinate across plugins to avoid conflicting redirects.

Context #

KeyTypeDescription
relay_statestrThe SAML RelayState value from the original login request, if any. Often used by IdPs to encode a “deep link” — the URL the user was trying to reach before they were bounced to the IdP.
session_infodictSame shape as for SSO__PROCESS_ADDITIONAL_REQUEST_DATA.

Target #

Same as SSO__PROCESS_ADDITIONAL_REQUEST_DATA — the Canvas user that just logged in.

Example #

import json

from canvas_generated.messages.effects_pb2 import EffectType
from canvas_sdk.effects import Effect
from canvas_sdk.events import EventType
from canvas_sdk.handlers.base import BaseHandler


class RouteSSOByGroup(BaseHandler):
    """Send admins to the admin app and everyone else to the schedule."""

    RESPONDS_TO = EventType.Name(EventType.SSO__GET_POST_LOGIN_REDIRECT)

    def compute(self):
        session_info = json.loads(self.event.context)["session_info"]
        groups = session_info.get("ava", {}).get("groups", [])

        if "canvas-admins" in groups:
            url = "/admin/"
        else:
            url = "/schedule/"

        return [
            Effect(
                type=EffectType.REDIRECT_CONTEXT,
                payload=json.dumps({"url": url}),
            )
        ]

REDIRECT_CONTEXT #

The effect that carries the post-login URL back to Canvas. It is only meaningful when returned from a SSO__GET_POST_LOGIN_REDIRECT handler.

Payload #

KeyTypeDescription
urlstrThe URL Canvas should redirect the user to after SSO login. Relative paths (e.g. /schedule/) and absolute URLs are both accepted.

There is no SDK helper class for this effect — construct it directly with Effect(type=EffectType.REDIRECT_CONTEXT, payload=json.dumps({"url": ...})) as shown in the example above.