ltijs Documentation

repository·master·Indexed 18 days ago

https://github.com/cvmcosta/ltijs

A library for turning web applications into LTI 1.3 Learning Tools. It implements a tool provider as an Express server, handling security and validation requirements automatically. Features include support for MongoDB, Firestore, and Sequelize, as well as implementations for Deep Linking, Dynamic Registration, and Grade services (submitting scores and managing line items).

Tokens
24K
Snippets
78
Records
97
Agent score
63%

What's inside ltijs

  1. Authenticate requests using the ltik token

    master

    For requests not directed at reserved endpoints, Ltijs validates them by matching a session cookie with an ltik JWT token. The ltik token must be provided in one of the following ways (in this order of priority):

    1. LTIK-AUTH-V1 Authorization header: Authorization: LTIK-AUTH-V1 Token=<ltik>, Additional=<additional>
    2. Query parameter: https://tool.com?ltik=<ltik>
    3. Request body: { "ltik": "<ltik>" }
    4. Bearer Authorization header: Authorization: Bearer <ltik>

    When using LTIK-AUTH-V1, req.headers.authorization will only contain the Additional portion, while the ltik is available in req.token.

    // Example LTIK-AUTH-V1 header
    // Authorization: LTIK-AUTH-V1 Token=eyJhbGci... , Additional=Bearer KxwRJS...
  2. Database requirements and plugins

    master

    By default, ltijs uses MongoDB to store and manage server data. You must have MongoDB installed and running.

    If you prefer other databases, you can use community-maintained database plugins that follow the same structure as the main database class:

    • Firestore Plugin: @examind-ai/ltijs-firestore
    • Sequelize Plugin: Supports MySQL and PostgreSQL via @Cvmcosta/ltijs-sequelize.
  3. Use Ltiaas (LTI as a Service) mode

    master

    By setting ltiaas: true in the options parameter, Ltijs removes the session cookie request authentication step. In this mode, all request validation is performed via the ltik token. Unlike devMode, ltiaas mode still creates and validates login state cookies.

    lti.setup('EXAMPLEKEY', 
      { url: 'mongodb://localhost/database' }, 
      {
        ltiaas: true
      }
    )
  4. Understand the Platform class

    master
    The Platform class in ltijs represents an LTI® Consumer. It is the primary abstraction used to manage and interact with the LTI platform (the system that hosts the tool, such as a Learning Management System). It provides methods to retrieve platform identifiers, manage cryptographic keys, configure authentication endpoints, and handle access tokens.
  5. Choose between LTIJS and LTIAAS

    master

    Decide between using the open-source LTIJS library or the hosted LTIAAS service based on your hosting and feature requirements.

    LTIJS

    Use LTIJS if you want to host your own private LTI server. You are responsible for:

    • Managing a Node.js environment and Linux server.
    • Maintaining a database.
    • Keeping software up to date.
    • Managing security and compliance.

    LTIAAS

    Use LTIAAS if you want a hosted service that removes the complexity of server and database management. LTIAAS provides several features not available in the LTIJS library:

    • Asynchronous Service Keys: Non-expiring tokens for tasks like periodic roster syncing or offline grade submissions.
    • Admin Interface: A portal to manage LMS registrations, view usage statistics, and debug logs.
    • Multiple Tools/Accounts: Support for multiple tools or separate development/production environments within a single account.
    • Professional Support: In-house support and consulting services.
  6. Understand Deep Linking contentItems constraints

    master

    The contentItems parameter accepts a single content item object or an array of objects following the LTI® 1.3 content item specification.

    Important: Ltijs does not guarantee all items will be sent. It only sends items that fit within the platform's accepted item types and allowed quantity. For example, if a platform only allows one content item per request, only the first item in your array will be sent.

    const items = [
      {
        type: 'ltiResourceLink',
        title: 'LTI resource',
        url: 'https://your.ltijs.com?resource=resource1',
        custom: {
          resource: 'resource1'
        }
      },
      {
        type: 'link',
        title: 'Link',
        url: 'https://link.com'
      }
    ]
    
    const message = await lti.DeepLinking.createDeepLinkingMessage(token, items, { message: 'Successfully registered resources!' })
  7. How to retrieve platforms with multiple Client IDs

    master

    Ltijs supports multiple platforms sharing the same platform URL (common in Canvas implementations) by using unique clientIds.

    • To get all platforms for a URL: Call lti.getPlatform(platformUrl). This returns an Array of Platform objects.
    • To get a specific platform: Call lti.getPlatform(platformUrl, clientId). This returns a single Platform object.

    You can use the clientId field from the IdToken object to retrieve the correct platform during an onConnect event.

    // Returns [Platform, Platform]
    const plats = await lti.getPlatform('http://plat.com')
    
    // Returns Platform
    const plat = await lti.getPlatform('http://plat.com', 'CLIENTID2')
    
    // Usage in onConnect
    lti.onConnect((token, request, response, next) => {
        const plat = await lti.getPlatform(token.iss, token.clientId)
    })
  8. How to use the Ltijs Provider singleton

    master

    The lti object (accessed via require('ltijs').Provider) is a singleton. You should call lti.setup() exactly once in your application entry point. Once setup, the same lti instance can be imported into other files to access services like lti.Grade, lti.Platform, or the underlying Express app.

    // a.js (Entry point)
    const lti = require('ltijs').Provider
    
    lti.setup('LTIKEY', { url: 'mongodb://localhost/database' }, { appRoute: '/', loginRoute: '/login' })
    
    lti.deploy()
    
    // b.js (Other file)
    const lti = require('ltijs').Provider
    // Access services like Grade
    await lti.Grade.scorePublish(token, grade)
  9. How Ltijs handles Redirection URIs and URL Parameters

    master

    Ltijs solves the inconsistency between LMS implementations (like Canvas and Moodle) regarding how redirect_uri and custom query parameters are handled during the OAuth2 flow.

    Instead of sending a redirect_uri containing query parameters—which often causes OAuth2 validation failures because the URI doesn't exactly match the registered URI—Ltijs uses the following strategy:

    1. Capture: It receives a target_link_uri that includes the desired URL parameters (e.g., https://tool.com?resource=123).
    2. Store: It strips the query parameters from the URI and stores them inside the OAuth2 state token.
    3. Clean: It sends a 'clean' redirect_uri (e.g., https://tool.com) to the Platform to ensure strict OAuth2 compliance and successful matching.
    4. Restore: Once the launch flow is complete and the user is redirected back, Ltijs retrieves the parameters from the state token and reapplies them to the final URL.

    This allows developers to use a single resource selection strategy (using URL parameters) that works across all LMSs, regardless of whether they support custom parameters in the redirection URI or not.

    // Example Flow:
    
    // 1. Received target_link_uri:
    https://tool.com?resource=123
    
    // 2. Internal state storage (simplified):
    {
      state: "12uy3g8asd7123vasdjhv123876asd",
      query: { resource: "123" }
    }
    
    // 3. The redirect_uri sent to the LMS (to ensure OAuth2 compliance):
    https://tool.com
    
    // 4. Final URL after launch is complete:
    https://tool.com?resource=123
  10. LTI Advantage Services available in Ltijs

    master

    Ltijs provides implementations for several LTI Advantage services. Note that detailed class documentation for these services is hosted externally at the official documentation site.

    Supported services include:

    • Deep Linking Service: For facilitating the selection of content during tool launch.
    • Assignment and Grades Service: For managing assignments and grade transfers.
    • Names and Roles Provisioning Service: For managing user identities and roles within a context.
    • Dynamic Registration Service: For allowing tools to register themselves with a platform automatically.
  11. Configure LTI behavior using callbacks

    master

    Available Callbacks

    • onConnect(token, req, res, next): Triggered on a successful launch request at the appRoute. The token is the validated idtoken.
    • onDeepLinking(token, req, res, next): Triggered on a successful deep linking request. Use this to display your provider's deep linking UI.
    • onInvalidToken(req, res, next): Triggered when an idtoken fails validation. Access error details via res.locals.err.
    • onSessionTimeout(req, res, next): Triggered when no valid session is found. Access error details via res.locals.err.
    • onUnregisteredPlatform(req, res): Triggered when a launch attempt comes from an unregistered platform.
    • onInactivePlatform(req, res): Triggered when a platform was registered via Dynamic Registration but is currently inactive.
    // Example: Handling a successful connection
    lti.onConnect(async (token, req, res, next) => {
        console.log(token)
        return res.send('User connected!')
    })
    
    // Example: Handling an invalid token
    lti.onInvalidToken(async (req, res, next) => { 
        return res.status(401).send(res.locals.err)
    })