Async / Service-Key Grading
Make sure you've read about authenticating API requests and accessing the API asynchronously before proceeding to the guide below.
The AGS and NRPS endpoints accept both the ltik based and service key based API authentication methods.
Due to the nature of LTI®, it's recommended to always utilize the LTI® services synchronously, within the context of an LTI® launch. For most use cases it should be enough and a lot easier to trigger periodic tasks when someone launches into your tool. However, some scenarios make synchronous calls impractical: a nightly job that pushes every student's progress to the LMS gradebook, a webhook from an external grading service that fires hours after the original launch, a roster refresh on a schedule, or a backfill of grades after fixing a scoring bug. For these cases, the ltik token is not suitable, because it expires 24 hours after the launch in which it was issued.
LTIAAS exposes a long-lived alternative called the serviceKey, which is issued during any LTI® launch that has access to the Assignment and Grades or Names and Roles Provisioning services. The serviceKey does not expire, can be persisted in your application's database, and can be used outside of an LTI® launch via the service key based authentication method. This guide walks through the end-to-end pattern for using the serviceKey to submit grades asynchronously: capturing it at launch time, scheduling background jobs, swapping the authentication header, batching score submissions, and surfacing operational health.
Capture the serviceKey on every launch
Step 1 of 6When a user launches into your tool and the launch context has access to at least one of the Assignment and Grades or Names and Roles Provisioning services, the ID Token returned by /api/idtoken includes a services.serviceKey field. Your application's back-end should capture this value during the launch and persist it in your own database, keyed by the (platformId, contextId, resourceLinkId) triple that identifies the launch context.
// Building Ltik based API authentication header
const authorizationHeader = `LTIK-AUTH-V2 ${API_KEY}:${LTIK}`
const headers = { Authorization: authorizationHeader }
// Making /api/idtoken GET request
const idtoken = await requests.get(
'https://your.ltiaas.com/api/idtoken',
{ headers }
)
const serviceKey = idtoken['services']['serviceKey']
// Persist the serviceKey alongside the context that originated it.
await storeServiceKeyInDatabase({
platformId: idtoken['platform']['id'],
contextId: idtoken['launch']['context']['id'],
resourceLinkId: idtoken['launch']['resourceLink']['id'],
serviceKey
})
The serviceKey does not expire; however, due to the nature of LTI®, the information stored within a certain serviceKey might become inaccurate at some point. For this reason it's recommended to update the serviceKey for a certain context on every launch by overwriting the stored value. This guarantees that your application always has the freshest reference to the launch context.
The serviceKey grants API access to its associated context indefinitely, so it should be encrypted at rest. It's also useful to store the (platformId, contextId, resourceLinkId) triple alongside activity and grading information in your application's own database, so that background jobs can find the right serviceKey for the work they need to do.
You can read more about the structure and lifecycle of the serviceKey in the Accessing the API asynchronously guide.
What's next
- Grade Passback flow — the synchronous version of this guide. Read it first to understand the per-user score envelope, then return here for the asynchronous pattern.
- Names & Roles flow — the same
serviceKeytechnique works for refreshing class rosters from a cron job, outside of a live launch. - Accessing the API asynchronously — the underlying authentication method this flow is built on.
