Coder Social home page Coder Social logo

ltijs's Introduction



IMS Global Certified

Easily turn your web application into a LTI® 1.3 Learning Tool.

codecov Node Version NPM package NPM downloads JavaScript Style Guide APACHE2 License Donate

Please ⭐️ us on GitHub, it always helps!

Ltijs is LTI® Advantage Complete Certified by IMS

Ltijs is the first LTI Library to implement the new LTI® Advantage Dynamic Registration Service, now supported by Moodle 3.10. The Dynamic Registration Service turns the LTI Tool registration flow into a fast, completely automatic process.


LTI As A Service



A ready-to-go SaaS LTI solution.

If you need an enterprise-ready LTI deployment, LTIaaS can get you up and running in a matter of minutes. We offer a SaaS solution with a powerful, easy to use, API that gives you access to the entire functionality of the LTI protocol. And you only start paying once your product starts to grow.

Through our consultation services we can help you design, build and maintain your LTI tool. The LTIaaS API is already being used to reach thousands of students across the entire world!

For more information visit LTIaaS.com


Table of Contents


Introduction

The Learning Tools Interoperability (LTI®) protocol is a standard for integration of rich learning applications within educational environments. ref

This library implements a tool provider as an Express server, with preconfigured routes and methods that manage the LTI® 1.3 protocol for you. Making it fast and simple to create a working learning tool with access to every LTI® service, without having to worry about manually implementing any of the security and validation required to do so.


Feature roadmap

Feature Implementation Documentation
Keyset endpoint support ✔️ ✔️
Deep Linking Service Class ✔️ ✔️
Grading Service Class ✔️ ✔️
Names and Roles Service Class ✔️ ✔️
Dynamic Registration Service ✔️ ✔️
Database plugins ✔️ ✔️
Revised usability tutorials
Key Rotation
Redis caching

Installation

Installing the package

$ npm install ltijs

MongoDB

This package natively uses mongoDB by default to store and manage the server data, so you need to have it installed, see link bellow for further instructions.

Database Plugins

Ltijs can also be used with other databases through database plugins that use the same structure as the main database class.


Quick start

Setting up Ltijs

const path = require('path')

// Require Provider 
const lti = require('ltijs').Provider

// Setup provider
lti.setup('LTIKEY', // Key used to sign cookies and tokens
  { // Database configuration
    url: 'mongodb://localhost/database',
    connection: { user: 'user', pass: 'password' }
  },
  { // Options
    appRoute: '/', loginRoute: '/login', // Optionally, specify some of the reserved routes
    cookies: {
      secure: false, // Set secure to true if the testing platform is in a different domain and https is being used
      sameSite: '' // Set sameSite to 'None' if the testing platform is in a different domain and https is being used
    },
    devMode: true // Set DevMode to false if running in a production environment with https
  }
)

// Set lti launch callback
lti.onConnect((token, req, res) => {
  console.log(token)
  return res.send('It\'s alive!')
})

const setup = async () => {
  // Deploy server and open connection to the database
  await lti.deploy({ port: 3000 }) // Specifying port. Defaults to 3000

  // Register platform
  await lti.registerPlatform({
    url: 'https://platform.url',
    name: 'Platform Name',
    clientId: 'TOOLCLIENTID',
    authenticationEndpoint: 'https://platform.url/auth',
    accesstokenEndpoint: 'https://platform.url/token',
    authConfig: { method: 'JWK_SET', key: 'https://platform.url/keyset' }
  })
}

setup()

Implementation example


Documentation

See bellow for the complete documentation:

Service documentations:

Additional documentation:


Contributing

Please ⭐️ us on GitHub, it always helps!

If you find a bug or think that something is hard to understand feel free to open an issue or contact me on twitter @cvmcosta, pull requests are also welcome :)

And if you feel like it, you can donate any amount through paypal, it helps a lot.

Buy Me A Coffee


Special thanks

I would like to thank the Federal University of Maranhão and UNA-SUS/UFMA for the support throughout the entire development process.


I would like to thank CourseKey for making the Certification process possible and allowing me to be an IMS Member through them, which will contribute immensely to the future of the project.


I would like to thank Examind for the amazing work on the Firestore database plugin. As well as the continuous help and support in the development of this project.


License

APACHE2 License

Learning Tools Interoperability® (LTI®) is a trademark of the IMS Global Learning Consortium, Inc. (https://www.imsglobal.org)

ltijs's People

Contributors

cvmcosta avatar danny-does-stuff avatar dependabot[bot] avatar fadeenk avatar g-guirado avatar joecrop avatar johnnyoshika avatar larstheglidingsquirrel avatar lselden avatar pfgray avatar svarlamov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ltijs's Issues

[Enhancement][Security] Add key rotation

Now that the keyset endpoint is done. It would be good to add key rotation support to improve security.

  • Add as job.
  • Add as function.
  • Optional functionality, enabled manually for each platform registered.

Typescript support

Hi :)

First of all: thanks for your great work!

would you be interested in including typings in this library, for it to be usable in typescript? I'm currently using it in a typescript project in university, so I'd be able to provide the typings I made. They might be incomplete however and I'd appreciate if you'd have a look at it, given your understanding of the library goes much deeper!

Cheers

SameSite cookies

Hello!

The latest version of ltijs returns a cookie without SameSite=None when calling /login. This breaks my stuff horribly with the latest version of Chrome, so I've had to revert to an older version of ltijs.

I can see a new "externalRequest" flag in the Provider.redirect() method, but I'm not sure I understand its purpose.

Can you give us a little more info about what you were trying to achieve?

Thanks,
Eric

How can I always renew the time session

Describe the bug
I get the message "Token invalid or expired. Please reinitiate login." but it is because the session expired
Expected behavior
Always show the plugin

Provider logs
Copy of the relevant provider logs.

2020-06-26 20:53:32 default[test] 2020-06-26T20:53:32.290Z provider:main Passing request to session timeout handler 2020-06-26 20:53:32 default[test] 2020-06-26T20:53:32.379Z provider:main Receiving request at path: /sessionTimeout

Ltijs version

  • Version 4.1.0

NodeJS version

  • Version 12

Platform used

  • moodle

[ENHANCEMENT][DATABASE] Organize Database code

The database code should no longer be treated as a singleton. I should come up with a way to implement the database in a way that doesn't break current implementations but allows for easier manipulation of the database in future additions without having to pass the database object as a parameter.

Path does not match reserved endpoints: when I deploy on App Engine

I am deploying the ltijs server in the app engine I get the message "Invalid token. Please reinitiate login." and the next log

2020-06-26 15:26:03 default[20200626t151009]  "POST /login" 302
2020-06-26 15:30:45 default[20200626t151009]  2020-06-26T15:30:45.291Z provider:main Receiving request at path: /login
2020-06-26 15:30:45 default[20200626t151009]  2020-06-26T15:30:45.291Z provider:main Receiving a login request from: https://moodle-test.lmslti.booklick.net
2020-06-26 15:30:45 default[20200626t151009]  2020-06-26T15:30:45.330Z provider:main Redirecting to platform authentication endpoint
2020-06-26 15:30:46 default[20200626t151009]  2020-06-26T15:30:46.099Z provider:main Receiving request at path: /
2020-06-26 15:30:46 default[20200626t151009]  2020-06-26T15:30:46.099Z provider:main Path does not match reserved endpoints
2020-06-26 15:30:46 default[20200626t151009]  2020-06-26T15:30:46.099Z provider:main Cookies received:
2020-06-26 15:30:46 default[20200626t151009]  2020-06-26T15:30:46.099Z provider:main [Object: null prototype] {}
2020-06-26 15:30:46 default[20200626t151009]  2020-06-26T15:30:46.100Z provider:main No LTIK found
2020-06-26 15:30:46 default[20200626t151009]  2020-06-26T15:30:46.100Z provider:main Request body:  [Object: null prototype] {
2020-06-26 15:30:46 default[20200626t151009]    error: 'invalid_request',
2020-06-26 15:30:46 default[20200626t151009]    error_description:

Grade ScorePublish code 400 bad request with Canvas

I'm having issues posting a grade in Canvas. I'm trying to run the following inside lti.onConnect() callback:

let grade = {
  scoreGiven: 10,
  activityProgress: 'Completed',
  gradingProgress: 'FullyGraded'
}

await lti.Grade.ScorePublish(res.locals.token, grade);

The following is the debug output:

provider:gradeService Target platform: https://canvas.test.instructure.com +0ms
provider:gradeService Attempting to retrieve platform access_token for [https://canvas.test.instructure.com] +3ms
provider:platform Access_token for https://canvas.test.instructure.com not found +0ms
provider:platform Attempting to generate new access_token for https://canvas.test.instructure.com +0ms
provider:auth Awaiting return from the platform +44ms
provider:gradeService Response code 400 (Bad Request) +320ms

error log:

{ level: 'error',
  message:
   'Message: Response code 400 (Bad Request)\nStack: HTTPError: Response code 400 (Bad Request)\n    at EventEmitter.emitter.on (/path-to-test-app/node_modules/got/source/as-promise.js:74:19)\n    at process._tickCallback (internal/process/next_tick.js:68:7)',
  timestamp: '2019-10-14T16:16:14.285Z' }

I can see I don't have an access token in my database and lti.js is trying to get one from the platform. When I look at the console output of confjwt in Auth.js, it seems like I'm getting the appropriate client ID and endpoint (https://ouruniversity.test.instructure.com/login/oauth2/token) before the jwt sign, so I'm not sure why the request is bad.

Does anyone know what I might be doing wrong or can point me to where I can get more debug information?

Works with Blackboard?

Describe the solution you'd like
I would like to know if it is possible to use it with Blackboard?

Serverless support (AWS)?

I would love to use this library in an AWS lambda function. That seems like it would require the ability to swap out dependence on an Express server and instead allow the function to be called with HTTP routes that come in through AWS API Gateway. Has anyone considered using ltijs in this way? I'm imagining a server plugin architecture in the same way that you have implemented database plugin support. Thoughts? I'm so happy that this exists and would love to collaborate in making it serverless compatible.
~Nathaniel

OIDC login doesn't work when initiated with GET request

I'm testing against the IMS reference platform https://lti-ri.imsglobal.org/

OIDC login works if initiated with a POST request, but not with a GET request, which I believe tools should also support.

The code handling the login request looks for stuff into req.body, but this will only work for POST requests. For GET requests, you will need to look into req.query instead.

I've created a:
const params = { ...req.body, ...req.query }
to merge both, and that seems to work okay. Can't believe Express doesn't do that for us in 2020!

Anyway, looks like a simple fix.

Thanks for your awesome work on this library!

NRPS link header parsing does not work if there are multiple links

For example, Canvas returns link headers that have multiple links: <http://192.168.55.182:8900/api/lti/courses/1/names_and_roles?page=1&per_page=1>; rel="current",<http://192.168.55.182:8900/api/lti/courses/1/names_and_roles?page=2&per_page=1>; rel="next",<http://192.168.55.182:8900/api/lti/courses/1/names_and_roles?page=1&per_page=1>; rel="first",<http://192.168.55.182:8900/api/lti/courses/1/names_and_roles?page=2&per_page=1>; rel="last"

if (headers.link && headers.link.search(/rel=.*next/)) next = headers.link.split(';rel=next')[0]

Missing await

When the provider inserts idtoken and contexttoken, it's missing an await keyword.

This means I'm returning a 307 before data has actually been inserted in my (DynamoDB) database.

When the LTI platform immediately comes back to me, the request fails because I'm trying to look up stuff in the database that hasn't been inserted yet.

Error retrieving NameAndRoles

Describe the bug
I'm trying to retrieve data in class NamesAndRoles - function getMembers and get the error HTTPError: Response code 500 (Internal Server Error)

I have logged the data platform from this line

// NameAndRoles.js
async getMembers(idtoken, options) {
...
const platform = await (0, _classPrivateFieldGet2.default)(this, _getPlatform).call(this, idtoken.iss, idtoken.clientId, (0, _classPrivateFieldGet2.default)(this, _ENCRYPTIONKEY), (0, _classPrivateFieldGet2.default)(this, _Database));

console.log({ platform }); // { platform: Platform: {} }
...
}

const options = { limit: 1 };
const idtoken = {
    iss: 'https://canvas.instructure.com',
    user: 'a684e22b-9978-4cef-98d8-98ee5f4cfd6c',
    platformInfo: {
        guid: 'OJwJhR6cNZVC9aiyUh8DLT9onnyVif2hOWpa5490:canvas-lms',
        name: 'Root account',
        version: 'cloud',
        product_family_code: 'canvas',
        validation_context: null
    },
    clientId: '10000000000004',
    platformId: '8421b0dc94540ac04bdf13cc5f7f4460',
    deploymentId: '24:e7484a3d7fa6e228f44fc0fd50c318add6f918bf',
    createdAt: '2020-11-13T03:43:04.941Z',
    platformContext: {
        roles: [Array],
        contextId: 'https%3A%2F%2Fcanvas.instructure.com1000000000000424%3Ae7484a3d7fa6e228f44fc0fd50c318add6f918bfe7484a3d7fa6e228f44fc0fd50c318add6f918bf_e7484a3d7fa6e228f44fc0fd50c318add6f918bf',
        path: '/',
        user: 'a684e22b-9978-4cef-98d8-98ee5f4cfd6c',
        targetLinkUri: 'https://localhost:3003',
        context: [Object],
        resource: [Object],
        launchPresentation: [Object],
        messageType: 'LtiResourceLinkRequest',
        version: '1.3.0',
        endpoint: [Object],
        namesRoles: [Object],
        createdAt: '2020-11-13T03:43:04.957Z'
    }
}

NameAndRolesConsumer

// NameAndRolesConsumer.js
async function caller() {
    const token = res.locals.token;
    const result = await lti.NamesAndRoles.getMembers(token, { limit: 1 });
}

Expected behavior
The expected response will be look like the provided response in the documentation in namesandroles

{
  "id" : "https://lms.example.com/sections/2923/memberships",
  "context": {
    "id": "2923-abc",
    "label": "CPS 435",
    "title": "CPS 435 Learning Analytics",
  },
  "members" : [
    {
      "status" : "Active",
      "name": "Jane Q. Public",
      "picture" : "https://platform.example.edu/jane.jpg",
      "given_name" : "Jane",
      "family_name" : "Doe",
      "middle_name" : "Marie",
      "email": "[email protected]",
      "user_id" : "0ae836b9-7fc9-4060-006f-27b2066ac545",
      "lis_person_sourcedid": "59254-6782-12ab",
      "roles": [
        "http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor"
      ]
    }
  ]
}

Provider logs
Copy of the relevant provider logs.

  1. Run code with debug flag: DEBUG=provider:* npm start.
  2. Copy logs relevant to the issue.
2020-11-13T11:32:26.163Z provider:namesAndRolesService HTTPError: Response code 500 (Internal Server Error)
at Request.<anonymous> (/app/node_modules/got/dist/source/as-promise/index.js:117:42)
at processTicksAndRejections (internal/process/task_queues.js:97:5)

Screenshots
If applicable, add screenshots to help explain your problem.

Ltijs version

  • Version 1.3 (maybe...) i got this information form package.json file

NodeJS version

  • Version 12.19.0 - containerized in Docker with image node:12.19.0-alpine

Platform used

  • Canvas

Additional context
LTI configuration function

// Setup function
const setup = async () => {
    await lti.deploy({ port: vars.PORT }); // vars.PORT = 3000

    const ltiPlatConfig = {
        url: 'https://canvas.instructure.com',
        name: 'dvseok',
        clientId: '10000000000004',
        authenticationEndpoint: 'http://dvseok.shop/api/lti/authorize_redirect',
        accesstokenEndpoint: 'http://dvseok.shop/login/oauth2/token',
        authConfig: {
            method: 'JWK_SET',
            key: 'http://dvseok.shop/api/lti/security/jwks',
        },
    };

    const platform = await lti.registerPlatform(ltiPlatConfig);
    console.log(platform); // { Platform: {}}
};

Hosting LTI provider on different domain

I'm attempting to get a development version of a basic LTI instance working with a live production Moodle instance. I'm hosting the tool locally and am attempting to update the grade book of the Moodle instance but am running into a CORS issue where I'm being blocked by the Moodle instance for making a cross-site request.

I have the LTI connecting and loading an HTML page with a button that fires off this function:

function SendGrade () {
            const Http = new XMLHttpRequest();
            const url='https://www.myMoodleURL/grade?ltik=' + ltik;
            Http.open("POST", url);
            Http.send();
}

This request is getting denied for being cross-site since it's originating from my localhost.

I'm hoping there is a way around this that I'm just missing.

Any help of how I can make my requests into my Moodle instance from a separately hosted domain would be much appreciated.

Missing "state" field in OIDC login response

Hi there!
Utils.Reqest.ltiAdvantageLogin() doesn't seem to set the state field in the OIDC login response, which I believe is mandatory according to specs, so it can later be validated together with the id_token in Utils.Auth.validateToken().
Am I missing something, or is this something you plan to add?
Thanks!

Invalid session cookies on prod environment

Hi,
We are not completely sure if this is a ltijs issue, but we tried everything we can and not able to get this working.

Here's our setup for our prod environment:

// Setup
lti.setup(process.env.LTI_KEY,
  {
    url: 'mongodb+xxxxxxxxx/' + process.env.DB_NAME,
    connection: { user: process.env.DB_USER, pass: process.env.DB_PASS }
  }, {
    staticPath: path.join(__dirname, './public'), // Path to static files
    cookies: {
      secure: true, // Set secure to true if the testing platform is in a different domain and https is being used
      sameSite: '', // Set sameSite to 'None' if the testing platform is in a different domain and https is being used
      domain: '.xyz.com'
    },
    devMode: false // Set DevMode to true if the testing platform is in a different domain and https is not being used
  })

Now, when we do a fetch request for the /info route like this...

const getLTIInfo = async(ltiToken) => {
  const response = await fetch(`https://lti.xyz.com/info?ltik=${ltiToken}`, {
    method: 'GET',
    credentials: "same-origin",
    headers: {
      'Content-Type': 'application/json'
    }
  });
  return response.json();
}

LTIJS is unable to find the session cookies.
Any idea on what we are not doing right here? I thought setting the credentials to same-origin should automatically pick up the cookies from the browser from the same origin, but it is not.

Question on Deeplinking Request

Hi, I am confused on this Deep Linking Request process. Here's what I am trying to:

  1. I am in Canvas trying to create an assignment.
  2. I selected the submission type as "External Tool".
    Here's a screenshot for this: https://www.screencast.com/t/MAL2cgpK
  3. Now, I am confused on when EXACTLY Canvas calls the LTI deep launch.
  4. You have it in your docs that Deep linking endpoints are the same as main launch. If this is the case, how do I know when to present our UI to select or create a new resource?
    Could anyone please shed some light on the points 3 & 4 so I can move forward with this?
    Thanks a lot!

Cannot connect to self-hosted Canvas lms

I have tried ltijs to connect to our self-hosted Canvas at http://dvseok.shop but I cannot get token in function lti.onConnect, it returend undefined. this is our config:

await lti.registerPlatform({
    url: "http://dvseok.shop",
    name: "dvseok",
    clientId: "10000000000003",
    authenticationEndpoint: "http://dvseok.shop/api/lti/authorize_redirect",
    accesstokenEndpoint: "http://dvseok.shop/login/oauth2/token",
    authConfig: {
      method: "JWK_SET",
      key: "http://dvseok.shop/api/lti/security/jwks",
    },
  });

I also tried with your demo project ltijs-demo-server and ltijs-demo-client, when I go to browser of ltijs-demo-client, it always displayed Failed retrieving members! Error: Missing lti key..

I tried to calling a GET request /info demo server with my Canvas LTI key. This is the response:

{
    "status": 401,
    "error": "Unauthorized",
    "details": {
        "message": "Error validating LTIK or IdToken",
        "errorLog": "jwt malformed"
    }
}

Am I missing anything? Thanks!

Awesome project

Just wanna say this is an awesome project. The majority of LTI libraries are for PHP, outdated, and haven't been touched in quite a while, so seeing a new one for Node is quite uplifting.

Any ideas about loosening the requirements for Mongo? My backend is on Firebase cloud functions (so uses Firestore as the database) haha.

Either way amazing job!

Platform settings for self-hosted Canvas

Hi,
I installed Canvas and self-hosting it on our own server. I am confused about the platform settings for this type of setup.

Here's my platform setup:

  const plat = await lti.registerPlatform({
    url: 'https://canvas.greenos.io',
    name: 'Greenos Canvas',
    clientId: '10000000000001',
    authenticationEndpoint:'https://canvas.instructure.com/api/lti/authorize_redirect',
    accesstokenEndpoint:'https://canvas.greenos.io/login/oauth2/token',
    authConfig: { 
      method: 'JWK_SET', 
      key: 'https://canvas.instructure.com/api/lti/security/jwks' }
  })

And upon deployment of the app and trying to launch, I am getting an error Unregistered platform attempting connection.

 [email protected] start /use/src/app
lti
> env DEBUG=provider:* node index.js
lti
environment variables...
lti
LTIKEY
lti
dynosadmin
lti
2020-10-21T16:18:36.253Z provider:main Attempting to connect to database
lti
2020-10-21T16:18:36.677Z provider:database Database connected
lti
2020-10-21T16:18:36.678Z provider:database Database connection open
lti
2020-10-21T16:18:36.686Z provider:main Ltijs started listening on port: 3000
lti
_ _______ _____ _ _____
lti
| | |__ __|_ _| | |/ ____|
lti
| | | | | | | | (___
lti
| | | | | | _ | |\___ \
lti
| |____| | _| |_| |__| |____) |
lti
|______|_| |_____|\____/|_____/
lti
LTI Provider is listening on port 3000!
lti
LTI provider config:
lti
>App Route: /
lti
>Initiate Login Route: /login
lti
>Keyset Route: /keys
lti
>Session Timeout Route: /sessiontimeout
lti
>Invalid Token Route: /invalidtoken
lti
2020-10-21T16:18:37.111Z provider:main Registering new platform
lti
2020-10-21T16:18:37.111Z provider:main Platform Url: https://canvas.greenos.io
lti
2020-10-21T16:18:37.111Z provider:main Platform ClientId: 10000000000001
lti
-----BEGIN PUBLIC KEY-----
lti
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqvImuTa1FlP8Pf6t46rH
lti
/QRohlYxabcy0Dzo5h4Gjkco+kVd2QnVz3slEHyFxF71R8tk8Zas22qSu2VCe8PY
lti
hiJaSDesUaH+mHiMIu++fnUAea3IZH1MVfst1GzbKuR5/wQzclW+atVtKIbAezyr
lti
GDfSyuxbsDI0eyuy5gLHZ2wdzKJsN4wcM1DMTAJdpsWD/U2Dsbilcn/zRcKN2iuZ
lti
JbdZTckIQm3khKDjORHtY3vBR7KEv3k4Zmr90aKUNTbDSa2NH8DwRoG5qOg/+A1e
lti
CAZlwxtMFNotd5/b5YUlPORdBLL/i0wSel6/Ebnm+mhCgmBJDYnIGbzB0aTh0wQ4
lti
jhDQlKvXoaLZ+xO6nYYCbInol2OZkuZ98n+ksX6SVPQdjumYy8yp1OSyX0dBGV7M
lti
fKRr3ngAx1yXpYPljQdEJMP/btn6Jp+HNJFb89YqcG+h6MglKFELJnoZsevX2yxp
lti
sOkPYEgMUmehJsPcq3iufMLN6kILwm1mxBa1eMVPA5nS2+pNPxNulUqOsS4LNXYy
lti
CWHfZ4ima01ZXQxuVSbdbVToxYs/WGCe2vrlRu8YMqF4S/pgelcuwkMeWZzMjotz
lti
4c3EUW9yARgDeavUYgVp83nQwRRulhkDZwoBgDnnwUDhVOlPEV8Zdav6PVQv4KIq
lti
e4oc5QFI6raaZ1wWUpuOq2UCAwEAAQ==
lti
-----END PUBLIC KEY-----
lti
Deployed!
lti
2020-10-21T16:19:44.200Z provider:main Receiving request at path: /login
lti
2020-10-21T16:19:44.201Z provider:main Receiving a login request from: https://canvas.instructure.com
lti
2020-10-21T16:19:44.230Z provider:main Unregistered platform attempting connection: https://canvas.instructure.com

I looked into other issues reported on Canvas setup, but they are for cloud-hosted canvas. I just wanted to check with the community here to see if they can point out any problem in my platform setup.

Also, another question: Where can we use the Deployment Id provided by canvas?

Thanks a lot!

Course roles, course lis data, course endpoints, and course services are stored in the idtokens

Describe the bug
It seems that course roles, course lis data, course endpoints, and course services are stored in the idtokens collection instead of the contexttokens collection. So if I access a CIS100 course, then access a HIS180 course, the CIS100 data is lost and overridden with the HIS180 course data. This is a likely scenario as learners and faculty may have multiple web browser tabs open. There is another scenario where faculty need to grade work in the LTI app before passing grades back the LMS. This may impact grade pass back.

Expected behavior
Course roles, course lis data, course endpoints, and course services should be stored with the contexttoken.
Institution and system roles should be stored with the idtoken.

Provider logs
N/a

Screenshots
N/a

Ltijs version

  • Version 5.1.0

NodeJS version

  • Version 14.9.0

Platform used

  • Moodle

Additional context
N/a

Get rid of parse-domain

parse-domain has jest as a dependency, which brings in tons of unnecessary stuff.
This is insane, and the author doesn't seem too bothered about it.

This makes parse-domain, and therefore ltijs, almost unfit for an AWS lambda environment, where you really want to keep things as small as possible.

Can we look for an alternative, or maybe just implement a cookieDomain option?

Thanks!

Configurable token max age

At the moment, Utils.Auth.validateIat() has a hard-coded limit of 10 seconds for the token max age. It would be great for manual testing to be able to configure this max age, e.g. 1 minute.

Cookie is not saved in Safari

Describe the bug
Hello, It does not save the cookie in the safari browser, I enter through chrome and it saves the cookie, I receive the INVALID_TOKEN error in sarafi in chrome I do not get it, I have this configuration

 appRoute: '/',
     loginRoute: '/ login',
     logger: false,
     staticPath: APP_FOLDER,
     tokenMaxAge: false,
     cookies: {
         secure: true,
         sameSite: 'None'
     }

the moodle installation has a different url than the tool, both are https

Expected behavior
The expected behavior is that the cookie is saved in safari and allows the plugin to be opened

Provider logs
2020-09-08 15:41:08 default[prod] 2020-09-08T15:41:08.871Z provider:main Receiving request at path: /login
2020-09-08 15:41:08 default[prod] 2020-09-08T15:41:08.871Z provider:main Receiving a login request from: https://client.net
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.296Z provider:main Redirecting to platform authentication endpoint
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.296Z provider:main Generated state: stateId
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.297Z provider:main Login request:
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.297Z provider:main {
2020-09-08 15:41:09 default[prod] response_type: 'id_token',
2020-09-08 15:41:09 default[prod] response_mode: 'form_post',
2020-09-08 15:41:09 default[prod] id_token_signed_response_alg: 'RS256',
2020-09-08 15:41:09 default[prod] scope: 'openid',
2020-09-08 15:41:09 default[prod] client_id: 'cliendidexample',
2020-09-08 15:41:09 default[prod] redirect_uri: 'https://example.net/',
2020-09-08 15:41:09 default[prod] login_hint: 'loginhintId',
2020-09-08 15:41:09 default[prod] nonce: 'nonceId',
2020-09-08 15:41:09 default[prod] prompt: 'none',
2020-09-08 15:41:09 default[prod] state: 'stateId',
2020-09-08 15:41:09 default[prod] lti_message_hint: 'ltihint'
2020-09-08 15:41:09 default[prod] }
2020-09-08 15:41:09 default[prod] "POST / HTTP/1.1" 302
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:main Receiving request at path: /
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:main Path does not match reserved endpoints
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:main Cookies received:
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:main [Object: null prototype] {}
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:main Received idtoken for validation
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:auth Response state: stateid
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:auth Attempting to validate iss claim
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:auth Request Iss claim: undefined
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:auth Response Iss claim: https://client.net
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:auth Error: ISS_CLAIM_DOES_NOT_MATCH
2020-09-08 15:41:09 default[prod] at Function.validateToken (/workspace/node_modules/ltijs/dist/Utils/Auth.js:97:27)
2020-09-08 15:41:09 default[prod] at sessionValidator (/workspace/node_modules/ltijs/dist/Provider/Provider.js:300:38)
2020-09-08 15:41:09 default[prod] at Layer.handle [as handle_request] (/workspace/node_modules/express/lib/router/layer.js:95:5)
2020-09-08 15:41:09 default[prod] at trim_prefix (/workspace/node_modules/express/lib/router/index.js:317:13)
2020-09-08 15:41:09 default[prod] at /workspace/node_modules/express/lib/router/index.js:284:7
2020-09-08 15:41:09 default[prod] at Function.process_params (/workspace/node_modules/express/lib/router/index.js:335:12)
2020-09-08 15:41:09 default[prod] at next (/workspace/node_modules/express/lib/router/index.js:275:10)
2020-09-08 15:41:09 default[prod] at serveStatic (/workspace/node_modules/serve-static/index.js:75:16)
2020-09-08 15:41:09 default[prod] at Layer.handle [as handle_request] (/workspace/node_modules/express/lib/router/layer.js:95:5)
2020-09-08 15:41:09 default[prod] at trim_prefix (/workspace/node_modules/express/lib/router/index.js:317:13)
2020-09-08 15:41:09 default[prod] at /workspace/node_modules/express/lib/router/index.js:284:7
2020-09-08 15:41:09 default[prod] at Function.process_params (/workspace/node_modules/express/lib/router/index.js:335:12)
2020-09-08 15:41:09 default[prod] at next (/workspace/node_modules/express/lib/router/index.js:275:10)
2020-09-08 15:41:09 default[prod] at /workspace/node_modules/express-bearer-token/index.js:84:9
2020-09-08 15:41:09 default[prod] at Layer.handle [as handle_request] (/workspace/node_modules/express/lib/router/layer.js:95:5)
2020-09-08 15:41:09 default[prod] at trim_prefix (/workspace/node_modules/express/lib/router/index.js:317:13)
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.626Z provider:main Passing request to invalid token handler
2020-09-08 15:41:09 default[prod] "GET /invalidtoken HTTP/1.1" 401
2020-09-08 15:41:09 default[prod] 2020-09-08T15:41:09.710Z provider:main Receiving request at path: /invalidtoken

Screenshots
image

Ltijs version

  • Version 5.0.2

NodeJS version

  • Version 12

Platform used

  • Moodle moodle rooms

Additional context
Add any other context about the problem here.

[FEATURE] Implement Deep Linking service

Implement the Deep Linking service

Methods to receive content-item claim objects and return:

  • A self submitting post form with the signed JWT message.
  • Only the signed JWT message so that the user can submit it as he sees fit.

Support for optional claims like success and error messages.

[Bug][Database] Using ltijs in cluster mode with pm2 causes platform registration at startup to create duplicates

Description: Using ltijs in cluster mode with pm2 causes platform registration at startup to create duplicates.

Probable cause: The test for duplicate platforms is done at a application level, so when in cluster mode, each application instance attempts to register a platform at the same time, which causes the duplicate, since the database has not yet registered the addition.

Fix: Add the 'unique' tag to platformurl field in the database.

Possibility of selecting multiple resources with deeplinking

Hi,
So far we have been planning to implement our tool UI to select only one resource at a time. Reading LTIJS docs, we understand that some platforms maynot allow the tools to select more than one.
Given all of this, we are seeing some impelmentations like shown in this video https://www.youtube.com/watch?v=zBbN41fyIlA where they manage to send more than one resource from the tool using course level placement. Just wondering if there Is there anyway we can achieve this using LTI specs? It does not look like they are using deeplinking workflow laid out in your docs.
Thanks!

Keep getting "No LTIK or IdToken found."message.

Describe the bug
This may be perhaps a problem in the LTIKEY setup.
I did the setup as described in the tutorial. I am using localhost moodle and when I launch the demo tool, I get this error.
{"status":401,"error":"Unauthorized","details":{"message":"No LTIK or IdToken found.","bodyReceived":{}}}

Expected behavior
Expecting it to see "Tool works" or some other success message.

Provider logs
Copy of the relevant provider logs.

  1. Run code with debug flag: DEBUG=provider:* npm start.
  2. Copy logs relevant to the issue.

Screenshots
If applicable, add screenshots to help explain your problem.

Ltijs version

  • Version 5.3.0

NodeJS version

  • Version 12.6.1
    Platform used
  • Moodle (Localhost)

Additional context
Under .env file, I am using LTI_KEY=LTIKEY. Do we need to change this something else?
Is this where I need to keep the private key?

Multiple platforms

I want to make an LTI provider tool, is it possible to have multiple platforms (multiple Moodles) connected?

gradeservice 400 bad request in moodle

Describe the bug
Thanks for the great library. Unfortunately i'm facing issues in the gradingservice for moodle. it throws 400 bad request.

Provider logs
provider:auth Cookie found +0ms
provider:main Passing request to next handler +4s
provider:gradeService Target platform: http://localhost:8888/moodle +0ms
provider:gradeService Attempting to retrieve platform access_token for [http://localhost:8888/moodle] +5ms
provider:platform Access_token for http://localhost:8888/moodle not found +0ms
provider:platform Attempting to generate new access_token for http://localhost:8888/moodle +0ms
provider:auth Awaiting return from the platform +0ms
provider:gradeService Response code 400 (Bad Request) +172ms

Screenshots
If applicable, add screenshots to help explain your problem.
image

Ltijs version

  • Version 5.0.3

NodeJS version

  • Version 12.14.0

Platform used

  • Moodle

howto debug "Token invalid or expired. Please reinitiate login."

I'm trying to build a "tool" for moodle. I am not able to get ltijs working, because I always get the message

Token invalid or expired. Please reinitiate login.

from within moodle. I can configure and setup the tool itself (I get an access token public/private keys, etc.) but that's all.

So, I'm wondering, what can I do in order to figure out what's going on?

Custom middleware

Hello again!

Fantastic work on your LTI library, please keep it up!

I had to do some serious HTTP logging of all requests and responses, including headers and body, so I ended up adding the following code inside Server.js at the end of the constructor:

    this.app.use((req, res, next) => {
      debugHttpReq(`${req.method} ${req.originalUrl}`)
      Object.entries(req.headers).forEach(([name, value]) => {
        debugHttpReq(`${name}: ${value}`)
      })
      debugHttpReq(req.body)
      res.on('finish', () => {
        debugHttpResp(
          `${res.statusCode} ${res.statusMessage}; ${res.get(
            'Content-Length'
          ) || 0}b sent`
        )
        debugHttpResp(res._header)
        debugHttpResp(res.etp_body)
      })
      const oldWrite = res.write
      const oldEnd = res.end
      const chunks = []
      res.write = (...restArgs) => {
        chunks.push(Buffer.from(restArgs[0]))
        oldWrite.apply(res, restArgs)
      }
      res.end = (...restArgs) => {
        if (restArgs[0]) {
          chunks.push(Buffer.from(restArgs[0]))
        }
        res.etp_body = Buffer.concat(chunks).toString('utf8')
        oldEnd.apply(res, restArgs)
      }
      next()
    });

I know everybody will want to do their own logging slightly differently, so I'm not asking you to add the code above to your library.

What would be awesome though... when I create my LTI object, if I could pass an optional appConfigFn function, and that function would be called with the Express app as a parameter, and it could do whatever it wants, e.g. install custom logging middleware :)

What do you think?

Where do we input Deployment id?

Almost all the platforms give us deployment id;s. When we register a platform, don't we need to add the deployment id? I don't see in the platform class.Is it something tool needs to take care of it on its own?

Canvas External app Setup

Hi @Cvmcosta I was able get everything working with Moodle. Now when i try to register an external app with Canvas, it asks for consumer key and secret. How do get these keys?
image
do you have any tutorial for Canvas similar to what you have for moodle?

Issues with Hosted LTIJS server

Describe the bug
I moved the LTIJS server code to a hosted server and trying to integrate with a Localhost Moodle and having an Unauthorized 401 error.

Expected behavior
I am expecting it to read the LTIKEY properly and authenticate the request.
Provider logs

lti
> [email protected] start /use/src/app
lti
> env DEBUG=provider:* node index.js
lti
environment variables...
lti
LTIKEY
lti
dynosadmin
lti
2020-10-19T04:58:13.929Z provider:main Attempting to connect to database
lti
2020-10-19T04:58:14.287Z provider:database Database connected
lti
2020-10-19T04:58:14.287Z provider:database Database connection open
lti
2020-10-19T04:58:14.293Z provider:main Ltijs started listening on port: 3000
lti
_ _______ _____ _ _____
lti
| | |__ __|_ _| | |/ ____|
lti
| | | | | | | | (___
lti
| | | | | | _ | |\___ \
lti
| |____| | _| |_| |__| |____) |
lti
|______|_| |_____|\____/|_____/
lti
LTI Provider is listening on port 3000!
lti
LTI provider config:
lti
>App Route: /
lti
>Initiate Login Route: /login
lti
>Keyset Route: /keys
lti
>Session Timeout Route: /sessiontimeout
lti
>Invalid Token Route: /invalidtoken
lti
Starting in Dev Mode, state validation and session cookies will not be required. THIS SHOULD NOT BE USED IN A PRODUCTION ENVIRONMENT!
lti
2020-10-19T04:58:14.430Z provider:main Platform already registered
lti
-----BEGIN PUBLIC KEY-----
lti
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwjYuHsWBQRH8ori9+cbF
lti
ov7am78z8xotcEOx0r9w4Rz3R5ReS8K8Y54vWZGIX/qlQQvdJ5vXBjxMjz8PCtRw
lti
mM0PMLdQO3kkn/meCZlb//GsIJaOCP6zbFoAIz7IkyEJJ3dtILIgsSiR5zu5aPyV
lti
/5lUGm2Z2zQGlZbzH9GhuAVMBOx7qk4P5FNs1GZXenQSHyq+bB5EJ9eqmurEoZUb
lti
lSypE//AzTGP+9JXInT9tkeBqrqOrXFgEtrZB+rCrqOLvXBy9zFtWt0i3YIepWWx
lti
DQoodv9Vti2/e9E2uLEtviVraSwwec6jN1ry716Z1zys+4+sx3CDLt3b3hhfW5OV
lti
Dl8JzcWcHuAJIy4KIy+YxKXkDxHM/oRxLqq1Tj5fdSnrw12wO0meCQFuLoSjdxou
lti
/SE1ueBCRB6r+ILID7V/HuU93fu/tgC8K7OHR0KmM1wWWHGcfe8phde5r1K78DEg
lti
amZa4lRgidPBX4ucMtGDm0mdrdazxH1j0R3bNn6YD8Ql8oCyw26gh+DdxnU9HFzE
lti
aW2b1yDp7SDW+mX9PGGwCYbEF+9JH0O1wPa7GP7ieGnjNctJ8HCj/kblBCjjXBF6
lti
aYoAIFlPzTl4PlYiqM2jQEEVh7PeanfIsIXU2gPUY697BWWQkuHsHbuo8VoOmMnz
lti
x/fE5zw3OImEhcUX8Mgr0hcCAwEAAQ==
lti
-----END PUBLIC KEY-----
lti
Deployed!
lti
2020-10-19T04:58:55.942Z provider:main Receiving request at path: /login
lti
2020-10-19T04:58:55.943Z provider:main Receiving a login request from: http://localhost
lti
2020-10-19T04:58:55.962Z provider:main Redirecting to platform authentication endpoint
lti
2020-10-19T04:58:55.962Z provider:main Target Link URI: https://stg-lti.dynos.io
lti
2020-10-19T04:58:55.963Z provider:main Login request:
lti
2020-10-19T04:58:55.966Z provider:main {
lti
response_type: 'id_token',
lti
response_mode: 'form_post',
lti
id_token_signed_response_alg: 'RS256',
lti
scope: 'openid',
lti
client_id: 'sWZ99TqdxZnkXqC',
lti
redirect_uri: 'https://stg-lti.dynos.io',
lti
login_hint: '2',
lti
nonce: 'tnab8bh49xqwbhc2b0d4i68us',
lti
prompt: 'none',
lti
state: '675daef7e498e773123fc795e2058888e3db7da9e5c339992a',
lti
lti_message_hint: '5',
lti
lti_deployment_id: '2'
lti
}
lti
2020-10-19T04:58:56.853Z provider:main Receiving request at path: /
lti
2020-10-19T04:58:56.853Z provider:main Path does not match reserved endpoints
lti
2020-10-19T04:58:56.853Z provider:main Cookies received:
lti
2020-10-19T04:58:56.854Z provider:main [Object: null prototype] {}
lti
2020-10-19T04:58:56.854Z provider:main Received idtoken for validation
lti
2020-10-19T04:58:56.854Z provider:auth Response state: 675daef7e498e773123fc795e2058888e3db7da9e5c339992a
lti
2020-10-19T04:58:56.856Z provider:auth Attempting to validate iss claim
lti
2020-10-19T04:58:56.856Z provider:auth Request Iss claim: undefined
lti
2020-10-19T04:58:56.857Z provider:auth Response Iss claim: http://localhost
lti
2020-10-19T04:58:56.857Z provider:auth Dev Mode enabled: Missing state validation cookies will be ignored
lti
2020-10-19T04:58:56.857Z provider:auth Attempting to retrieve registered platform
lti
2020-10-19T04:58:56.872Z provider:auth Retrieving key from jwk_set
lti
2020-10-19T04:59:00.035Z provider:main Deleting state cookie and Database entry
lti
2020-10-19T04:59:00.055Z provider:auth RequestError: connect ECONNREFUSED 127.0.0.1:80
lti
at ClientRequest. (/use/src/app/node_modules/got/dist/source/core/index.js:957:25)
lti
at Object.onceWrapper (events.js:421:26)
lti
at ClientRequest.emit (events.js:326:22)
lti
at ClientRequest.origin.emit (/use/src/app/node_modules/@szmarczak/http-timer/dist/source/index.js:39:20)
lti
at Socket.socketErrorListener (_http_client.js:428:9)
lti
at Socket.emit (events.js:314:20)
lti
at emitErrorNT (internal/streams/destroy.js:92:8)
lti
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
lti
at processTicksAndRejections (internal/process/task_queues.js:84:21)
lti
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1145:16)
lti
2020-10-19T04:59:00.056Z provider:main Passing request to invalid token handler
lti
2020-10-19T04:59:00.160Z provider:main Receiving request at path: /invalidtoken
lti
2020-10-19T04:59:21.434Z provider:main Receiving request at path: /login
lti
2020-10-19T04:59:21.434Z provider:main Receiving a login request from: http://localhost
lti
2020-10-19T04:59:21.450Z provider:main Redirecting to platform authentication endpoint
lti
2020-10-19T04:59:21.450Z provider:main Target Link URI: https://stg-lti.dynos.io
lti
2020-10-19T04:59:21.450Z provider:main Login request:
lti
2020-10-19T04:59:21.450Z provider:main {
lti
response_type: 'id_token',
lti
response_mode: 'form_post',
lti
id_token_signed_response_alg: 'RS256',
lti
scope: 'openid',
lti
client_id: 'sWZ99TqdxZnkXqC',
lti
redirect_uri: 'https://stg-lti.dynos.io',
lti
login_hint: '2',
lti
nonce: 'k279crznlzireb0zqxut9aj0a',
lti
prompt: 'none',
lti
state: 'a1d02b511a967c096b05e1bfc42be52c892cce60f713b6cdda',
lti
lti_message_hint: '5',
lti
lti_deployment_id: '2'
lti
}
lti
2020-10-19T04:59:22.407Z provider:main Receiving request at path: /
lti
2020-10-19T04:59:22.407Z provider:main Path does not match reserved endpoints
lti
2020-10-19T04:59:22.407Z provider:main Cookies received:
lti
2020-10-19T04:59:22.407Z provider:main [Object: null prototype] {}
lti
2020-10-19T04:59:22.407Z provider:main Received idtoken for validation
lti
2020-10-19T04:59:22.407Z provider:auth Response state: a1d02b511a967c096b05e1bfc42be52c892cce60f713b6cdda
lti
2020-10-19T04:59:22.408Z provider:auth Attempting to validate iss claim
lti
2020-10-19T04:59:22.408Z provider:auth Request Iss claim: undefined
lti
2020-10-19T04:59:22.408Z provider:auth Response Iss claim: http://localhost
lti
2020-10-19T04:59:22.408Z provider:auth Dev Mode enabled: Missing state validation cookies will be ignored
lti
2020-10-19T04:59:22.408Z provider:auth Attempting to retrieve registered platform
lti
2020-10-19T04:59:22.423Z provider:auth Retrieving key from jwk_set
lti
2020-10-19T04:59:25.513Z provider:main Deleting state cookie and Database entry
lti
2020-10-19T04:59:25.528Z provider:auth RequestError: connect ECONNREFUSED 127.0.0.1:80
lti
at ClientRequest. (/use/src/app/node_modules/got/dist/source/core/index.js:957:25)
lti
at Object.onceWrapper (events.js:421:26)
lti
at ClientRequest.emit (events.js:326:22)
lti
at ClientRequest.origin.emit (/use/src/app/node_modules/@szmarczak/http-timer/dist/source/index.js:39:20)
lti
at Socket.socketErrorListener (_http_client.js:428:9)
lti
at Socket.emit (events.js:314:20)
lti
at emitErrorNT (internal/streams/destroy.js:92:8)
lti
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
lti
at processTicksAndRejections (internal/process/task_queues.js:84:21)
lti
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1145:16)
lti
2020-10-19T04:59:25.528Z provider:main Passing request to invalid token handler
lti
2020-10-19T04:59:25.601Z provider:main Receiving request at path: /invalidtoken
lti
2020-10-19T05:06:24.955Z provider:main Receiving request at path: /
lti
2020-10-19T05:06:24.955Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:06:24.955Z provider:main Cookies received:
lti
2020-10-19T05:06:24.955Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:06:24.956Z provider:main Accessing as whitelisted route
lti
2020-10-19T05:07:13.690Z provider:main Receiving request at path: /
lti
2020-10-19T05:07:13.690Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:07:13.690Z provider:main Cookies received:
lti
2020-10-19T05:07:13.690Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:07:13.691Z provider:main Accessing as whitelisted route
lti
2020-10-19T05:07:13.758Z provider:main Receiving request at path: /main
lti
2020-10-19T05:07:13.758Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:07:13.758Z provider:main Cookies received:
lti
2020-10-19T05:07:13.758Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:07:13.758Z provider:main No ltik found
lti
2020-10-19T05:07:13.758Z provider:main Request body: {}
lti
2020-10-19T05:07:13.758Z provider:main Passing request to invalid token handler
lti
2020-10-19T05:07:13.825Z provider:main Receiving request at path: /invalidtoken
lti
2020-10-19T05:09:05.241Z provider:main Receiving request at path: /
lti
2020-10-19T05:09:05.241Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:09:05.241Z provider:main Cookies received:
lti
2020-10-19T05:09:05.241Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:09:05.241Z provider:main Accessing as whitelisted route
lti
2020-10-19T05:09:05.306Z provider:main Receiving request at path: /main
lti
2020-10-19T05:09:05.306Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:09:05.306Z provider:main Cookies received:
lti
2020-10-19T05:09:05.306Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:09:05.306Z provider:main No ltik found
lti
2020-10-19T05:09:05.306Z provider:main Request body: {}
lti
2020-10-19T05:09:05.306Z provider:main Passing request to invalid token handler
lti
2020-10-19T05:09:05.369Z provider:main Receiving request at path: /invalidtoken
lti
2020-10-19T05:09:29.450Z provider:main Receiving request at path: /login
lti
2020-10-19T05:09:29.451Z provider:main Receiving a login request from: http://localhost
lti
2020-10-19T05:09:29.634Z provider:main Redirecting to platform authentication endpoint
lti
2020-10-19T05:09:29.635Z provider:main Target Link URI: https://stg-lti.dynos.io
lti
2020-10-19T05:09:29.635Z provider:main Login request:
lti
2020-10-19T05:09:29.635Z provider:main {
lti
response_type: 'id_token',
lti
response_mode: 'form_post',
lti
id_token_signed_response_alg: 'RS256',
lti
scope: 'openid',
lti
client_id: 'sWZ99TqdxZnkXqC',
lti
redirect_uri: 'https://stg-lti.dynos.io',
lti
login_hint: '2',
lti
nonce: 'kik3wc6ekq1exq00tsnjs0dlo',
lti
prompt: 'none',
lti
state: '5e52b6335424d210dc6f45b3b7280f478918f32cf8ea739e64',
lti
lti_message_hint: '5',
lti
lti_deployment_id: '2'
lti
}
lti
2020-10-19T05:09:30.481Z provider:main Receiving request at path: /
lti
2020-10-19T05:09:30.482Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:09:30.482Z provider:main Cookies received:
lti
2020-10-19T05:09:30.482Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:09:30.482Z provider:main Received idtoken for validation
lti
2020-10-19T05:09:30.482Z provider:auth Response state: 5e52b6335424d210dc6f45b3b7280f478918f32cf8ea739e64
lti
2020-10-19T05:09:30.484Z provider:auth Attempting to validate iss claim
lti
2020-10-19T05:09:30.484Z provider:auth Request Iss claim: undefined
lti
2020-10-19T05:09:30.484Z provider:auth Response Iss claim: http://localhost
lti
2020-10-19T05:09:30.484Z provider:auth Dev Mode enabled: Missing state validation cookies will be ignored
lti
2020-10-19T05:09:30.484Z provider:auth Attempting to retrieve registered platform
lti
2020-10-19T05:09:30.498Z provider:auth Retrieving key from jwk_set
lti
2020-10-19T05:09:33.545Z provider:main Deleting state cookie and Database entry
lti
2020-10-19T05:09:33.559Z provider:auth RequestError: connect ECONNREFUSED 127.0.0.1:80
lti
at ClientRequest. (/use/src/app/node_modules/got/dist/source/core/index.js:957:25)
lti
at Object.onceWrapper (events.js:421:26)
lti
at ClientRequest.emit (events.js:326:22)
lti
at ClientRequest.origin.emit (/use/src/app/node_modules/@szmarczak/http-timer/dist/source/index.js:39:20)
lti
at Socket.socketErrorListener (_http_client.js:428:9)
lti
at Socket.emit (events.js:314:20)
lti
at emitErrorNT (internal/streams/destroy.js:92:8)
lti
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
lti
at processTicksAndRejections (internal/process/task_queues.js:84:21)
lti
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1145:16)
lti
2020-10-19T05:09:33.559Z provider:main Passing request to invalid token handler
lti
2020-10-19T05:09:33.628Z provider:main Receiving request at path: /invalidtoken
lti
2020-10-19T05:14:35.441Z provider:main Receiving request at path: /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
lti
2020-10-19T05:14:35.441Z provider:main Path does not match reserved endpoints
lti
2020-10-19T05:14:35.441Z provider:main Cookies received:
lti
2020-10-19T05:14:35.441Z provider:main [Object: null prototype] {}
lti
2020-10-19T05:14:35.441Z provider:main No ltik found
lti
2020-10-19T05:14:35.441Z provider:main Request body: [Object: null prototype] { '' }
lti
2020-10-19T05:14:35.441Z provider:main Passing request to invalid token handler
lti
2020-10-19T05:14:35.717Z provider:main Receiving request at path: /invalidtoken
lti
2020-10-19T05:18:26.856Z provider:main Receiving request at path: /invalidtoken

Screenshots
Here's a screenshot of the settings: https://prnt.sc/v21we1

Ltijs version
Latest

NodeJS version

  • Version 12

Platform used

  • Localhost Moodle

Additional context
We are seeing this error on the launch: https://prnt.sc/v21x59

Here's our setup:

// Setup
lti.setup(process.env.LTI_KEY,
  {
    url: 'mongodb+srv://cluster0.ekibo.mongodb.net/' + process.env.DB_NAME,
    connection: { user: process.env.DB_USER, pass: process.env.DB_PASS }
  }, {
    staticPath: path.join(__dirname, './public'), // Path to static files
    cookies: {
      secure: false, // Set secure to true if the testing platform is in a different domain and https is being used
      sameSite: '', // Set sameSite to 'None' if the testing platform is in a different domain and https is being used
      domain: '.dynos.io'
    },
    devMode: true // Set DevMode to true if the testing platform is in a different domain and https is not being used
  })

Invalid token. Please reinitiate login.

Describe the bug
Getting "Invalid token. Please reinitiate login." HTTP 401 error in Moodle.

Expected behavior
Show "It's alive"

Provider logs
LTI Provider is listening on port 3000!
LTI provider config:

App Url: /
Initiate login URL: /login
Keyset Url: /keys
Session Timeout Url: /sessionTimeout
Invalid Token Url: /invalidToken
provider:main Platform already registered. +37ms
provider:main Platform already registered. +10ms
provider:main Platform already registered. +7ms
provider:main Receiving request at path: /login +4s
provider:main Receiving a login request from: http://www.mymoodle.local +0ms
provider:main Redirecting to platform authentication endpoint +2ms
provider:main Generated state: c2735a621668668e +0ms
provider:main Login request: {
response_type: 'id_token',
response_mode: 'form_post',
id_token_signed_response_alg: 'RS256',
scope: 'openid',
client_id: 'GISQB0HdF95ijvc',
redirect_uri: 'http://192.168.50.59:3000',
login_hint: '2',
nonce: 'Pm3Dp6GRYlXC4nb9CDM2vA==',
prompt: 'none',
state: 'c2735a621668668e',
lti_message_hint: '2',
lti_deployment_id: '1'
} +8ms
provider:main Receiving request at path: / +75ms
provider:main Path does not match reserved endpoints +0ms
provider:main Cookies received: +0ms
provider:main [Object: null prototype] {} +0ms
provider:main No LTIK found +0ms
provider:main Request body: [Object: null prototype] {
error: 'invalid_request',
state: 'c2735a621668668e'
} +1ms
provider:main Receiving request at path: /invalidToken +23ms

Screenshots


require('dotenv').config()
const path = require('path')

// Require Provider 
const LTI = require('ltijs').Provider

// Configure provider
const lti = new LTI('APPLTREEFRUIT', 
  { url: `mongodb://${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_NAME}` , 
    connection: { 
          useUnifiedTopology: true , 
          useNewUrlParser: true, 
          authSource: 'admin',
          auth: { 
              user:process.env.DB_USER, 
              password: process.env.DB_PASSWORD 
          }
      }
  }, 
  {   appUrl: '/', 
      loginUrl: '/login', 
      logger: true , 
  })


let setup = async () => {
  // Deploy and open connection to the database
  await lti.deploy()
  // Get the public key generated for that platform
  let plat = await lti.registerPlatform({ 
    url: 'http://www.mymoodle.local',
    name: 'Moodle Local',
    clientId: 'GISQB0HdF95ijvc',
    authenticationEndpoint: 'http://172.16.238.38/mod/lti/auth.php',
    accesstokenEndpoint: 'http://172.16.238.38/mod/lti/token.php',
    authConfig: { method: 'JWK_SET', key: 'http://172.16.238.38/mod/lti/certs.php' }
  })    
 
  // Set connection callback
  lti.onConnect((connection, request, response) => {
    // Call redirect function
    console.log("OnConnect:")
    lti.redirect(response, '/main')
  }, { secure: false })

  // Set main endpoint route
  lti.app.get('/main', (req, res) => {
    // Id token
    console.log("LOCALS:")
    console.log(res.locals)
    console.log("")
    res.send('It\'s alive!')
  })
    
}

setup()

Ltijs version
4.1.0

NodeJS version
v14.5.0

Platform used
Moodle tool settings:
Tool URL: http://192.168.50.59:3000
Login URL: http://192.168.50.59:3000/login
Redirect URL: http://192.168.50.59:3000
Public key URL: http://192.168.50.59:3000/keys
(also tried copy/paste keys instead of URL)

Moodle tool config shows
Platform ID: http://www.mymoodle.local
Client ID: GISQB0HdF95ijvc
Deployment ID: 1
Public keyset URL: http://www.mymoodle.local/mod/lti/certs.php
Access token URL: http://www.mymoodle.local/mod/lti/token.php
Authentication request URL: http://www.mymoodle.local/mod/lti/auth.php

Additional context
Running bitnami/moodle in docker mapped to port 80 on localhost
Running LTIJS in vscode remote container mapped to port 3000 on localhost
www.mymoodle.local is 172.16.238.38
localhost is 192.168.50.59

tool_platform is an optional claim but its absence causes a 'property of undefined' error

Describe the bug
Trying to get our new consumer up and running against our LTI tool, but it was failing after successful validation with a property of undefined error.

Expected behavior
It shouldn't try to validate an optional absent claim

Provider logs

2020-07-08T10:26:04.356+01:00 | 2020-07-08T09:26:04.355Z provider:auth Successfully validated token!
-- | --
  | 2020-07-08T10:26:04.356+01:00 | 2020-07-08T09:26:04.356Z provider:auth Cannot read property 'family_code' of undefined

Ltijs version

  • Version 3.6.3

NodeJS version

  • Version 13

Platform used

  • Custom

Additional context
I'm a noob at understanding this stuff so I hope I got everything right. Thank you so much for this library.

Invalid token Error: ISS_CLAIM_DOES_NOT_MATCH

Describe the bug
The lti tool opens in Canvas and shows INVALID TOKEN error message

Expected behavior
That the tool loads correctly

Provider logs
2020-08-24 15:57:38 default[prod] 2020-08-24T15:57:38.645Z provider:main Received idtoken for validation
2020-08-24 15:57:38 default[prod] 2020-08-24T15:57:38.645Z provider:auth Response state: c3dgv9m70xvuizihzphvdkcg4
2020-08-24 15:57:38 default[prod] 2020-08-24T15:57:38.645Z provider:auth Attempting to validate iss claim
2020-08-24 15:57:38 default[prod] 2020-08-24T15:57:38.645Z provider:auth Request Iss claim: undefined
2020-08-24 15:57:38 default[prod] 2020-08-24T15:57:38.645Z provider:auth Response Iss claim: https://canvas.instructure.com
2020-08-24 15:57:38 default[prod] 2020-08-24T15:57:38.646Z provider:auth Error: ISS_CLAIM_DOES_NOT_MATCH

Ltijs version

  • Version 5.0.2

NodeJS version

  • Version 12

Platform used

  • Canvas

Update moodle's lti plugin to support JWK keyset

I've modified moodle's lti plugin to support JWK keyset, which makes it a lot easier to setup an external tool. I'm not familiar with moodle's contribution politics but i'm looking into it to publish this change. There's an issue about it open in the moodle's issue tracker.

The modified plugin can be found here: Basiclti4moodle

Shared OAuth secret authentication

First of all this is not really an issue but more like general question:
The tool consumer I have to use does not provide the platform registration data that is needed in LTIJS' registerPlatform method. That is, there is no such data as authenticationEndpoint you describe in your tutorial with Moodle as a tool consumer.

In my tool consumer there is only a shared OAuth secret that has to be stored at the tool provider to be used for verifying launch requests. The only config data that is set at the tool consumer is therefore this data: Name, Description, Launch URL, OAuth consumer key, and OAuth secret. My question is, how can I configure/register this tool consumer platform with LTIJS using the shared OAuth secret?

Thanks in advance and best regards
Matthias

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.