xAPI LRS Auth Proxy - Reference Implementation for cmi5 Session-Based Security

Henry Ryng

Administrator
Staff member

Background: cmi5 Security Model Evolution​

In the IEEE LTSC cmi5 working group, we're currently defining the minimum security rights an Assignable Unit (AU, also known as a Learning Record Provider/LRP) has for reading and writing to the LRS. While the default isolation model (actor + activity + registration scoped) covers most use cases well, we've identified several important scenarios that require expanded permissions.

These use cases—including competency assertion, team training, analytics dashboards, and adaptive learning—are documented and discussed here:
https://opensource.ieee.org/ltsc/cmi5-staging/-/issues/34

The Real-World Challenge​

In my consulting work, I frequently need to stand up learning systems using various LRS backends (YetAnalytics, Veracity, SCORM Cloud, etc.). A recurring challenge is that most LRS implementations use static API keys that:
  • Never expire (security risk)
  • Allow any actor to be impersonated (privacy violation)
  • Cannot be scoped to specific sessions
  • Don't support the permission model we're defining in cmi5

The Solution: OAuth JWT Proxy​

To validate these concepts and provide a working reference implementation, I've created an xAPI LRS Auth Proxy that implements session-based JWT authentication for cmi5/xAPI systems.

How It Works​

  1. LMS requests token - When launching content, the LMS calls the proxy's token API with the learner's actor, registration (session ID), and requested permissions
  2. Proxy issues JWT - A short-lived (default 1 hour for testing but configurable and API settable), cryptographically signed token scoped to specific actor/activity/registration
  3. Content uses token - The AU receives this via standard cmi5 fetch, completely transparent to existing content
  4. Proxy validates & forwards - Each xAPI request is validated against the token's permissions before forwarding to the LRS

Key Features​

  • ✅ Non-breaking - Works with existing cmi5 content (AU fetch flow unchanged)
  • ✅ LRS-agnostic - Sits in front of any xAPI-compliant LRS backend
  • ✅ Permission enforcement - Implements the full permission model from the cmi5 use cases
  • ✅ Multi-tenant ready - Supports SaaS deployments with host header routing
  • ✅ Production ready - Written in Go, includes Docker deployment, PostgreSQL backend
  • ✅ Open source - MIT license, comprehensive documentation

Use Cases Enabled​

The proxy supports all the permission scopes we've identified:
  • Default isolation (actor-activity-registration-scoped)
  • Course-wide analytics (actor-course-registration-scoped)
  • Team training (group-activity-registration-scoped)
  • Adaptive learning (actor-activity-all-registrations)
  • Certification tracking (actor-cross-course)
  • And more...

GitHub Repository​

The complete reference implementation is available here:
https://github.com/tla-ecosystem/xapi-lrs-auth-proxy

Includes:
  • Full Go source code (~1,750 lines)
  • Comprehensive architecture documentation
  • Testing guide with examples
  • Docker deployment ready
  • PostgreSQL schema for multi-tenant deployments

Seeking Community Feedback​

I'm sharing this with the TLA community for several reasons:
  1. Standards alignment - Does this approach align with the direction of TLA and cmi5?
  2. Real-world validation - Can others test this with their LRS/LMS combinations?
  3. Use case coverage - Are there permission scenarios we're missing?
  4. Implementation feedback - How can we make this more useful for the community?
This is intended as a reference implementation that LRS vendors, LMS developers, and training platform operators can adopt, fork, or learn from. I'm particularly interested in feedback from:
  • LRS vendors on integration approaches
  • LMS developers on token issuance workflows
  • Content developers on any friction points
  • Security professionals on the authentication model
Questions, suggestions, and critiques welcome! This is still evolving and community input will make it better.
 
Back
Top