NAV
javascript

Introduction

Welcome to the Intellischool Data Platform (IDaP) API docs. You can use the IDaP API to interact with data stored on the IDaP, and (depending on the tenant) write back changes from the cloud to on-premises applications and databases.

This documentation currently includes examples in JavaScript only, but we'll be adding more examples shortly. As the IDaP API is GraphQL-based, the actual execution of tasks is similar across all programming languages.

About the IDaP

The Intellischool Data Platform (IDaP) is a distributed, scalable data platform, capable of providing both transactional and warehouse data storage. Also incorporated into the IDaP are a number of back-end functions aligned with Intellischool's front-end products.

Albitros, Dextyr and Wylba are front-end products that run on top of the IDaP, providing a graphical interface over the exact same API documented herein. With minimal exceptions, if you can achieve something in Albitros, Dextyr or Wylba, you can also achieve it via the IDaP API.

Accessing the API

In order to access the IDaP API, you must either have:

Any IDaP tenant is automatically licensed to use the IDaP API. Likewise, third-party integrators that wish to use the IDaP API are also able to do so at no cost.

You may obtain an API key by either:

Authentication

The IDaP supports three primary modes of authentication:

  1. Basic authentication, for integrations interacting with a single tenant's data;
  2. OAuth 2.0 authentication, for multi-tenant integrations; or
  3. Learning Tools Interoperability authentication.

Learning Tools Interoperability authentication, as well as other LTI principles, are covered in the Learning Tools Interoperability section of these docs.

Basic auth

To generate a Basic token:

const credentials = "<api_key>:<api_secret>";
const token = new Buffer(credentials).toString('base64');

const authentication = `Basic ${token}`;

You can now pass authentication in the Authorization header when making API calls.

Basic authentication is supported in situations where a single tenant is solely accessing their own data. API keys issued for Basic authentication are limited to interacting with data within the tenant for which the key was generated.

OAuth 2.0

If you're developing an integration that will be used by more than one IDaP tenant, you can use OAuth 2.0 to gain access to an app.

To get started, you will need to register your application through intellischool.dev. At the end of this process, you will receive a client_id and client_secret.

If you're developing a web app or a back-end web server app, you should select the Auth Code grant type. If you're developing a native app (such as a desktop or mobile app), you should choose the Auth Code with PKCE grant type.

At the successful completion of an OAuth flow you will be granted an access token to connect to an IDaP tenancy. If the authorizing user has access to more than one IDaP tenant, they will be prompted to select which tenant your application should be granted access to.

Once the user has completed the OAuth flow you can then use the granted token to interact with the appropriate API endpoint.

1. Authorize your app

Your app should direct users to the following URL:

GET https://core.intellischool.net/connect/authorize
    ?response_type=code
    &client_id=YOURCLIENTID
    &redirect_uri=YOURREDIRECTURI
    &scope=openid community.read
    &state=123

Your app should initiate the OAuth flow by directing users to the consent endpoint. The table denotes the parameters that should be supplied, noting that the code_challenge and code_challenge_method fields are applicable to an Auth Code with PKCE flow only:

Parameter Description
response_type This value should always be code
client_id The client_id issued when you created your app
scope Permissions to request (see below)
redirect_uri The URL on your server to redirect back to
state Optional: A unique string to be passed back on completion (see below)
code_challenge PKCE only: The code challenge your app has generated (see below)
code_challenge_method PKCE only: This value should always be S256

OAuth scopes

A scope in the context of IDaP authorization maps directly back to IDaP roles. A complete list of roles is available in the Scopes section of this documentation. For example, the finance.read role equates to the finance.read OAuth scope.

Additionally, your app may request the following scopes:

Redirect URIs

All redirect URIs must start with the https scheme, with the exception of localhost.

State

The state parameter, aside from being used to convey state information back to your app, should also be used to avoid forgery attacks. Pass in a value that is unique to the authorization flow for your app. It will be passed back after the user completes authorization.

Generate a code challenge:

const base64url = require('base64url');
const hash = require('crypto').createHash('sha256');

let code_verifier = 'myRAnd0m5tr1nGTh4tisB3twe3n43aNd128ch4rAct3R5L0nG'

let code_challenge = base64url(hash.update(code_verifier).digest('hex'))

Code challenge (PKCE only)

Before starting the authorization flow, your app must generate a code verifier. This is a random string between 43 and 128 characters long, that consists of the characters A-Z, a-z, 0-9 and the punctuation -._~ (hypen, period, underscore, and tilde).

The code challenge is created by performing a SHA256 hash on the code verifier, and then Base64 URL encoding the hash.

2. Receive your code

If the user authorizes your app, the IDaP will redirect them back to your specified redirect_uri with the following query parameters:

Parameter Description
code A temporary code that may only be exchanged once, and expires 5 minutes after issuance.
state If you provided a value, the IDaP will return this value to you in the state parameter. It is best practice to check that the parameter value matches what your application sent - if it does not, your request may have been subject to an attack by a third party and you should abort the flow.

If any errors occur or the user denies the request, the IDaP will redirect the user back to your redirect_uri with an error parameter describing the problem.

3. Exchange the code

Exchange your verification code for an access token:

const fetch = require('node-fetch');
const credentials = "<client_id>:<client_secret>";
const token = new Buffer(credentials).toString('base64');

let response = await fetch('https://core.intellischool.net/connect/token',{
  method: 'post',
  headers: { Authorization: `Basic ${credentials}`},
  body: 'grant_type=authorization_code&code=CODE&redirect_uri=URI'
})
.then(res => res.json())

You can now exchange the verification code for an access token. You will also receive an identity token if you've requested the openid, profile or email scopes, and a refresh token if you've requested the offline_access scope.

The exchange URL is:

POST https://core.intellischool.net/connect/token

The request requires an authorization header containing your app's API key and secret:

Authorization: Basic + base64encode(client_id + ':' + client_secret)

You will need to provide the following parameters in the body of your POST request:

Parameter Description
grant_type Always authorization_code
code The authorization code you received from the consent endpoint
redirect_uri The same redirect URI you provided to the consent endpoint
client_id PKCE only: the client ID of your app
code_verifier PKCE only: the code verifier that you created during the authorization step

4. Receive your tokens

An example access token:

{
  "nbf": 1589543023,
  "exp": 1589544823,
  "iss": "https://core.intellischool.net/auth",
  "aud": "YOUR_CLIENT_ID",
  "sub": "YOUR_CLIENT_ID",
  "intellischool_tenant": "TENANT_ID",
  "intellischool_region": "vic.intellischool.com.au",
  "jti": "026609f2-4a23-4eae-a3a3-206452ddc4e2",
  "authentication_event_id": "001dc026-5d86-4869-98a6-624bef340a35",
  "scope": [
    "openid",
    "profile",
    "offline_access",
    "community.read"
  ]
}

The connect endpoint will verify all the parameters in the request, ensuring the code hasn't expired and that the client ID and secret match. If everything passes verification, it will generate your tokens and return them in the response.

The response will contain the following parameters:

Parameter Description
access_token The token you should use to call the IDaP API
id_token The token containing user identity details (if an OpenID scope was requested)
expires_in The amount of seconds until your access_token expires
token_type Always Bearer
refresh_token The token you can use to refresh the access_token once it has expired (if your app requested the offline_access scope)

5. Get the API endpoint

Get the tenant ID and region:

const jose = require('jose');

const access_token = jose.JWT.decode(request.access_token);

const { tenant, region } = access_token;

const api_endpoint = `https://api.${region}/v1/graphql`;

The IDaP is a multi-tenant platform, with data stored in various regions around the world. Because the data that the IDaP is storing is often quite sensitive, the jurisdictions in which our tenants operate regularly mandate that data must be stored at rest within that jurisdiction's borders.

To ensure that our tenants' data remains within their jurisdiction as much as is possible, there is a different API endpoint for each region.

To get the API endpoint for the tenant, extract the intellischool_tenant and intellischool_region claims from the returned access_token. Then apply the following:

https://api.(region)/v1/graphql

For example, if the tenant's region is vic.intellischool.com.au, the API endpoint would be:

https://api.vic.intellischool.com.au/v1/graphql

6. Interacting with the API

You now have everything you need to interact with the API. It is your responsibility to ensure that the issued tokens are kept safe.

More information on interacting with the API can be found in the GraphQL section on this page.

7. Refreshing access tokens

Refresh your access token:

const fetch = require('node-fetch');
const credentials = "<client_id>:<client_secret>";
const token = new Buffer(credentials).toString('base64');

let response = await fetch('https://core.intellischool.net/connect/token',{
  method: 'post',
  headers: { Authorization: `Basic ${credentials}`},
  body: 'grant_type=refresh_token&refresh_token=REFRESHTOKEN'
})
.then(res => res.json())

Access tokens expire after 30 minutes. If your app requested the offline_access scope, you will need to refresh your access token once it has expired to continue interacting with the IDaP API.

To refresh your access token, you will need to POST your refresh_token to the token endpoint: POST https://core.intellischool.net/connect/token

The request has the same authorization requirements as step 4, being a Basic token containing your Base-64 encoded client ID and client secret.

In the request body, include the following parameters:

Parameter Description
grant_type Always refresh_token when refreshing an existing token
refresh_token The refresh token provided during the previous token grant

Each time you perform a token refresh, you should save the new refresh token returned in the response. If, for some reason, your app doesn't receive the response, you can retry your existing token for a grace period of 30 minutes.

8. Revoking tokens

Revoke a token:

const fetch = require('node-fetch');
const credentials = "<client_id>:<client_secret>";
const token = new Buffer(credentials).toString('base64');

let response = await fetch('https://core.intellischool.net/connect/revocation',{
  method: 'post',
  headers: { Authorization: `Basic ${credentials}`},
  body: 'token=REFRESHTOKEN'
})
.then(res => res.json())

You can revoke a refresh token and remove all associations with your app by making a request to the revocation endpoint.

As with all interactions between your app and the connect endpoints, you will need to include your client ID and client secret as a Basic token in the Authorization header.

To revoke a token, POST to the revocation endpoint: POST https://core.intellischool.net/connect/revocation

You must include your most recent refresh_token in the body of the POST request, as the token parameter.

A successful revocation request will return a HTTP 200 OK response with an empty body.

Scopes

The term scope can be interchanged with the term role in terms of IDaP front-end products. Where a front-end product refers to a role, it is the same as an API scope.

External application providers can access most API scopes. However, some scopes are restricted due to the nature of data available, or to protect Intellischool's intellectual property. If you would like to access a restricted scope, please contact Developer Support.

In order for a scope to become available for an external app to consume, the IDaP tenant must have purchased the relevant module. Scopes in the table below are grouped by the module required to use them.

Scope types

A scope may be one of three types:

  1. admin - grants access to all features and configuration options for that particular module;
  2. write - grants access to view and make changes to all data within the scope; and
  3. read - grants access to view data within the scope, but not make any changes.

The exceptions to these are the:

LTI / LIS scopes

The IDaP supports all of the roles specified in the Learning Tools Interoperability / Learning Information Services specifications. These roles are mapped to internal IDaP roles automatically.

LTI/LIS roles are mapped in the context of the application being launched. For example, if launching into the Scheduler app, a LTI/LIS role of person#Administrator would be assigned a scheduler.admin IDaP role.

If a tenant wishes to customise the LTI/LIS role mappings, they can do so via the Settings page in Albitros, Dextyr or Wylba, or the equivalent whitelabelled product.

LTI/LIS roles are never mapped to the superuser role unless overridden by a tenant.

Available scopes

Module Restricted Scopes
Admissions No admissions.admin, admissions.read, admissions.write
Analytics Yes analytics.admin, analytics.creator, analytics.self, plus others
Attendance No attendance.admin, attendance.read, attendance.write
Community No community.admin, community.read, community.write
CRM No crm.admin, crm.read, crm.write
Events & Ticketing No events.admin, events.read, events.write
Finance Hub No finance.admin, finance.read, finance.write
Forms No forms.admin, forms.read, forms.write
Integration Hub No sync.admin, sync.read, sync.write
Launchpad No launchpad.admin, launchpad.read, launchpad.write
Medical Centre Yes medical.admin, medical.read, medical.write
Scheduler No scheduler.admin, scheduler.read, scheduler.write
Visitor Manager No visitor.admin, visitor.read, visitor.write
Voice No voice.admin, voice.read, voice.write

GraphQL

The primary IDaP API is a GraphQL API. If you're new to GraphQL (GQL), there is a great introduction here.

Intellischool chose to use GraphQL for the primary API due to its highly flexible nature. It's an adaptive standard, which facilitates our philosophy of continual improvement without causing a headache for our integrators when we add new fields or types to the API.

In order to connect to any GraphQL API, it's best practice to use a GQL library. These libraries have numerous features built-in that will make integrating your application simpler.

We use the Apollo Client internally, and recommend that our integrators do so as well. It's compatible with any JavaScript environment (including Node.js, React, Angular and others), and also has native clients for iOS and Android.

If you're not developing in JavaScript or for iOS/Android, there's an official list of GraphQL clients that you can refer to. Any of them should work with the IDaP API.

1. Configure your GQL client

Create a new GraphQL client:

/* This example assumes you are using Node.js
   For client-side implementations, refer to the Apollo docs */
const { ApolloClient  } = require('apollo-client');
const { InMemoryCache } = require('apollo-cache-inmemory');
const { createHttpLink } = require('apollo-link-http');
const fetch = require('node-fetch');

const link = createHttpLink({
  `https://api.${region}/v1/graphql`,
  fetch,
  headers: {
    'Authorization': 'Bearer YOURTOKEN'
    'x-intellischool-tenant': 'YOURTENANTID',
    'x-intellischool-app-id': 'YOURCLIENTID',
    'x-intelliscchool-user-id': 'USERID'
  }
})

const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
})

Most GQL clients require that you configure the connection to the GQL API separately and prior to making any calls to the API itself.

When configuring your client, there are five headers that should be included in each of your requests.

Header Basic value OAuth value
Authorization Base-64 encoded API key and secret Access token granted earlier
x-intellischool-tenant Tenant ID provided tenant claim retrieved from access token
x-intellischool-app-id API key Application's client ID
x-intellischool-role Required role Required scope
x-intellischool-user-id Not required User ID if acting on behalf of user

The x-intellischool-user-id header can be omitted if you are using Basic authentication, or if your application is not acting on behalf of a specific user.

2. Query the API

An example querying the students type:

const gql = require('graphql-tag');

await client.query({
  query: gql`
    query get_students($status: enum_StudentStatus_enum!) {
      students(where: {
        status: {_eq: $status}
      }) {
        stu_uuid
        current_year_level
        entity {
          entity_uuid
          given_name
          family_name
        }
      }
    }
  `,
  variables: {
    status: "current"
  }
})
.then(result => console.log(result))

Once you have your client configured, you can query the API. The example here shows a simple GQL query that retrieves current the tenant's current students.

The query also retrieves the associated entity record for the student record. The entity record contains the student's personal information, such as name, date of birth, and residential details, whereas the student record contains their current enrolment details, such as year level, entry date, and exit date.

The IDaP API is large; far too large to fully document here. The best way to learn how to interact with it is by using the API explorer. The explorer provides contextual help in the Documentation Explorer pane, explaining the purpose of each component.

3. Mutate some data

An example mutation of the students type:

const gql = require('graphql-tag');

await client.mutate({
  mutation: gql`
    mutation mark_student_as_leaving(
      $exit_date: Date!, 
      $stu_uuid: uuid!
    ) {
      update_students(
        where: {
          stu_uuid: {_eq: $stu_uuid} },
        _set: {
          exit_date: $exit_date }
      ) {
        affected_rows
      }
    }
  `,
  variables: {
    "exit_date": "2020-08-30T05:30:00+09:30",
    "stu_uuid": "dbeb67f5-b83f-44e0-ad47-7b55d0af3e7b"
  }
})
.then(result => console.log(result))

A GraphQL mutation is effectively an INSERT, DELETE or UPDATE statement on the underlying IDaP. Depending on the roles/scopes that your application has access to, you may be able to perform mutations to update data.

As with queries, the best way to learn about how to mutate data via the API is by using the API explorer.

Learning Tools Interoperability

The Intellischool Data Platform (IDaP) and (by extension) the products built on top of the platform - namely Albitros, Dextyr, and Wylba - are Learning Tools Interoperability (LTI) v.1.3.0 compliant.

An authorised LTI-compatible Platform can link to and launch into IDaP tools, effectively providing Single Sign-On. Likewise, the IDaP can launch LTI-compatible Tools through some products.

Platforms and tools

As the components of the IDaP vary significantly in their purpose, their respective software service types in terms of the LTI specification vary. In some cases a component may be able to be used as both a Platform or Tool.

For clarity, these roles can be summarised as follows:

Platform Tool
Launchpad Analytics, Forms, Parent-Teacher Interviews (component of Scheduler), Payments (component of Finance Hub)

Messages and services

The IDaP supports two types of LTI integration methods:

An example of an LTI message in terms of the IDaP is an LTI Launch link. This facilitates single sign-on for a resource that is part of a tool when a user clicks on the link in a supported platform.

An example of an LTI service is a notification from the IDaP’s Analytics component to a third-party platform. This happens between two servers and does not involve a user’s browser.

Deployments

Platform deployments

Where the IDaP is acting as a LTI platform (or identity provider), the IDaP requires at least two pieces of information, being the:

Optionally, the following can also be provided:

Where the type of tool being integrated is not supplied, the IDaP will limit the LTI integration to messages only. Services are supported only for known tool integrations.

Tool deployments

Deployment of an LTI integration with an IDaP component requires at least two pieces of information, being the:

  1. URI namespace of the platform (e.g. https://lms.school.edu); and the
  2. Type of platform;

Optionally a public_key supplied by the platform can also be provided. If not provided, the IDaP will generate a key pair to use for the integration.

The URI namespace of the platform must start with https. As per the LTI specification: LTI v1.3 requires the use of HTTPS (using TLS) for both messages and services. Additionally, implementers MUST use HTTPS for all URLs to resources included in messages and services (for example, URLs to service endpoints, or to static content like images and thumbnails).

Once supplied, the IDaP will return a deployment_id value. If a public_key was not supplied, the IDaP will generate and return a new private_key for the Platform to use when signing tokens.

LTI Launch

This section specifies the requirements for linking to an IDaP resource, using a third-party Platform as the identity provider.

Claims

An example LTI Launch token:

{
  "alg": "RS256",
  "typ": "JWT"
}
.
{
  "iss": "https://lms.school.edu",
  "sub": "4e4928b7-df3e-4501-a5d0-f2cc54b3beef",
  "aud": "https://core.intellischool.net/auth/lti",
  "iat": 1234567890,
  "exp": 1234567890,
  "name": "Ms Jane Marie Doe",
  "given_name": "Jane",
  "family_name": "Doe",
  "middle_name": "Marie",
  "email": "[email protected]",
  "picture": "https://lms.school.edu/jane.jpg",
  "locale": "en-US",
  "https://purl.imsglobal.org/spec/lti/claim/deployment_id":
    "a94f9cf6-80cf-4a61-85ca-2d0d4ea63403",
  "https://purl.imsglobal.org/spec/lti/claim/message_type": 
    "LtiResourceLinkRequest",
  "https://purl.imsglobal.org/spec/lti/claim/version":
    "1.3.0",
  "https://purl.imsglobal.org/spec/lti/claim/lis": {
    "person_sourcedId": "person_id_in_external_system"
  },
  "https://purl.imsglobal.org/spec/lti/claim/roles": [
    "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Student"
  ],
  "https://purl.imsglobal.org/spec/lti/claim/resource_link": {
    "id": "ec123cba-0aa2-4712-b9df-87cd75ea994d"
  },
  "https://purl.imsglobal.org/spec/lti/claim/target_link_uri":
    "https://analytics.intellischool.cloud/dashboard/123456",
  "https://purl.imsglobal.org/spec/lti/claim/launch_presentation": {
    "document_target": "iframe"
  }
}
. // JWT SIGNATURE

Compulsory claims

Any LTI link or launch request requires, at minimum, the following claim in the token header:

Additionally, the following claims must always be present in the payload:

Optional claims

The following claims may be optionally included in a token’s payload:

Subject claims

An example of an UUID subject:

{ 
  // Other claims
  "sub": "eb4f50b5-386f-4cf0-b0c2-2b55205e8ea4",
  // More claims
}

An example of an e-mail subject:

{
  // Other claims
  "sub": "[email protected]",
  // More claims
}

An example of an external identifier subject:

{
  // Other claims
  "sub": "AB123456789",
  // More claims
}

The IDaP supports a number of different identifiers when matching an LTI entity with a known entity. By default, the sub claim can be populated with (in order of preference):

  1. An universally unique identifier, including dashes, including (in order of speed):
    1. An IDaP user_uuid;
    2. An IDaP entity_uuid, student_uuid or staff_uuid; or
    3. An external UUID populated in the ext_id field of the entity, student or staff tables;
  2. An e-mail address, that is unique to an entity in the tenant; or
  3. An external ID of any type, populated in the ext_id field of the entity, student or staff tables.

When the sub claim is an e-mail address or external ID, the IDaP will attempt to limit the search scope of the identifier to the student or staff tables based on the https://purl.imsglobal.org/lti/claim/roles claim. For example, if the token includes staff role, it will limit the identifier search to the staff table. Similarly, if the token includes a student role, it will limit the identifier search to the student table.

Depending on the tenant's LTI configuration, the IDaP may provision users on-demand based on the information provided by an authorized LTI Platform. There are three possible configurations for on-demand provisioning:

  1. Enabled - the IDaP will automatically provision new user accounts for entities that can be matched to the sub claim of the LTI token;
  2. Disabled - the IDaP will reject login requests if the sub claim cannot be matched to an existing provisioned user; or
  3. Enabled with unknown entity provisioning (not recommended) - the IDaP will automatically provision new user accounts for sub claims that cannot be matched to an existing user, regardless of whether or not a matching entity can be found. Use of this setting is not recommended, and is offered for compatibility reasons only.

Signing the token

The IDaP expects LTI tokens to be signed by the platform’s private key using the RS256 algorithm, as recommended by the IMS Security Framework:

The alg value SHOULD be the default of RS256 ... Use of algorithms other [than] RS256 will limit interoperability.

However, if a Platform chooses to sign a token with the RS384 or RS512 algorithms the token will also be validated. Any other algorithms will result in the token being rejected.

If a public key was not supplied to the IDaP during configuration, the IDaP automatically generates a new key pair and returns the private key for configuration in the platform.

LTI endpoint

An example LTI Launch request:

POST https://core.intellischool.net/auth/lti
     ?id_token=your.lti-compliant-token

LTI Launch resources are provided via an HTTPS URL. When an LTI-compliant platform presents a user with an LTI Launch resource, the IDaP expects either an id_token or JWT parameter to be provided. As per the LTI specification, only the POST method is supported.

Error handling

When the IDaP is acting as a LTI Tool (i.e. identity consumer), LTI tokens may be rejected for some reason. Depending on the type of LTI request, the IDaP will feed back error information in different ways.

If your message includes a return_url in the launch presentation claim, users will be redirected back to the nominated return URL with an error and code query parameter.

An example JSON error response:

{
  "short": "ERROR_SHORT_REASON",
  "code": "A123"
}

If your message does not include a return_url, the IDaP will return an application/json document with the error details.

The LTI standard does not mandate how a LTI Platform should handle errors from LTI Tools, however we recommend including basic error handling in your LTI deployment.

Platform authentication

An example token with the IDaP as a Platform:

{
  "alg": "RS256",
  "typ": "JWT"
}
.
{
  "iss": "https://launchpad.school.edu",
  "sub": "bc9fe146-6883-403e-b1d6-5b1a28c5d29d",
  "aud": "https//lti-tool.com/",
  "iat": 1234567890,
  "exp": 1234567890,
  "nonce": "f69da4b8-a013-4715-a4fe-adc45a5f7372",
  "name": "Ms Jane Marie Doe",
  "given_name": "Jane",
  "family_name": "Doe",
  "middle_name": "Marie",
  "email": "[email protected]",
  "picture": "https://lms.school.edu/jane.jpg",
  "locale": "en-US",
  "https://purl.imsglobal.org/spec/lti/claim/deployment_id":
    "a05e369b-7448-49f5-9a7f-e45399f6978d",
  "https://purl.imsglobal.org/spec/lti/claim/message_type": 
    "LtiResourceLinkRequest",
  "https://purl.imsglobal.org/spec/lti/claim/version":
    "1.3.0",
  "https://purl.imsglobal.org/spec/lti/claim/lis": {
    "person_sourcedId": "school.edu:e3158a0b-7f36-41c1-a5b3-6970174f7bb9"
  },
  "https://purl.imsglobal.org/spec/lti/claim/roles": [
    "http://purl.imsglobal.org/vocab/lis/v2/institution/person#Student"
  ],
  "https://purl.imsglobal.org/spec/lti/claim/resource_link": {
    "id": "376848a1-fb7c-4d9a-82a6-97f723c1935d"
  },
  "https://purl.imsglobal.org/spec/lti/claim/target_link_uri":
    "https://lti-tool.com/path/to/resource",
  "https://purl.imsglobal.org/spec/lti/claim/launch_presentation": {
    "document_target": "iframe"
  }
}
. // JWT SIGNATURE

When the IDaP is acting as a LTI Platform (i.e. an identity provider), it will issue LTI tokens as per the specification. Tokens include all of the required message claims, in addition to:

Tokens issued by the IDaP are signed using a private key and RS256 encryption. The public key will be provided upon configuring the IDaP for the Tool to which LTI tokens are to be issued.

Troubleshooting LTI

The IDaP provides error codes that help you track down why an identity token isn’t being processed as expected. The table below summarises these codes for your reference:

Error code Typical cause of error
A480 An HTTP verb other than POST was used to make the request, OR the body of the POST request was empty.
A481A The token was not correctly passed to the authentication endpoint in the body of a POST request. Ensure that the token is present in either the id_token or JWT fields, and that the form is submitted with a MIME type of either application/x-www-form-urlencoded OR application/json.
A481B The IDaP could not interpret the contents of the JWT provided. Ensure that the JWT meets the format requirements. Consider using an open source library to build your tokens if you are not already doing so.
A481C The provided token was missing one or more required claims. Ensure that all LTI fields are prefixed with https://purl.imsglobal.org/spec/lti/claim/. Refer to the Compulsory claims section above.
A482 The token has been issued with a deployment_id that is unknown to the IDaP. Ensure that LTI is appropriately configured in the IDaP tenancy.
A483 The token failed validation. Ensure that it was signed with the correct private key, the algorithm is valid (either RS256, RS384 or RS512) and that the required claims match their expected values as defined in the Compulsory claims section of this document.
A484 The user could not be found, and the tenant's LTI settings prevent new users from being provisioned on-demand. Check your sub claim and make sure it can be resolved to a unique identifier.
A485A There was an error while retrieving the user details by UUID. Check the error message for a resolution hint.
A485B There was an error while retrieving the user details by e-mail address. Check the error message for a resolution hint.
A488 The tenant is not licensed to use the application being launched into.

Getting help

If you need help getting started, or something isn't behaving as you expected, please let us know! You can reach Developer Support at [email protected].

Custom development

Intellischool can assist with the development of custom integrations with and extensions to the IDaP. If you would like to discuss engaging our team on a professional basis, please contact Developer Support at [email protected].