All notable changes to this project will be documented in this file.
v0.2.0
Ltix 0.2 has 60 breaking changes. Upgrading to 0.2 describes each one and what to change in your tool.
Security
- Ltix rejects a launch whose ID token is for a different login or a different registration than its login request.
- Ltix rejects an ID token an hour after its
iat, and a token withiatornbfin the future. - Ltix rejects an ID token with an untrusted audience in an
audlist, with critical header extensions, or with a missing or malformediss,iat, orexp. - Your storage adapter records a nonce only after Ltix has verified the ID token.
- Ltix sends platform requests only over HTTPS and only to public addresses. It follows a redirect or pagination link only to the scheme, host, and port of the first request.
- A request configured to skip TLS certificate verification returns an error.
Ltix.JWT.KeySetfetches each key set URL at most once every 30 seconds.inspectoutput omits private keys and access tokens.
Storage adapter and keys
- Your storage adapter signs each JWT through the
key_idandsigncallbacks.Ltix.Registrationhas notool_jwkfield. - Storage adapter callbacks receive your registration struct and the options of the call. The registration lookup receives the platform's deployment ID.
- A failing storage adapter callback returns
StorageError. Ltix.JWKis a PEM-based struct that replacesJOSE.JWK.Ltix.JWK.new/1builds a key from a PEM, a DER, a JWK map, or a public key alone.Ltix.JWT.KeySetis a process your application starts. It replaces the key set caches and the:jwks_cachesetting.Ltix.Registration,Ltix.JWK, andLtix.Deploymentvalidate their fields strictly and reportInvalidField. Registration URLs must be HTTPS.Ltix.OAuthandLtix.Testaccept any struct that implementsLtix.RegisterableorLtix.Deployable.
Launch claims and roles
- Ltix checks the type of each claim, reports every missing or invalid claim by its name in the token, and omits a malformed optional claim.
- Claim parsers can be modules that implement
Ltix.LaunchClaims.Parser, and can override the built-in parsers. A failing claim parser returnsInvalidClaim. - Ltix tries custom role parsers in order from the longest prefix to the shortest.
Role.administrator?/1checks the institution role.Role.context_administrator?/1checks the context role.Role.to_uri!/1returns the URI of any role.- The parser options are named
claim_parsersandrole_parsersin every function and in the application config.
Advantage services
Ltix.OAuth.authenticate/2authenticates a custom Advantage service from a launch context.Client.request/3andClient.request_pages/3send its requests.Ltix.OAuth.Clienthas atokenfield with anAccessToken. Itsaccess_token,expires_at, andscopesfields are removed.AccessToken.expired?/1,AccessToken.to_map/1,AccessToken.from_map/1, andClient.require_unexpired/1are added for caching and storing tokens.Client.refresh/1returns the client unchanged until its token has expired.- A client accepts a token with fewer scopes than requested. The
require_all_scopesoption returns an error when a scope is missing.ScopeMismatchlists the scopes a request needed. - Token requests include the deployment ID, and the
audienceof the registration when it has one. get_resultsandget_membersare renamed tolist_resultsandlist_members.stream_line_items,stream_results, andstream_membersstream a collection page by page.- List functions return
CollectionTooLargeabove 10,000 entries. - Grade operations accept an
endpointoption.AGSEndpoint.new/1andMembershipsEndpoint.new/1validate their URLs and scopes. delete_line_item/2takes the line item as aline_itemoption.- Scores are built from keyword lists or maps. Score, line item, and deep linking dates are
DateTimevalues. to_jsonis replaced byto_mapand JSON encoder protocol implementations for scores, line items, and content items. Grade results, members, and contexts haveto_maptoo.- Unrecognized member fields are in
Memberextensions. A malformed member returns an error. - Ltix parses
Linkheaders per RFC 8288, resolves relative next links, and stops paginating when a next link repeats a page.
Deep linking
build_response/3enforcesaccept_presentation_document_targetsandaccept_media_types, and reports every constraint violation with the index of the item.- Content item options accept maps or keyword lists, including nested fields. Unknown options and extensions that would replace standard fields are rejected.
- A resource link accepts a grade service
LineItemas its line item. verify_deep_linking_responsereturnsSignatureInvalidfor an invalid or malformed token.
Errors and options
- Every fallible operation has a bang variant.
- Functions raise
InvalidOptionfor an unknown or invalid option. - A function that finds one error returns it. A function that finds several returns an error class struct with them in
errors. - HTTP 401 and 403 responses return
AccessDenied. A failed request returnsTransportErrorwith its URL and response headers. - Malformed tokens, token responses, and service responses return Ltix errors.
Ltix.Errors.status_code/1returns the Plug status code of any exception.- Abbreviated struct fields are spelled out, and module names use uppercase acronyms such as
LIS,AGS, andJSON.
Telemetry
- Ltix emits telemetry events for OIDC login and callback, key set fetches, OAuth token requests and refreshes, the grade service, the memberships service, and deep linking.
Testing
Ltix.Test.assert_storage_adapter!checks a storage adapter, including its signing callbacks.- Ltix calls the storage adapter in your test config.
setup_platform!/1takes:registrationand:deploymentfunctions that create the records in your storage. - Ltix sends each request in a test to the
Req.Teststub named after the module that makes it, such asLtix.GradeService.stub_get_membersis renamed tostub_list_members. launch_params/2andbuild_launch_context/2take the same options, default to the instructor role, and include a course context.- A test can launch from several test platforms.
Ltix.Testcompiles without the optional Plug dependency.
Dependencies
- Jason is an optional dependency for Elixir versions without the built-in
JSONmodule. - Ltix is tested on Elixir 1.17 through 1.20.
v0.1.0
Initial release with support for LTI 1.3 and LTI Advantage features:
- LTI 1.3 Core: OIDC launch flow, launch claim parsing, JWT verification
- Assignment and Grade Services 2.0
- Names and Role Provisioning Service 2.0
- Deep Linking 2.0