diff --git a/.gitignore b/.gitignore index 436b92873..3e8b6e34a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ npm-debug.log* yarn-debug.log* -yarn-error.log* \ No newline at end of file +yarn-error.log* + +.obsidian \ No newline at end of file diff --git a/docs/blackboard/caliper/caliper-intro.md b/docs/blackboard/caliper/caliper-intro.md deleted file mode 100644 index 8532f0612..000000000 --- a/docs/blackboard/caliper/caliper-intro.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -sidebar_position: 1 -published: "" -edited: "" ---- - -# Welcome to caliper! diff --git a/docs/blackboard/lti/1.1/welcome.md b/docs/blackboard/lti/1.1/welcome.md new file mode 100644 index 000000000..75540fce3 --- /dev/null +++ b/docs/blackboard/lti/1.1/welcome.md @@ -0,0 +1 @@ +LTI 1.1 diff --git a/docs/blackboard/lti/1.3/ags/help.md b/docs/blackboard/lti/1.3/ags/help.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/blackboard/lti/sanctioned-lti-registration-deployment.md b/docs/blackboard/lti/1.3/best-practices.md similarity index 73% rename from docs/blackboard/lti/sanctioned-lti-registration-deployment.md rename to docs/blackboard/lti/1.3/best-practices.md index 7754b0dcf..13b15313e 100644 --- a/docs/blackboard/lti/sanctioned-lti-registration-deployment.md +++ b/docs/blackboard/lti/1.3/best-practices.md @@ -1,18 +1,22 @@ --- -title: Sanctioned LTI Registration and Deployment with Learn -id: lti-registration-deployment -categories: Standards -author: Mark Kauffman +title: Best practices and common issues +id: best-practices published: "" -edited: "" -sidebar_position: 3 +edited: "2024-09-04" +author: Mark Kauffman, Scott Hurrey --- -## Motivation +## Sanctioned method of deployment -At Anthology we want our clients to have the best possible experience with Learn and the products that are integrated with it. To that end we developed a central registration service on our developer portal for use by 3rd-party vendors that are LTI 1.3 Tool providers. Using the central registration service, the Tool provider can go through the complexities of Tool registration and get a Client ID. That Client ID is all our mutual clients need to deploy a Tool. When the Tool is deployed a Deployment ID is generated that the client then provides the Tool vendor. The Client ID and Deployment ID are included in all LTI 1.3 communication, giving the Tool everything needed to identify the client's LMS. Reference [LTI Registration and Deployment](./lti-registration-and-deployment.md). +### tl;dr -## Why Vendor Tool-registration Is Best +For LTI 1.3 only integrations the best client experience is given by a vendor when the vendor registers on the Anthology central registration portal and shares the client_id with the client. There are other processes that involve the vendor asking the client to register the LTI-1.3-only integration. While not ideal, that’s OK, as long as the integration is not using the associated REST API key/secret. + +### Motivation + +At Anthology we want our clients to have the best possible experience with Learn and the products that are integrated with it. To that end we developed a central registration service on our developer portal for use by 3rd-party vendors that are LTI 1.3 Tool providers. Using the central registration service, the Tool provider can go through the complexities of Tool registration and get a Client ID. That Client ID is all our mutual clients need to deploy a Tool. When the Tool is deployed a Deployment ID is generated that the client then provides the Tool vendor. The Client ID and Deployment ID are included in all LTI 1.3 communication, giving the Tool everything needed to identify the client's LMS. + +### Why Vendor Tool-registration Is Best Why do we only sanction vendor Tool registration? First, the vendor owns the Tool, hence it should be their responsibility to manage it. Second, there are about nine pieces of information to exchange during the registration process. Those are vendor specific settings, and the client doesn't need to be aware of any of those. Third, and especially important, should the vendor need to change any details about their Tool, if they own the registration, they can change it in a one-time action on their registration for all clients with negligible impact on our mutual clients. If the vendor has requested the client register the vendor Tool, then every client will need to make the changes on the central registration system. This latter option is error prone and likely to produce Tool downtime for our mutual clients. @@ -24,6 +28,22 @@ Hence, a Tool vendor can always design their system and processes so that our mu The bottom line is that having the vendor register their Tool(s) to get Client ID(s) and having our mutual clients simply deploy their Client ID in exchange for a Deployment is the best process. But, if a vendor believes that it’s necessary for clients to register an LTI Tool, then clients are free to do so, while knowing that said vendor can likely make the process easier and simpler. We ask that the vendor talk to us and consider improving their architecture and processes to make our mutual clients work easier on deployment. And again, for REST Applications or for LTI Applications using REST APIs, the client should never register except in the case that the client owns, hosts, and manages the REST Application on-premise. -## tl;dr +## Common issues -For LTI 1.3 only integrations the best client experience is given by a vendor when the vendor registers on the Anthology central registration portal and shares the client_id with the client. There are other processes that involve the vendor asking the client to register the LTI-1.3-only integration. While not ideal, that’s OK, as long as the integration is not using the associated REST API key/secret. +### Turn on all the switches + +We often hear about this message "The Tool Provider has been disabled by the System Administrator" The usual cause is that one of the 3 LTI switches is disabled. There are 3 places you need to enable LTI: (1) at the tool level, (2) at the course/organization level, and (3) at the LTI Global Properties level. Screenshots follow. **LAST, BUT NOT LEAST - Make certain you are enrolled in the course, as an instructor or student, before using the LTI placements you create in a course! Your launch will fail if you don't have a role in the course.** + +#### All the Switches + +1. Administrator Panel -> Tools & Utilities section -> Tools + +![1-LTIConfigAdminTools.png](/assets/img/turn-on-all-switches-1.png) + +2. In a Course/Organization, Start at the Left Nav Menu + +![2-LTIConfigCourseOrg.png](/assets/img/turn-on-all-switches-2.png) + +3. Administrator Panel -> Integrations section -> LTI Tool Providers -> Manage Global Properties + +![3-LTIConfigManageGlobal.png](/assets/img/turn-on-all-switches-3.png) diff --git a/docs/blackboard/lti/1.3/core/authentication.md b/docs/blackboard/lti/1.3/core/authentication.md new file mode 100644 index 000000000..2d99ea51f --- /dev/null +++ b/docs/blackboard/lti/1.3/core/authentication.md @@ -0,0 +1,81 @@ +--- +title: Authenticating using OIDC +id: oidc-auth +sidebar_position: 2 +published: "2024-09-04" +edited: "2024-09-04" +--- + +To complete the LTI message flow we need to perform an OIDC authentication step as seen here + +![image of the OIDC authentication part within the LTI workflow](/assets/img/lti-launch-sequence-oidc.png) + +## Overview + +When a user clicks on an LTI link within Learn, the Learn server receives a GET request from the browser with information about that LTI link. Once it loads the tool configuration associated with that link the first thing it does is initiate the OIDC Login request with a browser redirect to the registered OIDC Login URI provided by your tool when registering on the Developer Portal. The initial login request also passes some information along as query parameters. + +The data sent by Learn to the OIDC login endpoint of your tool is the following: + +- issuer +- login_hint - an opaque value to the tool that must be returned back +- target_link_uri - the URI configured by the tool for this LTI link +- lti_message_hint - an opaque value to the tool that must be returned back +- lti_deployment_id - this is optional, but Learn always sends it +- client_id - this is optional, but Learn always sends it +- lti_storage_target - for use if cookies aren't possible + +Once the request is received, your tool must then redirect to the registered OIDC Authentication Request URI provided by the Developer Portal (shown when the registration process was completed), including a Redirect URI (which must be pre-registered) and a state value, along with the other values passed in by the platform. The Redirect URI declares where the tool wants the subsequent LTI launch to go, and the state is what protects against CSRF. The state should be saved in a cookie, so the tool can verify that the initiator of the request is the same browser that sends the LTI message launch. If a cookie cannot work because of browser restrictions preventing setting of cookies by 3rd parties in iframes, then another option must be pursued such as lti_storage_target. + +:::caution Redirect URI +Make sure that the Redirect URI is encoded using URLEncode before redirecting to the OIDC endpoint of the Developer Portal. Failure to encode that value could result on broken workflows +::: + +The fields the tool must send on the redirect to the Developer Portal are: + +- response_type=id_token +- scope=open_id +- login_hint - received as a parameter on the login request from Learn +- lti_message_hint - received as a parameter on the login request from Learn +- state - a random value generated by your tool to prevent CRSF attacks +- nonce - a random value generated by your tool to prevent duplicate requests +- redirect_uri - a pre-registered URL of your tool where the LTI POST with the data will be sent **(MUST BE ENCODED)** +- client_id - The Client ID (or Application ID) of your tool + +:::danger login_hint and lti_message_hint values +The values for the `login_hint` and `lti_message_hint` must be sent to the Developer Portal on the redirect **unaltered** since those contain information critical for the workflow and are verified in subsequent calls +::: + +## Sample code + +Below you can find sample code that outline how the OIDC redirect can be performed + +#### NodeJS + +```node +exports.oidcLogin = function(req, res) { + const state = uuid.v4(); // save this locally, such as in a cookie; optional in the OIDC spec + const nonce = uuid.v4(); // Used to prevent playback + const client = // You'll need to determine the client ID for this request from parameters on the request + const redirectUri = // Get the Redirect URI for this client + const oidcAuthUrl = // The URL you were given for this client when you registered your application + + let url = + oidcAuthUrl + + "?response_type=id_token" + + "&scope=openid" + + "&login_hint=" + + req.query.login_hint + + "<i_message_hint=" + + req.query.lti_message_hint + + "&state=" + + state + + "&redirect_uri=" + + encodeURIComponent(redirectUri) + + "&client_id=" + + clientId + + "&nonce=" + + nonce; + + res.redirect(url); +}; +``` diff --git a/docs/blackboard/lti/1.3/core/core-launch.md b/docs/blackboard/lti/1.3/core/core-launch.md new file mode 100644 index 000000000..17e752c0e --- /dev/null +++ b/docs/blackboard/lti/1.3/core/core-launch.md @@ -0,0 +1,25 @@ +--- +title: LTI Message Launch Flow +id: core-launch +sidebar_position: 1 +published: "" +edited: "" +--- + +LTI proposes a communication between LMS and the system based on JWT payloads sent between the systems, each with a different intention, however, the Core LTI 1.3 launch is the same for any type of interaction. This core launch is the base from where Deep Linking, Assignments and Grades and Names and Roles Provisioning Service are build upon (These services are outlined in later sections) + +The UML sequence diagram below shows all the steps, including some optional ones, for implementing the reception of an LTI message launch. We'll break each step down in the next sections. + + + +![LTI Launch Sequence](/assets/img/lti-launch-sequence.png) + +### Workflow Steps + +The LTI workflow above has three main steps to complete the communication between the two systems. + +- First, it performs an OIDC authentication which starts when the user clicks on the LTI item within Learn +- Second, it receives a JWT token from Learn and performs a validation to review if the token received from Learn is correct and hasn't been altered +- And third, it performs additional calls if needed to authenticate to complementary services. + +These steps will be reviewed in depth in the following sections. diff --git a/docs/blackboard/lti/core/id-token.md b/docs/blackboard/lti/1.3/core/jwt-sample.md similarity index 66% rename from docs/blackboard/lti/core/id-token.md rename to docs/blackboard/lti/1.3/core/jwt-sample.md index c47783216..e3571efee 100644 --- a/docs/blackboard/lti/core/id-token.md +++ b/docs/blackboard/lti/1.3/core/jwt-sample.md @@ -1,65 +1,22 @@ --- -layout: post -title: "Handling the Launch with id_token JWT" -id: id-token +title: Sample JWT content +id: jwt-contents +sidebar_position: 5 published: "" -edited: "" -categories: Standards -author: Eric Preston +edited: "2024-09-04" --- -### Overview +The following is a sample of the expected JWT contents received from the form POST request -Once the OIDC login negotiation has succeeded you will receive a FORM POST from the browser with two form paramaters: - -1. id_token - this is the JSON Web Token (JWT) that contains all the launch information. See [jwt.io](https://jwt.io) for more information on JWTs. You can also use that site to inspect any JWTs you receive (or create). -2. state - if you sent a state value back in the OIDC auth response you will receive this as a URL parameter. You can (should?) use to to ensure the user who initiated the OIDC login is the same user issuing the launch. - -These are the basic steps you should upon receiving the id_token JWT: - -1. Verify the token - 1. Get the header, body, and signature from the JWT (these parts are separated by a period `.` - 2. Verify the signing algorithm is what you expect - 3. Get the Client ID and its JWKS URL. - 4. Validate the signature, using a JWT library -2. Parse the body into JSON - you now have all the information you need to handle the launch for your tool - -### Sample code - -Some sample code in Node.js is below: - -``` -exports.handleIdToken = function(id_token) { - let parts = id_token.split("."); - - let header = JSON.parse(Buffer.from(parts[0], "base64").toString()); - let body = JSON.parse(Buffer.from(parts[1], "base64").toString()); - - // Verify launch is from correct party - // aud could be an array or a single entry - let clientId; - if (jwtPayload.body.aud instanceof Array) { - clientId = jwtPayload.body.aud[0]; - } else { - clientId = jwtPayload.body.aud; - } - - let publicKey = // Get public key from the configured JWKS URL using the kid in the header of the JWT - - jwt.verify(id_token, jwk2pem(publicKey)); - - // All is good so run with the JWT body -}; -``` - -### Sample JWT JSON +:::info +Please keep in mind that this information can change, always review the Core LTI 1.3 specification for details about the included information +::: ``` { "kid": "53c4573a-1ac8-4484-b036-a7b22b557e8c", "alg": "RS256" -} - +}, { "sub": "4f1025ffab1846ee9ca0a53299dd51b6", "https://purl.imsglobal.org/spec/lti/claim/deployment_id": "c3c37f92-d008-43db-9e8a-e10fd139ec2d", diff --git a/docs/blackboard/lti/1.3/core/lti-post.md b/docs/blackboard/lti/1.3/core/lti-post.md new file mode 100644 index 000000000..f3cdc2f26 --- /dev/null +++ b/docs/blackboard/lti/1.3/core/lti-post.md @@ -0,0 +1,73 @@ +--- +title: Receiving the id_token +id: idtoken-verification +sidebar_position: 3 +published: "" +edited: "" +--- + +From the same workflow used on previous sections, we can now work on the next part of the flow which is the handling of the POST request which includes the id_token + +![image of the LTI workflow outlining the LTI POST to the tool](/assets/img/lti-launch-sequence-idtoken.png) + +## Overview + +Continuing after the OIDC redirect from the last section, the Developer Portal receives the OIDC authentication request from the tool and validates that the redirect URI is registered. It then, redirects to Learn with a command to authenticate the LTI launch, which builds the id_token (JWT) that contains the LTI payload (user, course, resource, etc.) and signs it with its private key. Learn then auto-submits a form with the POST method to the redirect URI specified with two form parameters: + +- `id_token` this is the JSON Web Token (JWT) that contains all the launch information. See [jwt.io](https://jwt.io) for more information on JWTs. You can also use that site to inspect any JWTs you receive (or create). +- `state` - if you sent a state value back in the OIDC auth response you will receive this as a URL parameter. You can (and should) use it to ensure the user who initiated the OIDC login is the same user issuing the launch. + +When your tool receives this form POST from the browser, the first thing it should do is validate the state is what it stored in the cookie. If it doesn't match the tool should reject the request since it could have been altered. + +The next step is to unpack the JWT and validate the signature. JWTs are comprised of three Base64-encoded strings separated by the period (.) sign. The first part is the header which contains the key ID (kid) and signing algorithm. The second part is the payload in JSON format, and it contains the issuer (iss), client ID (aud), user ID (sub) and other information about the launch. Your tool must look up the platform configuration for that issuer/client ID/deployment ID combination and get the platform's public key from the Developer Portal public keyset URL, using the kid in the JWT header for selecting the particular key the platform used to sign the token. The third part is the signature, which normally your code won't work with directly. + +Your tool then uses a library of their choosing to validate the signature of the JWT. If the signature is valid then the tool can proceed to process the rest of the JWT information and render its UI with the information it has about the LTI message. + +## tl;dr of the steps needed to validate the token + +These are the steps you should follow upon receiving the id_token JWT: + +1. Verify the token + 1. Get the header, body, and signature from the JWT (these parts are separated by a period `.`) + 2. Verify the signing algorithm is what you expect. This can be found by parsing the header portion of the id_token + 3. Verify if the launch is for the proper Client ID (Application ID) by checking the `aud` property of the body portion. It should match the Client ID of your tool + 4. Get the JWKS key used by Learn to sign the JWT token. This can be found by performing a GET request to the JWKS endpoint given by the Developer Portal when registering the application, from there, you can select the proper key by checking the `kid` value included in the header of the JWT token against the values received from the Developer Portal + 5. Validate the signature using a JWT library, using the id_token and the key selected from the `kid` +2. Parse the body into JSON - you now have all the information you need to handle the launch for your tool + +:::caution Verify the token with a proper library +To prevent any issues while verifying the token, use a JWT library that has a `verify` function since this will cryptographically validate the token. +::: + +## Sample code + +Below you can find sample code that outline how the validation of the id_token can be performed + +#### NodeJS + +```nodejs +const jwt = require("jsonwebtoken"); +const jwk2pem = require("pem-jwk"); + +exports.handleIdToken = function(id_token) { + let parts = id_token.split("."); + + let header = JSON.parse(Buffer.from(parts[0], "base64").toString()); + let body = JSON.parse(Buffer.from(parts[1], "base64").toString()); + + // Verify launch is from correct party + // aud could be an array or a single entry + let clientId; + if (jwtPayload.body.aud instanceof Array) { + clientId = jwtPayload.body.aud[0]; + } else { + clientId = jwtPayload.body.aud; + } + + let publicKey = // Get public key from the configured JWKS URL using the kid in the header of the JWT + + jwt.verify(id_token, jwk2pem(publicKey)); + + // All is good so run with the JWT body +}; +``` diff --git a/docs/blackboard/lti/1.3/core/optional-auths.md b/docs/blackboard/lti/1.3/core/optional-auths.md new file mode 100644 index 000000000..82bd17bbb --- /dev/null +++ b/docs/blackboard/lti/1.3/core/optional-auths.md @@ -0,0 +1,23 @@ +--- +title: Optional authentication for additional services +id: optional-requests +sidebar_position: 4 +published: "" +edited: "2024-09-04" +--- + +As seen in the workflow in previous sections, once the JWt token is sent to your tool, you can verify its content and then, render the page corresponding to your application or data, however, if you want to perform additional calls through REST APIs or, use the additional services from LTI advantage (Assignments and Grades Service or Names and Roles Provisioning Service), you will need to perform additional authentication processes. + +### Learn REST Token + +If your tool is going to use the Learn public REST API in order to get or set information it can't via LTI then it should retrieve a Learn OAuth 2 access token at this time and cache it. There are choices as to what OAuth 2 flow you can use, so please refer to this document on how to [retrieve a Learn OAuth 2 access token](/docs/blackboard/rest-apis/getting-started/first-steps.md). + +In the workflow image referenced from other section, we use with 3-Legged oAuth flow as its the most common for UI-based work where you want the API call to be done on behalf of the interacting user. See this document on using [3-legged oauth](/docs/blackboard/rest-apis/getting-started/3lo.md). + +### LTI Rest Token + +If your tool wants to take advantage of the LTI services, such as Assignment & Grades, or Names & Roles, then you'll need to retrieve an LTI access token. This token is of a different format and uses a different security model than the Learn public API. + +You'll need to construct a signed (with your private key) JWT and post that to the LTI OAuth 2 token endpoint provided by the Developer Portal when registering your application. If all is well, you will receive an access token back which you should cache, and use for making service calls back to Learn. Keep in mind that the LTI access token has the same time constraints as the REST API token which is a 1 hour expiration time. + +The workflow, parameters and information needed to perform this authentication flow will be covered under the Assignments and Grades and Names and Roles PRovisioning System sections. diff --git a/docs/blackboard/lti/deep-linking-two-json.md b/docs/blackboard/lti/1.3/dl/deep-linking-two-json.md similarity index 100% rename from docs/blackboard/lti/deep-linking-two-json.md rename to docs/blackboard/lti/1.3/dl/deep-linking-two-json.md diff --git a/docs/blackboard/lti/1.3/nrps/help.md b/docs/blackboard/lti/1.3/nrps/help.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/blackboard/lti/getting-started-with-lti.md b/docs/blackboard/lti/1.3/register-an-application.md similarity index 62% rename from docs/blackboard/lti/getting-started-with-lti.md rename to docs/blackboard/lti/1.3/register-an-application.md index fc89cc4c9..c59ea280f 100644 --- a/docs/blackboard/lti/getting-started-with-lti.md +++ b/docs/blackboard/lti/1.3/register-an-application.md @@ -1,78 +1,28 @@ --- -title: "Getting Started With LTI" -id: getting-started-with-lti -categories: Standards +title: Registering a new LTI application +id: register-an-application published: "" edited: "" author: Scott Hurrey --- -### Overview - -Learning Tools Interoperability (LTI) is a standard from the IMS Global consortium. -This standard focuses on contextual launches and grade return. For more -information about the standard, see [Learning Tools -Interoperability](https://imsglobal.org/lti). - -Note that Learn supports two versions of LTI: - - 1. LTI 1.1 - 2. LTI 1.3/Advantage - -This getting started guide is focused on LTI 1.3/Advantage. LTI 1.1 has been deprecated by the IMS Global, and it's been around for over 10 years. Learn will continue support of LTI 1.1 tools for the indeterminate future while LTI 1.1 tool developers migrate their tool to LTI 1.3/Advantage. If you are building a new tool, it is **_strongly recommended_** you use LTI 1.3/Advantage. - -### LTI 1.3/Advantage - -LTI Advantage consists of the following four specifications: - - 1. LTI Core (AKA LTI 1.3) - 2. Deep Linking - 3. Names and Roles - 4. Assignments and Grades - -Additional companion specs will be released as they are developed. - -Learn supports all of the above LTI Advantage specs, as well as the new Course Group spec which will be published soon. - -It is imperative that you read the specs from the IMS Global. They refer to other specifications that LTI Advantage is based on, such as the OIDC specification, JWT, and OAuth 2. We highly recommend you familiarize yourself with these specifications. - -Start with the IMS Security Framework here - -Continue with the LTI Advantage specs here - -The implementation guide is very helpful as well - -You can test your tool with the IMS LTI Reference Implementation here: . It is written in Ruby and is open source. - -We have a sample LTI tool written in React and Node.js which we discuss in a later section. That can be found here: - - -There are other LTI resources here: - -### Building an LTI 1.3 Application - -Please see this guide for a recipe on building an LTI 1.3 application. Note that you can develop an LTI application in any programming language and framework, and deploy it to any cloud service provider. -We cannot provide guidance on what technologies or hosting platforms to use, but we will cover all the steps required for building an application. - -[Tool Implementation Guide](./tutorials/implementation-guide.md) - -### Registering Your Application - In this section we cover how you register your application with Anthology and deploy it to a Learn instance. Registration and deployment are not covered in the specification (yet), and each LMS vendor handles it slightly differently. -#### Anthology Developer Portal +## Anthology Developer Portal The first thing to understand about registering your application is that Anthology has you register your tool **ONCE** with our developer portal here . This is a central, self-service application, running in AWS where you enter information about your application, and are given the values you need for your application to work with LTI Advantage and Learn. It is also the same place you get the ID, key, and secret if you are going to use our public REST API. -> **NOTE:** Do not ask institutions to register your tool with the Anthology Developer Portal. You register it **ONCE** with Anthology and institutions can deploy it with the Client ID you give them. They will receive a Deployment ID which they will exchange with you to set up the account. It is the deployment ID, in conjunction with the client ID and issuer, that uniquely identifies the business agreement between the tool vendor and the institution. +:::caution +Do not ask institutions to register your tool with the Anthology Developer Portal. You register it **ONCE** with Anthology and institutions can deploy it with the Client ID you give them. They will receive a Deployment ID which they will exchange with you to set up the account. It is the deployment ID, in conjunction with the client ID and issuer, that uniquely identifies the business agreement between the tool vendor and the institution. +::: -#### Information you Provide +### Information you Provide -##### Domain +#### Domain We will use the terms `Application` and `Tool` interchangeably throughout this document. What we refer to as an `Application` may be different than how you see it. For Learn, an `Application` is a web application, accepting GET and POST requests at a URL. That application is defined by its fully-qualified domain name (FQDN). An application can have many FQDNs, but two applications cannot share the same FQDN. The reason has to do with needing to be able to immport course archives, such as from IMS Common Cartridge. If there are LTI links in that archive the only way we have today to map those links to a particular LTI Application is through domain matching. If that seems like a limitation, please read on. -### LTI 1.3 Fields +#### LTI 1.3 Fields The LTI 1.3 spec defines the information you must provide to a Platform (LMS) such as Blackbaord Learn. Those values are: @@ -85,14 +35,14 @@ The LTI 1.3 spec defines the information you must provide to a Platform (LMS) su 4. **Signing Algorithm** - Anthology currently supports RS256 and RS512. We can support more as we are requested to do so. -### Custom Parameters +#### Custom Parameters The LTI spec supports the notion of custom parameters with a launch. These are arbitrary `name=value` tuples that you can provide to uniquely identify the launch, or any other piece of information you need from the platform at launch time. See the following two documents on how to use substitution parameters within custom parameters to receive context-specific data on an LTI launch: [IMS LTI 1.3 Parameter Substitution](https://www.imsglobal.org/spec/lti/v1p3/#customproperty) [Learn Template Variables](/docs/blackboard/rest-apis/advanced/dynamic-rendering-with-template-variables.md) -#### Information you Receive +### Information you Receive Once you have registered your application with the Blackboard Developer Portal, you will receive [almost] all the information you need to configuration your application to receive LTI 1.3 launches from a Learn instance. @@ -102,22 +52,24 @@ Once you have registered your application with the Blackboard Developer Portal, 4. Auth token endpoint - the endpoint you use to get an OAuth 2 Bearer Token if you wish to make service calls, such as Assignment & Grades, or Names & Roles back to Learn 5. OIDC auth request endpoint - the endpoint you respond to after you receive an OIDC login initiation request from Learn. -> **NOTE:** You will also receive an application key and secret. These are your credentials for using our public REST API. Be sure to save these off as you won't be able to get back at them later. We do not store the secret on our side. +:::info +You will also receive an application key and secret. These are your credentials for using our public REST API. Be sure to save these off as you won't be able to get back at them later. We do not store the secret on our side. +::: -### LTI Placements +## LTI Placements In Learn the way an LTI tool is surfaced in the user interface (UI) is through the definition of one or more `Placements`. An application developer can define these placements so a Learn admin doesn't have to. There are currently six types of placements you can create: -| Type | Description | Options | -| -------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------- | -| Deep Linking | Supports [LTI Deep Linking](https://www.imsglobal.org/spec/lti-dl/v2p0) to get content in outline or editor | Allow student access | -| Course Content | Can be placed in the course outline or editor | Can be graded | -| Course | Appears in Ultra Books & Tools, Original Tools | Allow student access | -| System | Appears in Ultra Base Nav Tools, Original Institution module | | -| Admin | Appears in Admin Tools module | | -| UEF | Special type for extending the Ultra UI; see [UEF docs](/docs/blackboard/premium-apis/uef/uef_getting_started.md) | | +| Type | Description | Options | +| -------------- | ----------------------------------------------------------------------------------------------------------- | -------------------- | +| Deep Linking | Supports [LTI Deep Linking](https://www.imsglobal.org/spec/lti-dl/v2p0) to get content in outline or editor | Allow student access | +| Course Content | Can be placed in the course outline or editor | Can be graded | +| Course | Appears in Ultra Books & Tools, Original Tools | Allow student access | +| System | Appears in Ultra Base Nav Tools, Original Institution module | | +| Admin | Appears in Admin Tools module | | +| UEF | Special type for extending the Ultra UI; see [UEF docs](/docs/blackboard/uef/uef_getting_started.md) | | -#### Placement properties +### Placement properties In the table above some placements allow you to control whether students have access or not. Some placements allow you to configure if it can be graded or not. All placements have the following properties in common: @@ -126,23 +78,7 @@ In the table above some placements allow you to control whether students have ac - Type - see above - Target link URI - because target_link_uri is part of the OIDC spec we support it here, however it's really just property of the placement. It can be anything you want. We don't launch to it, e.g., no FORM POST to this URL. It can be used for routing within your application. - Icon - we currently suggest a 50x50 pixel icon (PNG, GIF, JPEG). I don't think we support SVG currently. We will resize as needed. -- Custom parameters - a list of name=value pairs, each on their own line. These override any set on the Tool level. See the section above on using substitution parameters. - -### Make Your LTI Tool Available to Learn Servers - -Once you have developed and registered an LTI tool, you can share it with Learn -administrators so that they can configure their Learn servers to work with it. - -To deploy your application to a Learn instance share the Application ID with the administrator of -that Learn server. At the point they enter the Application (Client) ID they will see the properties of the application you configured through -the developer portal. They will also receive a new piece of information which is the **Deployment ID**. This deployment ID is sent with every LTI launch, and uniquely identifies the Learn instance that launch is coming from. - -It is likely that you'll need to use that deployment ID to map which Learn instance a launch is coming from. This is a bit of a chicken and egg problem, in that you have registered your application with the developer portal, but you don't know what Learn instances are using it yet. You can automatically handle that at launch time, e.g., if you haven't seen that deployment ID previously then prompt the user to set it up, or you can do the set up out of band. - -For more information about -registering your application, see [Register Your Application](https://help.blackboard.com/learn/Administrator/Hosting/System_Integration/LTI). - -At this point your application is connected to a Learn instance. All that remains is for an instructor or other user to create links in a course or use some of the automatically deployed links, such as a course tool placement. +- Custom parameters - a list of `name=value` pairs, each on their own line. These override any set on the Tool level if they have the same `name` value. See the section above on using substitution parameters. ### LTI Placement to Building Block Link Mapping @@ -159,10 +95,26 @@ for Developers. | A tool available outside of a course for all users | System Tool | user_tool | | A tool available only to system administrators | Administrator Tool | system_tool | -### Caveat +## Make Your LTI Tool Available to Learn Servers + +Once you have developed or are developing an application and want to test it with Blackboard Learn, you can register the application on the Developer Portal and make it available to Learn Administrators so that they can configure their Learn servers to work with it. -Deleting a registered LTI domain and/or the associated managed placements from the Administrator Panel -> LTI Tool Providers page will invalidate all of the associated LTI launch links in courses. The data will be gone from the database. There is no way to fix this. NEVER delete a registered domain or managed placements without considering these consequences. +To deploy your application to a Learn instance share the Application ID with the administrator of that Learn server. The administrator can access within the Learn instance to `Admin > LTI Tool Providers` and click on `Register a new LTI 1.3/Advantage tool`. In the field that shows up, paste the Application ID and then click Submit. + +Once submitted, they will see the properties of the application you configured through the Developer Portal. Once the administrator clicks "Submit" again, a new piece of information will be available which is the **Deployment ID**. This deployment ID is sent with every LTI launch, and uniquely identifies the Learn instance that launch is coming from. This can be seen by clicking the chevron next to the newly installed tool and clicking on "Edit" which shows the configuration parameters of the tool, including the Deployment ID + +It is likely that you'll need to use that deployment ID to map which Learn instance a launch is coming from. This is a bit of a chicken and egg problem, in that you have registered your application with the developer portal, but you don't know what Learn instances are using it yet. You can automatically handle that at launch time, e.g., if you haven't seen that deployment ID previously then prompt the user to set it up, or you can do the set up out of band. + +At this point your application is connected to a Learn instance. All that remains is for an instructor or other user to create links in a course or use some of the automatically deployed links, such as a course tool placement. + +## Deleting an LTI tool or placement from Blackboard Learn + +Deleting a registered LTI domain and/or the associated managed placements from the Administrator Panel -> LTI Tool Providers page will invalidate all of the associated LTI launch links in courses. The data will be gone from the database. There is no way to fix this. **NEVER** delete a registered domain or managed placements without considering these consequences. If you create an LTI 1.3 Tool that uses the same domain as a currently registered LTI 1.1 tool on a Learn system, there is code in Learn that will prompt you to migrate from LTI 1.1 to LTI 1.3. Generally that's a great option. Finally, only very brave people make changes on a production system without testing first on a test or staging system. We recommend you be more cautious than brave. + +## Ready to register you application? + +Now that we covered what information is needed from the system and what information can the system expect from Learn, we can register the application and start the development of the LTI 1.3 tool. To register your application, you can follow the steps outlined here (along with the information of this article) which will provide you a visual aid of what to expect when navigating the Developer Portal: [Registering and Managing a REST or LTI application](/docs/developer-portal/creating-new-rest-or-lti-application) diff --git a/docs/blackboard/lti/tutorials/develop-lti-advantage-solution.md b/docs/blackboard/lti/1.3/tutorials/develop-lti-advantage-solution.md similarity index 100% rename from docs/blackboard/lti/tutorials/develop-lti-advantage-solution.md rename to docs/blackboard/lti/1.3/tutorials/develop-lti-advantage-solution.md diff --git a/docs/blackboard/lti/tutorials/names-and-roles.md b/docs/blackboard/lti/1.3/tutorials/names-and-roles.md similarity index 100% rename from docs/blackboard/lti/tutorials/names-and-roles.md rename to docs/blackboard/lti/1.3/tutorials/names-and-roles.md diff --git a/docs/blackboard/lti/tutorials/py-lti-1p3.md b/docs/blackboard/lti/1.3/tutorials/py-lti-1p3.md similarity index 100% rename from docs/blackboard/lti/tutorials/py-lti-1p3.md rename to docs/blackboard/lti/1.3/tutorials/py-lti-1p3.md diff --git a/docs/blackboard/lti/tutorials/testing-tool.md b/docs/blackboard/lti/1.3/tutorials/testing-tool.md similarity index 100% rename from docs/blackboard/lti/tutorials/testing-tool.md rename to docs/blackboard/lti/1.3/tutorials/testing-tool.md diff --git a/docs/blackboard/lti/core/poidc-login-lti_storage_target.md b/docs/blackboard/lti/archive/poidc-login-lti_storage_target.md similarity index 100% rename from docs/blackboard/lti/core/poidc-login-lti_storage_target.md rename to docs/blackboard/lti/archive/poidc-login-lti_storage_target.md diff --git a/docs/blackboard/lti/core/oidc-login.md b/docs/blackboard/lti/core/oidc-login.md deleted file mode 100644 index 7b8fbaa22..000000000 --- a/docs/blackboard/lti/core/oidc-login.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -layout: post -title: "Handling OIDC Login" -id: handling-oidc-login -categories: Standards -published: "" -edited: "" -author: Eric Preston ---- - -### Overview - -The Open ID Connect 3rd-party-initiated login is the first step in handling an LTI 1.3 launch. - -From Learn you will receive a GET request to the URL you registered in the developer portal when you registered your application. The handling of this request is straight forward, but you'll need to note a couple of things. - -1. You will receive and lti_message_hint as a URL parameter. You must send it back unaltered. -2. We do send the client_id and lti_deployment_id on the request, but note they are not required by the specification. -3. We strongly recommend you create a _state_ parameter value and send that with your response, and store that locally so it can be verified on the subsequent launch request. This is how you prevent CSRF attacks. Note, that Safari currently doesn't support sending 3rd party cookies back if you are hosted in an iframe. - -### Sample - -Some sample code in Node.js is below: - -``` -exports.oidcLogin = function(req, res) { - const state = uuid.v4(); // save this locally, such as in a cookie; optional in the OIDC spec - const nonce = uuid.v4(); // Used to prevent playback - const client = // You'll need to determine the client ID for this request from parameters on the request - const redirectUri = // Get the Redirect URI for this client - const oidcAuthUrl = // The URL you were given for this client when you registered your application - - let url = - oidcAuthUrl + - "?response_type=id_token" + - "&scope=openid" + - "&login_hint=" + - req.query.login_hint + - "<i_message_hint=" + - req.query.lti_message_hint + - "&state=" + - state + - "&redirect_uri=" + - encodeURIComponent(redirectUri) + - "&client_id=" + - clientId + - "&nonce=" + - nonce; - - res.redirect(url); -}; -``` diff --git a/docs/blackboard/lti/lti-intro.md b/docs/blackboard/lti/lti-intro.md deleted file mode 100644 index db0ff8ab3..000000000 --- a/docs/blackboard/lti/lti-intro.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -sidebar_position: 1 -id: introduction -published: "" -edited: "" -author: Eric Preston ---- - -# Welcome to LTI 1.3 for Blackboard Learn! - -Blackboard Learn supports the latest version of the Learning Tools Interoperability (LTI) specification, which is LTI 1.3. This version of LTI provides enhanced security features and improved interoperability between learning management systems (LMSs) and external tools. - -With LTI 1.3, Blackboard supports the use of JSON Web Tokens (JWTs) for authentication, which provides a more secure way to exchange user information between the LMS and external tools. It also supports the use of the Resource Link Launch Request (RLLR) message, which enables better communication between the Learn and external tool provider regarding the specific context of a learning activity. - -In addition to these technical enhancements, LTI 1.3 also provides a streamlined user experience, making it easier for instructors and students to discover and use external tools within the Blackboard environment. - -Blackboard's support for LTI allows users to integrate with a wide range of third-party tools and services, including multimedia content, assessment tools, and learning analytics platforms. This enables instructors to create more engaging and interactive learning experiences for their students, and allows students to access a variety of learning resources from within their Blackboard course. - -Overall, Blackboard's support for LTI 1.3 demonstrates its commitment to providing a robust and secure platform for integrating with external tools and content providers, and to improving the overall teaching and learning experience for its users. - -## What Specifically is LTI 1.3? - -Learning Tools Interoperability (LTI) 1.3 is the latest version of the LTI specification, which is a set of technical standards that enable learning management systems (LMSs) to integrate with external tools and content providers. LTI 1.3 builds upon the previous versions of LTI, adding new features and enhancements that improve the security, interoperability, and user experience of LTI integrations. - -Overall, LTI 1.3 is a significant improvement over previous versions of the specification, providing enhanced security, improved interoperability, a streamlined user experience, and easier implementation for developers. As a result, it has become the preferred version of LTI for many LMSs and external tool providers. - -## What are the Benefits of LTI 1.3? - -Here are some of the key features and benefits of LTI 1.3: - -**Enhanced security**: LTI 1.3 introduces new security features such as JSON Web Tokens (JWTs) and the OpenID Connect (OIDC) authentication protocol, which provide a more secure way to exchange user information between the LMS and external tools. This reduces the risk of unauthorized access to sensitive user data and improves the overall security of LTI integrations. - -**Improved interoperability**: LTI 1.3 introduces the Resource Link Launch Request (RLLR) message, which enables better communication between the LMS and external tools regarding the specific context of a learning activity. This makes it easier for external tools to integrate with the LMS and provide a seamless user experience. - -**Streamlined user experience**: LTI 1.3 introduces a new Deep Linking feature, which enables instructors to create links to specific resources within external tools and embed them directly within their course content. This makes it easier for students to access external tools and content without leaving the LMS environment, improving the overall user experience. - -**Easier implementation**: LTI 1.3 introduces a new Developer Key and Secret mechanism, which simplifies the process of creating and managing LTI integrations. This makes it easier for developers to implement LTI integrations and reduces the time and effort required to maintain them. diff --git a/docs/blackboard/lti/lti-registration-and-deployment.md b/docs/blackboard/lti/lti-registration-and-deployment.md deleted file mode 100644 index df0fcb7f4..000000000 --- a/docs/blackboard/lti/lti-registration-and-deployment.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: "LTI Registration and Deployment with Learn" -id: registration-deployment -categories: Standards -published: "" -edited: "" -author: Eric Preston -sidebar_position: 4 ---- - -## Why do we use a central service at Anthology? - -We believe that having Tool vendors register an LTI Tool _once_ through [the Developer Portal](https://developer.anthology.com/) is the best approach. It allows Learn admins to deploy that tool by entering just one piece of information (the Client ID) in the Admin Panel and sharing another piece of information (the Deployment ID) with the Tool vendor. - -_Tool vendor's clients don't need to register individual applications with the Developer Portal. That defeats the entire purpose of building this centralized service to make everyone's life a little simpler._ - -When a Tool vendor needs to make changes to their tool configuration they do it in one place for Learn: the Developer Portal. If they add a new redirect URL, change the name of their application, or if they need to change the attributes of a placement (such as the icon, name, or target link URL) they can do so in one place. Learn admins can then synchronize their deployment without having to make those changes themselves: all the information required to perform an LTI launch is retrieved from the Developer Portal. - -## LTI 1.3/Advantage Security - -With LTI 1.3, an LTI Tool or Tool Provider shares a lot of information with a Tool Consumer or Platform and we must manage the signing and validation of the payload in a very different way than with the previous versions. - -With LTI 1.1, we used to exchange just 3 pieces of information: Key, Secret, and URL. LTI 1.1 uses OAuth 1.0a signing of the FORM POST parameters to ensure that the data is secure. With LTI 1.3, the entire security model has changed. - -The LTI 1.3/Advantage security model is based on OAuth 2 and OpenID Connect. It uses client credentials grant for getting bearer tokens, just like our REST API mechanism but rather than issuing keys and secrets we rely on asymmetric public/private key pairs. - -Learn is responsible for generating a private key that signs the LTI messages it sends to the tool, and it makes its public key(s) available via a JWKS URL for the tool to validate the signature of those messages. - -A tool is responsible for generating a private key that it uses to sign OAuth 2 bearer token requests for LTI messages it sends to Learn, such as Deep Linking response, Names and Roles, and Assignment and Grades. It provides a JWKS URL for its public key(s) so Learn can validate the signature of messages the tool sends to Learn. - -## LTI 1.3 Registration - -Because of the new security model and because LTI 1.3 has built-in support for preventing cross-site request forgery attacks (CSRF or XSRF), there is more information that needs to be shared between a tool and a platform. - -The LTI 1.3 specification requires that a Tool share the following: - -1. Login Initiation URL -2. Tool Redirect URL(s) -3. Tool JWKS URL -4. Signing Algorithm (RS256 or RS512 are the current choices) - -The above values are defined by the OpenID Connect 3rd-party-initiated login flow and the fact that we are using asymmetric keys. - -The specification also requires that a Platform share the following information with the tool: - -1. Client ID -2. Issuer -3. Auth token endpoint -4. OIDC auth request endpoint -5. Platform JWKS URL -6. Deployment ID - -The first 5 come from the OAuth 2 and OpenID Connect specifications upon which the LTI 1.3 security model is built. - -The Deployment ID is an LTI 1.3 construct to allow multiple deployments of a tool for a single Client ID, such as different colleges at a university. - -We've gone from three pieces of information to share between a platform and tool in LTI 1.1 to ten pieces of information that must be shared. - -## Anthology Developer Portal - -With LTI 1.3, since keys and secrets are no longer shared, and the signing of messages uses asymmetric public/private key pairs, Blackboard has the opportunity to generate its keys in a central service and do the signing and validation of messages there. - -With Learn we have split the _registration_ of a tool from the _deployment_ of a tool. - -Rather than ask a Learn administrator to exchange all of the above information with a Tool vendor (which is information the Learn admin doesn't care about and could easily make mistakes in entering) and in order to make both the Tool vendor and the Learn admin lives a bit better, we have centralized the registration of a tool. - -A Tool vendor registers their tool _once_ with the Blackboard Developer Portal, exchanging all of the information above _except_ the Deployment ID. The tool vendor is granted a Client ID and shares it with their clients. - -A Learn admin takes that Client ID and deploys it to Learn by entering a single value (the Client ID) in the Admin Panel. All the rest of the information required to perform an LTI launch from that Learn instance is retrieved from the Developer Portal. - -A Learn admin is granted a Deployment ID that it shares with the Tool vendor to uniquely identify the account associated with that institution. A Tool vendor now has all the information they need to accept LTI launches from that institution. - -## LTI Links or Placements - -Another aspect of LTI that the specification does not address is the issue of where an LTI link gets surfaced and what type of links do they support. - -A tool may want a link in the course outline, or in the rich content editor, or in a system-wide area, or as a link for a course but not in the outline. - -A tool may want to support Deep Linking so an instructor can select or create content in the Tool and have the links appear in the course. - -Learn has the concept of LTI Placements to support this. Blackboard allows a Tool vendor to register those placements with the Developer Portal, so an admin doesn't have to do that work. - -![LTI diagram](/assets/img/ltidiagram.png) - -If you have any other questions about LTI Registration and Deployment with Learn, let us know. diff --git a/docs/blackboard/lti/migrating/migrating-11.md b/docs/blackboard/lti/migrating/migrating-11.md deleted file mode 100644 index 58eea0ba2..000000000 --- a/docs/blackboard/lti/migrating/migrating-11.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -title: "Migrating from LTI 1.0/1.1 to 1.3" -id: migrating-from-lt1.1-to-lti1.3 -categories: Standards -published: "" -edited: "" -author: Eric Preston ---- - -### Overview - -For the first time in LTI's history we need to handle migrating from one version to another. Before 1.3 the changes were all -additive, but with 1.3 the payload format and security model have changed significantly, so we need a way to -migrate existing LTI 1.1 (and 1.0) links to support the 1.3 format. - -Note that Learn has never allowed two tools or applications to be configured in the same Learn instance with the -same fully qualified domain name (fqdn). This means that you cannot have both a 1.1 version and a 1.3 version of -a tool configured at the same time if they use the same fqdn. - -If a tool provider wants to upgrade their tool to LTI 1.3/Advantage but not break all of an institution's existing links -then they will need to host their LTI 1.3/Advantage tool at the same fqdn. - -In Learn we automatically upgrade the links for a tool when a Learn administrator deploys the 1.3 version of the tool. - -At deployment time, if Learn sees there is an existing 1.1 tool registered with the same domain(s) as the 1.3 -tool the admin is prompted to migrate the links. If they choose "yes" then we migrate ALL LTI 1.1 links to the -new LTI 1.3 application, effectively removing the LTI 1.1 domain configuration. The links remain and should work -fine if the tool developer has done their job correctly. The target_link_uri for the 1.3 tool is the same -as the launch URL defined in the LTI 1.1 placement or link. diff --git a/docs/blackboard/lti/turn-on-all-switches.md b/docs/blackboard/lti/turn-on-all-switches.md deleted file mode 100644 index 8106298f5..000000000 --- a/docs/blackboard/lti/turn-on-all-switches.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: LTI In Learn - Turn On All The Switches -id: turn-on-all-switches -categories: Standards -published: "" -edited: "" -author: Scott Hurrey -sidebar_position: 6 ---- - -### Overview - -We often hear about this message "The Tool Provider has been disabled by the System Administrator" The usual cause is that one of the 3 LTI switches is disabled. There are 3 places you need to enable LTI: (1) at the tool level, (2) at the course/organization level, and (3) at the LTI Global Properties level. Screenshots follow. **LAST, BUT NOT LEAST - Make certain you are enrolled in the course, as an instructor or student, before using the LTI placements you create in a course! Your launch will fail if you don't have a role in the course.** - -### All the Switches - -(1) Administrator Panel -> Tools & Utilities section -> Tools - -![1-LTIConfigAdminTools.png](/assets/img/turn-on-all-switches-1.png) - -(2) In a Course/Organization, Start at the Left Nav Menu - -![2-LTIConfigCourseOrg.png](/assets/img/turn-on-all-switches-2.png) - -(3) Administrator Panel -> Integrations section -> LTI Tool Providers -> Manage Global Properties - -![3-LTIConfigManageGlobal.png](/assets/img/turn-on-all-switches-3.png) diff --git a/docs/blackboard/lti/tutorials/implementation-guide.md b/docs/blackboard/lti/tutorials/implementation-guide.md deleted file mode 100644 index 80889fea1..000000000 --- a/docs/blackboard/lti/tutorials/implementation-guide.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: "LTI 1.3 Tool Implementation Guide" -id: lti-implementation-guide -categories: Standards -published: "" -edited: "" -author: Eric Preston ---- - -### Overview - -Implementing an LTI 1.3 + Advantage tool is involved, but we'll break down the steps here. There are many good resources -for building an LTI 1.3 tool as well: - -- [IMS LTI Implementation Guide](https://www.imsglobal.org/spec/lti/v1p3/impl) -- [LTI Bootcamp Resources](https://github.com/IMSGlobal/ltibootcamp) - -### What is LTI? - -At the end of the day all LTI is is a hyperlink from one web application (a Learning Management System or Virtual Learning Environment, called a Platform in the LTI specs) to another web application, called a Tool. The tool is normally hosted at a different domain and often created and supported by another vendor or the learning institution. - -The difference with LTI from a regular hyperlink is it includes data such as the user making the request, the course context and possibly information about the resource (e.g., assignment, discussion, book chapter). For this reason an LTI message must be sent as an HTTP FORM POST to the receiving web application. - -### Security - -Why is LTI complicated if all it is is a hyperlink with data? The answer is: security. - -A tool cannot blindly receive an HTTP POST with data from just anywhere. It needs to know who is sending that data and that it can trust the sender. A security contract must be established between the learning institution hosting the LMS and the tool. Additionally, because all LTI traffic is being transfered via a web browser, that traffic needs to be secured, both from an encryption standpoint as well as from a request forgery standpoint. - -#### Cross-site Request Forgery - -When a browser-based application has links that a user can click on to make something happen, there is an inherent risk of a cross-site request forgery attack, often abbreviated as CSRF or XSRF. If you are logged into your bank account's web site and they have a link or a URL that allows you to transfer money from one account to another, you run the risk of a malicious party offering you a link via email or social media that could get you to transfer money from your account to accounts you don't intend to send money. - -In the world of teaching and learning, with an LTI tool link, there exists the possibility that a malicious user could offer you a link via email or social media to get you to act on their behalf, such as take a quiz or buy a book. We'll soon see how the LTI specs prevent this sort of attack. - -#### Encryption - -Sensitive personal data are sent in LTI messages, so those data must be encrypted and LTI requires the use of TLS 1.2 or higher protocol from the browser. The days of insecure http transport are over. You must run your tool behind SSL supporting the TLS 1.2 or higher protocol. - -#### Authentication - -A tool needs to have a trust relationship with any LMS sending them an LTI message. They can't just accept a message from anyone. Messages must be signed by the sending party and that signature must be validated by the receiving party. The solution the IMS Global has adopted is to use OAuth 2, OpenID Connect, JSON Web Tokens (JWT), and asymmetric public/private key pairs. These are all industry standard specifications for security, and LTI builds upon those. - -When a platform sends a message it packages it up as a JSON Web Token ([JWT](https://jwt.io)) and signs the token with its private key that it has minted and stores securely. The platform publishes its public key at a publicly-accessibly URL and the tool uses that public key to validate the signer of the message. - -### Registration Information - -In order to achieve the security objectives, there are some pieces of information that must be exchanged between the platform and the tool. This is the security contract. - -The platform must receive the following information from the tool: - -- The fully-qualified domain name(s) where the tool is hosted, e.g., example.com -- The OIDC Login URI - a URL to the tool's endpoint for initiating the 3rd-party initiated login flow, which protects agains CSRF. See the [OIDC 3rd-party intiated login specification](https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin). -- One or more Redirect URIs - a URL where the tool will receive the LTI FORM POST with the id_token (JWT) containing the LTI message payload. Note, the redirect URIs must use the fully-qualified domain names referenced above. -- JWKS URL - The URL for the tool's public key set. If the tool is going to send messages to the platform, such as a Deep Linking response or a request for an OAuth access token, then the tool must sign those messages with a private key that it has minted, and provide the public key associated with that private key. This is the asymmetric part mentioned above. See for more information. -- A signing algorithm, e.g., RS-256 or RS-512. Both sides need to agree on the algorithm to sign and verify messages. - -The tool must receive and store for later use the following information from the platform: - -- Issuer - the issuer of the credentials. In Learn's case it is always https://blackboard.com -- Client ID - in Learn this is labeled the Application ID. An issuer can have one or more client IDs associated with it. -- Public JWKS URL - the JWKS URL of the platform (Learn in this case) with which the tool validates the signature of incoming LTI messages -- OAuth 2 Token URL - the URL of the platform's OAuth 2 token issuer for use when making LTI service calls, such as for Assignment and Grades, or Names and Roles. -- OIDC Auth Request URL - the URL the tool must redirect back to after an OIDC login request. This is part of the OIDC login flow for protecting agains CSRF attacks -- Deployment ID - a single client ID can have one or more deployments, so tools must track each of those deployments. This is an extension created by the LTI specification. - -With Learn you will also receive an Application Key and and Application Secret. Store these securely. These are what you use if you want to use the Learn public REST API. - -## LTI Message Launch Flow - -We have covered the information the two parties need to exchange and why that information is needed, at a high level. Now we look at the specifics of implementing the reception of an LTI launch by a tool from a platform. - -The UML sequence diagram below shows all the steps, including some optional ones, for implementing the reception of an LTI message launch. We'll break each step down in words. - -![LTI Launch Sequence](/assets/img/lti-launch-sequence.png) - -### LTI Launch - -#### OIDC Login - -When a user clicks on an LTI link within Learn the Learn server receives a GET request from the browser with information about that LTI link. Once it loads the tool configuration associated with that link the first thing it does is initiate the OIDC Login request with a browser redirect to the registered OIDC Login URI provided by the tool. It passes some information along with the request as query parameters. - -The data sent by the platform on the OIDC login are: - -- issuer -- login_hint - an opaque value to the tool that must be returned back -- target_link_uri - the URI configured by the tool for this LTI link -- lti_message_hint - an opaque value to the tool that must be returned back -- lti_deployment_id - this is optional, but Learn always sends it -- client_id - this is optional, but Learn always sends it -- lti_storage_target - for use if cookies aren't possible - -The tool must then redirect or post back to the registered OIDC Authentication Request URI provided by the platform, including a Redirect URI (which must be pre-registered) and a state value, along with the other values passed in by the platform. The Redirect URI declares where the tool wants the subsequent LTI launch to go, and the state is what protects against CSRF. The state should be saved in a cookie, so the tool can verify that the initiator of the request is the same browser that sends the LTI message launch. If a cookie cannot work because of browser restrictions preventing setting of cookies by 3rd parties in iframes, then another option must be pursued. There is a new spec coming soon to help with that. - -The fields the tool must send back are: - -- response_type=id_token -- scope=open_id -- login_hint - that was passed in on the login request -- lti_message_hint - that was passed in on the login request -- state - a value the tool generates for protecting against CSRF -- nonce - a value the tool generates to protect against duplicate requests -- redirect_uri - a pre-registered URL the tool wants the subsequent LTI POST to be made -- client_id - the client ID of this registration - -#### Receive JWT - -The platform receives the OIDC authentication request from the tool and validates that the redirect URI is registered. It then builds the id_token (JWT) that contains the LTI payload (user, course, resource, etc.) and signs it with its private key. The platform then auto-submits a FORM with the POST method to the redirect URI the tool specified with two form parameters: - -- id_token - the JWT -- state - the state the tool passed to the platform in the OIDC login response - -The tool receives this FORM POST from the browser and the first thing it should do is validate the state is what it stored in the cookie. If it doesn't match the tool should reject the request. - -The next step is to unpack the JWT and validate the signature. JWTs are comprised of three Base64-encoded strings separated by the period (.) sign. The first part is the header which contains the key ID (kid) and signing algorithm. The second part is the payload in JSON format, and it contains the issuer (iss), client ID (aud), user ID (sub) and other information about the launch. The tool must look up the platform configuration for that issuer/client ID/deployment ID combination and get the platform's public key from the registered public key URL, using the kid in the JWT header for selecting the particular public key the platform requires. The third part is the signature, which normally the tool code won't work with directly. - -The tool then uses a library of their choosing to validate the signature of the JWT. If the signature is valid then the tool can proceed to process the rest of the JWT information and render its UI with the information it has about the LTI message. - -#### Optional Steps - -There are two optional steps in the sequence diagram above. - -##### Learn REST Token - -If your tool is going to use the Learn public REST API in order to get or set information it can't via LTI then it should retrive a Learn OAuth 2 access token at this time and cache it. There are choices as to what OAuth 2 flow you can use, so please refer to this document on how to [retrieve a Learn OAuth 2 access token](/docs/blackboard/rest-apis/getting-started/first-steps.md). In the diagram above we show using the AuthCode flow as its the most common for UI-based work where you want the API call to be done on behalf of the interacting user. See this document on using [three-legged oauth](/docs/blackboard/rest-apis/getting-started/3lo.md). - -##### LTI Rest Token - -If your tool wants to take advantage of the LTI services, such as Assignment & Grades, or Names & Roles, then you'll need to retrieve an LTI access token. This token is of a different format and uses a different security model than the Learn public API. - -You'll need to construct a signed (with your private key) JWT and post that to the OAuth 2 Token URL registered with the tool. If all is well you will receive an access token back, which you should cache, and use for making service calls back to Learn. We'll cover making service calls in a later section. - -## LTI Deep Linking - -LTI Deep Linking is a UI flow that allows a user, often an instructor, to launch from the platform to the tool, via the browser, and display a UI from the tool from which to select or create content that will end up back in the platform. For example, you may wish to include links to publisher content in the course outline. You may wish to embed an instructional video in the rich text editor of a discussion or assignment. You may wish to create an assignment via a plagiarism detection service and include that in a learning module. There are unlimited use cases for deep linking. The key point to understand is that it's about getting content from a 3rd party LTI provider into the Learning Management System of your choice. Rather than having an instructor copy and paste URLs the tool vendor provides, which is the old way of doing things, deep linking allows the instructor (or student, in the case of submitting an assignment or contributing to a discussion) to select content via the tool's browser-based UI. - -An LTI Deep Linking launch is much like a Resource Link launch, except the message type is different, and you receive an additional claim: `https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings` - -This claim contains information about what the platform accepts, and a data field that must be sent back. - -The tool then presents a UI allowing the user to select or create content the tool provides. It can be LTI links, web links, files, images, or html. Learn only supports LTI links and web links at the moment. - -You can return one or more content items, and depending on from where the tool was launched the links will appear in the course outline or the rich text editor. If returned to the rich text editor they can be displayed as hyperlinks or embedded in the editor. See [Deep Linking JSON](../deep-linking-two-json.md) for details on how to configure the rendering of LTI links in the rich text editor. diff --git a/docs/blackboard/lti/welcome.md b/docs/blackboard/lti/welcome.md new file mode 100644 index 000000000..7d487f20c --- /dev/null +++ b/docs/blackboard/lti/welcome.md @@ -0,0 +1,63 @@ +--- +title: "Getting started with LTI" +sidebar_position: 1 +id: welcome +published: "" +edited: "" +--- + +Learning Tools Interoperability (LTI) is a standard from the IMS Global consortium. This standard focuses on contextual launches and grade return, providing a way to send and retrieve this data without having to manually migrate the information from one service into the other. + +LTI has two different standards available, LTI 1.1 and LTI 1.3. Both can be used to integrate with an LMS and exchange information. + +:::danger LTI 1.1 support +LTI 1.1 has been deprecated by the IMS Global, and it's been around for over 10 years. Learn will continue support of LTI 1.1 tools for the indeterminate future while LTI 1.1 tool developers migrate their tool to LTI 1.3/Advantage. +::: + +:::caution +This documentation is focused on LTI 1.3/Advantage. If you are building a new tool, it is **_strongly recommended_** you use LTI 1.3/Advantage. +::: + +### What Specifically is LTI 1.3? + +Learning Tools Interoperability (LTI) 1.3 is the latest version of the LTI specification, which is a set of technical standards that enable learning management systems (LMSs) to integrate with external tools and content providers. LTI 1.3 builds upon the previous versions of LTI, adding new features and enhancements that improve the security, interoperability, and user experience of LTI integrations. + +Overall, LTI 1.3 is a significant improvement over previous versions of the specification, providing enhanced security, improved interoperability, a streamlined user experience, and easier implementation for developers. As a result, it has become the preferred version of LTI for many LMSs and external tool providers. + +### What are the Benefits of LTI 1.3? + +Here are some of the key features and benefits of LTI 1.3: + +**Enhanced security**: LTI 1.3 introduces new security features such as JSON Web Tokens (JWTs) and the OpenID Connect (OIDC) authentication protocol, which provide a more secure way to exchange user information between the LMS and external tools. This reduces the risk of unauthorized access to sensitive user data and improves the overall security of LTI integrations. + +**Improved interoperability**: LTI 1.3 introduces the Resource Link Launch Request (RLLR) message, which enables better communication between the LMS and external tools regarding the specific context of a learning activity. This makes it easier for external tools to integrate with the LMS and provide a seamless user experience. + +**Streamlined user experience**: LTI 1.3 introduces a new Deep Linking feature, which enables instructors to create links to specific resources within external tools and embed them directly within their course content. This makes it easier for students to access external tools and content without leaving the LMS environment, improving the overall user experience. + +**Easier implementation**: LTI 1.3 introduces a new Developer Key and Secret mechanism, which simplifies the process of creating and managing LTI integrations. This makes it easier for developers to implement LTI integrations and reduces the time and effort required to maintain them. + +## LTI 1.3/Advantage + +In addition to LTI 1.3, 1EdTech also has additional specifications for different services that can interact with the LMS, providing an all round integration for course items, grades and roster management. LTI Advantage consists of the following four specifications: + + 1. Core LTI 1.3 (also referenced as LTI 1.3) + 2. Deep Linking + 3. Names and Roles + 4. Assignments and Grades + +### Blackboard Learn support for LTI Advantage + +Blackboard Learn currently has full support for the two different integration versions over LTI, **LTI 1.1** and **LTI 1.3/Advantage** however, as mentioned above, we recommend migrating/creating new applications using LTI 1.3. LTI 1.1 is still supported but is not recommended. + +## Test code and tools + +1EdTech has prepared a test tool that you can use to test an LTI connection with an LMS, you can access it and follow the steps to review the workflow here: . The tool is written in Ruby and is open source, there're other LTI resources available from 1EdTech here: + +We also have a sample LTI tool written in React and Node.js that can be found here: + + +## Useful links + +- IMS Security Framework: +- LTI Advantage specifications: +- The implementation guide is very helpful as well diff --git a/docs/blackboard/lti/proctoring/ultra-proctoring-service-integration.md b/docs/blackboard/proctoring/ultra-proctoring-service-integration.md similarity index 100% rename from docs/blackboard/lti/proctoring/ultra-proctoring-service-integration.md rename to docs/blackboard/proctoring/ultra-proctoring-service-integration.md diff --git a/docs/blackboard/lti/proctoring/ultra-proctoring-service-tutorials.md b/docs/blackboard/proctoring/ultra-proctoring-service-tutorials.md similarity index 100% rename from docs/blackboard/lti/proctoring/ultra-proctoring-service-tutorials.md rename to docs/blackboard/proctoring/ultra-proctoring-service-tutorials.md diff --git a/docs/blackboard/standards-intro.md b/docs/blackboard/standards/Getting Started.md similarity index 92% rename from docs/blackboard/standards-intro.md rename to docs/blackboard/standards/Getting Started.md index c685565a7..e419b7ea4 100644 --- a/docs/blackboard/standards-intro.md +++ b/docs/blackboard/standards/Getting Started.md @@ -1,8 +1,8 @@ --- title: Welcome to the World of Standards! +id: getting-started sidebar_position: 1 author: Mark O'Neil -displayed_sidebar: documentationSidebar published: "" edited: "" --- @@ -39,8 +39,6 @@ Anthology supports many standards across our our product portfolio. Some of the **LIS**: Learning Information Services is a standard from [1EduTech](https://www.1edtech.org). Blackboard Learn's integration with LIS allows institutions to automate the exchange of academic and enrollment data between Blackboard Learn (LMS) and the institution's student information system (SIS). This integration can help to streamline administrative processes, reduce errors, and improve data accuracy and consistency. -**LTI**: Learning Tools Interoperability is a standard from [1EduTech](https://www.1edtech.org) for integrating third-party learning tools and applications into the LMS. Blackboard Learn supports LTI 1.1 and 1.3, which enables users to access and use external learning tools and resources from within the Blackboard Learn environment. - **SCORM**: Sharable Content Object Reference Model is a widely used standard for e-learning content interoperability. SCORM 1.2 and 2004, enable users to create, import, and deliver SCORM-compliant content within the Blackboard Learn LMS. Details are available at [SCORM.com](https://scorm.com) and [Rustici Software](https://rusticisoftware.com) **QTI**: Question and Test Interoperability is a standard from [1EduTech](https://www.1edtech.org) for creating and sharing assessment items and tests. Blackboard Learn supports QTI 1.2 and 2.1, which enables users to create and import QTI-compliant assessment content and deliver it within Blackboard Learn. diff --git a/docs/blackboard/caliper/getting-started/caliper-event-store-for-learn.md b/docs/blackboard/standards/caliper/caliper-event-store-for-learn.md similarity index 100% rename from docs/blackboard/caliper/getting-started/caliper-event-store-for-learn.md rename to docs/blackboard/standards/caliper/caliper-event-store-for-learn.md diff --git a/docs/blackboard/caliper/events/assessment-events.md b/docs/blackboard/standards/caliper/events/assessment-events.md similarity index 100% rename from docs/blackboard/caliper/events/assessment-events.md rename to docs/blackboard/standards/caliper/events/assessment-events.md diff --git a/docs/blackboard/caliper/events/assignable-events.md b/docs/blackboard/standards/caliper/events/assignable-events.md similarity index 100% rename from docs/blackboard/caliper/events/assignable-events.md rename to docs/blackboard/standards/caliper/events/assignable-events.md diff --git a/docs/blackboard/caliper/events/blog-events.md b/docs/blackboard/standards/caliper/events/blog-events.md similarity index 100% rename from docs/blackboard/caliper/events/blog-events.md rename to docs/blackboard/standards/caliper/events/blog-events.md diff --git a/docs/blackboard/caliper/events/calculated-grade-snapshot-events.md b/docs/blackboard/standards/caliper/events/calculated-grade-snapshot-events.md similarity index 100% rename from docs/blackboard/caliper/events/calculated-grade-snapshot-events.md rename to docs/blackboard/standards/caliper/events/calculated-grade-snapshot-events.md diff --git a/docs/blackboard/caliper/events/content-events.md b/docs/blackboard/standards/caliper/events/content-events.md similarity index 100% rename from docs/blackboard/caliper/events/content-events.md rename to docs/blackboard/standards/caliper/events/content-events.md diff --git a/docs/blackboard/caliper/events/course-group-events.md b/docs/blackboard/standards/caliper/events/course-group-events.md similarity index 100% rename from docs/blackboard/caliper/events/course-group-events.md rename to docs/blackboard/standards/caliper/events/course-group-events.md diff --git a/docs/blackboard/caliper/events/event-guide.md b/docs/blackboard/standards/caliper/events/event-guide.md similarity index 100% rename from docs/blackboard/caliper/events/event-guide.md rename to docs/blackboard/standards/caliper/events/event-guide.md diff --git a/docs/blackboard/caliper/events/forum-events.md b/docs/blackboard/standards/caliper/events/forum-events.md similarity index 100% rename from docs/blackboard/caliper/events/forum-events.md rename to docs/blackboard/standards/caliper/events/forum-events.md diff --git a/docs/blackboard/caliper/events/grade-events.md b/docs/blackboard/standards/caliper/events/grade-events.md similarity index 100% rename from docs/blackboard/caliper/events/grade-events.md rename to docs/blackboard/standards/caliper/events/grade-events.md diff --git a/docs/blackboard/caliper/events/lti-events.md b/docs/blackboard/standards/caliper/events/lti-events.md similarity index 100% rename from docs/blackboard/caliper/events/lti-events.md rename to docs/blackboard/standards/caliper/events/lti-events.md diff --git a/docs/blackboard/caliper/events/session-events.md b/docs/blackboard/standards/caliper/events/session-events.md similarity index 100% rename from docs/blackboard/caliper/events/session-events.md rename to docs/blackboard/standards/caliper/events/session-events.md diff --git a/docs/blackboard/caliper/events/view-events.md b/docs/blackboard/standards/caliper/events/view-events.md similarity index 100% rename from docs/blackboard/caliper/events/view-events.md rename to docs/blackboard/standards/caliper/events/view-events.md diff --git a/docs/blackboard/caliper/events/wiki-events.md b/docs/blackboard/standards/caliper/events/wiki-events.md similarity index 100% rename from docs/blackboard/caliper/events/wiki-events.md rename to docs/blackboard/standards/caliper/events/wiki-events.md diff --git a/docs/blackboard/caliper/getting-started/getting-started-with-caliper.md b/docs/blackboard/standards/caliper/getting-started-with-caliper.md similarity index 100% rename from docs/blackboard/caliper/getting-started/getting-started-with-caliper.md rename to docs/blackboard/standards/caliper/getting-started-with-caliper.md diff --git a/docs/blackboard/caliper/getting-started/metric-profiles.md b/docs/blackboard/standards/caliper/metric-profiles.md similarity index 98% rename from docs/blackboard/caliper/getting-started/metric-profiles.md rename to docs/blackboard/standards/caliper/metric-profiles.md index a01305b35..bfde60a94 100644 --- a/docs/blackboard/caliper/getting-started/metric-profiles.md +++ b/docs/blackboard/standards/caliper/metric-profiles.md @@ -15,7 +15,7 @@ the use of common tools across platforms with the added ability to analyze the usage of that tool for all students regardless of the environment that student originates from. -We also have documentation on the [specific events sent](../events/event-guide.md) by Learn, +We also have documentation on the [specific events sent](./events/event-guide.md) by Learn, The metric profiles are realized in the form of JSON for Linked Data (JSON-LD) payloads containing a set of common objects, each with the ability to add diff --git a/docs/blackboard/uef/getting-started.md b/docs/blackboard/uef/getting-started.md new file mode 100644 index 000000000..2d2886393 --- /dev/null +++ b/docs/blackboard/uef/getting-started.md @@ -0,0 +1,3 @@ +--- +id: uef-getting-started +--- diff --git a/docs/blackboard/premium-apis/requesting-premium-apis.md b/docs/blackboard/uef/requesting-premium-apis.md similarity index 87% rename from docs/blackboard/premium-apis/requesting-premium-apis.md rename to docs/blackboard/uef/requesting-premium-apis.md index 97100f418..7261d93e0 100644 --- a/docs/blackboard/premium-apis/requesting-premium-apis.md +++ b/docs/blackboard/uef/requesting-premium-apis.md @@ -21,12 +21,12 @@ UEF is a set of Premium APIs that augment the Ultra experience of Learn. We designed a robust set of capabilities such as telemetry, help provider registration, and UI element rendering to enable better integrations and richer user experience. -Take a look at [First steps with UEF](./uef/uef_getting_started.md) to get started. +Take a look at [First steps with UEF](./uef_getting_started.md) to get started. ## How to request a Premium API If you’re an Anthology client or a partner in Bronze level or above, -please [submit a Behind the Blackboard ticket](https://blackboard.secure.force.com/) +please [submit a Behind the Blackboard ticket](https://support.anthology.com/) and we’ll get back to you as soon as possible. If you’re a Blackboard Developer Network Partner (BbDN), a Community diff --git a/docs/blackboard/premium-apis/uef/tutorials/communication_page_lvl_analytics-id.md b/docs/blackboard/uef/tutorials/communication_page_lvl_analytics-id.md similarity index 100% rename from docs/blackboard/premium-apis/uef/tutorials/communication_page_lvl_analytics-id.md rename to docs/blackboard/uef/tutorials/communication_page_lvl_analytics-id.md diff --git a/docs/blackboard/premium-apis/uef/tutorials/configure-uef.md b/docs/blackboard/uef/tutorials/configure-uef.md similarity index 100% rename from docs/blackboard/premium-apis/uef/tutorials/configure-uef.md rename to docs/blackboard/uef/tutorials/configure-uef.md diff --git a/docs/blackboard/premium-apis/uef/tutorials/lti-to-uef-tutorial.md b/docs/blackboard/uef/tutorials/lti-to-uef-tutorial.md similarity index 100% rename from docs/blackboard/premium-apis/uef/tutorials/lti-to-uef-tutorial.md rename to docs/blackboard/uef/tutorials/lti-to-uef-tutorial.md diff --git a/docs/blackboard/premium-apis/uef/tutorials/lti_launch_context_added.md b/docs/blackboard/uef/tutorials/lti_launch_context_added.md similarity index 100% rename from docs/blackboard/premium-apis/uef/tutorials/lti_launch_context_added.md rename to docs/blackboard/uef/tutorials/lti_launch_context_added.md diff --git a/docs/blackboard/premium-apis/uef/tutorials/security-and-tokens.md b/docs/blackboard/uef/tutorials/security-and-tokens.md similarity index 100% rename from docs/blackboard/premium-apis/uef/tutorials/security-and-tokens.md rename to docs/blackboard/uef/tutorials/security-and-tokens.md diff --git a/docs/blackboard/premium-apis/uef/tutorials/tutorials-course-leftnav.md b/docs/blackboard/uef/tutorials/tutorials-course-leftnav.md similarity index 100% rename from docs/blackboard/premium-apis/uef/tutorials/tutorials-course-leftnav.md rename to docs/blackboard/uef/tutorials/tutorials-course-leftnav.md diff --git a/docs/blackboard/premium-apis/uef/tutorials/tutorials.md b/docs/blackboard/uef/tutorials/tutorials.md similarity index 94% rename from docs/blackboard/premium-apis/uef/tutorials/tutorials.md rename to docs/blackboard/uef/tutorials/tutorials.md index 819dae640..9258d6e1e 100644 --- a/docs/blackboard/premium-apis/uef/tutorials/tutorials.md +++ b/docs/blackboard/uef/tutorials/tutorials.md @@ -31,4 +31,4 @@ Add a course banner. [See this tutorial/demo video](https://youtu.be/pxddXC-I4UI ### Notice -Before releasing a UEF integration, that uses the UEF Premium APIs, to production you will be required to meet a certain level of Blackboard Partnership. See [Become a Blackboard Partner](../../../../partners/become-a-partner.md). +Before releasing a UEF integration, that uses the UEF Premium APIs, to production you will be required to meet a certain level of Blackboard Partnership. See [Become an Anthology Partner](../../../partners/become-a-partner.md). diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/downloads/demo-integration.zip b/docs/blackboard/uef/uef-documentation/downloads/demo-integration.zip similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/downloads/demo-integration.zip rename to docs/blackboard/uef/uef-documentation/downloads/demo-integration.zip diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/images/create_integration.png b/docs/blackboard/uef/uef-documentation/images/create_integration.png similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/images/create_integration.png rename to docs/blackboard/uef/uef-documentation/images/create_integration.png diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/images/create_placement.png b/docs/blackboard/uef/uef-documentation/images/create_placement.png similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/images/create_placement.png rename to docs/blackboard/uef/uef-documentation/images/create_placement.png diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/images/integration_workflow.png b/docs/blackboard/uef/uef-documentation/images/integration_workflow.png similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/images/integration_workflow.png rename to docs/blackboard/uef/uef-documentation/images/integration_workflow.png diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/images/manage_placements.png b/docs/blackboard/uef/uef-documentation/images/manage_placements.png similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/images/manage_placements.png rename to docs/blackboard/uef/uef-documentation/images/manage_placements.png diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/images/portal_workflow.png b/docs/blackboard/uef/uef-documentation/images/portal_workflow.png similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/images/portal_workflow.png rename to docs/blackboard/uef/uef-documentation/images/portal_workflow.png diff --git a/docs/blackboard/premium-apis/uef/uef-documentation/images/register_provider_domain.png b/docs/blackboard/uef/uef-documentation/images/register_provider_domain.png similarity index 100% rename from docs/blackboard/premium-apis/uef/uef-documentation/images/register_provider_domain.png rename to docs/blackboard/uef/uef-documentation/images/register_provider_domain.png diff --git a/docs/blackboard/premium-apis/uef/uef_getting_started.md b/docs/blackboard/uef/uef_getting_started.md similarity index 100% rename from docs/blackboard/premium-apis/uef/uef_getting_started.md rename to docs/blackboard/uef/uef_getting_started.md diff --git a/docs/blackboard/premium-apis/what-are-they.md b/docs/blackboard/uef/what-are-they.md similarity index 100% rename from docs/blackboard/premium-apis/what-are-they.md rename to docs/blackboard/uef/what-are-they.md diff --git a/docs/blackboard/welcome.md b/docs/blackboard/welcome.md new file mode 100644 index 000000000..89e820131 --- /dev/null +++ b/docs/blackboard/welcome.md @@ -0,0 +1,6 @@ +--- +title: Integrating with Blackboard Learn +id: welcome +--- + +Describe the different types of integration that are available with Blackboard Learn. Provide links to each one diff --git a/docs/developer-ami.md b/docs/developer-ami.md index 2d077dbb3..aa0bce716 100644 --- a/docs/developer-ami.md +++ b/docs/developer-ami.md @@ -1,7 +1,6 @@ --- title: Blackboard Learn Sandbox environment id: developer-ami -categories: AMI author: Mark O'Neil published: "2018-07-04" edited: "2024-07-26" @@ -9,7 +8,7 @@ edited: "2024-07-26" :::danger AMI availability -As of July 26th, 2024, the last available image is Blackboard Learn 3900.95.0 and will be the latest image available while we review and align the publishing process with Amazon Web Services. +As of July 26th, 2024, the last available image is Blackboard Learn 3900.93.0 and will be the latest image available while we review and align the publishing process with Amazon Web Services. Once the review is completed, we'll resume publishing with the latest version of Blackboard Learn as an Amazon Marketplace Image ::: diff --git a/src/Components/Solutions/Solutions.jsx b/src/Components/Solutions/Solutions.jsx index 707a475e9..6783d7a4e 100644 --- a/src/Components/Solutions/Solutions.jsx +++ b/src/Components/Solutions/Solutions.jsx @@ -15,7 +15,7 @@ const Solutions = () => { className={styles["solutions-card-override"]} imgSrc={`/img/blackboard-learn-${hasHydrated ? colorMode : "dark"}.svg`} message="Expand on our LMS' capabilities by using LTI and the API to create users, pull assessments, grade data, manage calendars, and more." - href='/docs/blackboard/rest-apis/start-here' + href='/docs/blackboard/welcome' /> { - const authorArray = []; - const authorNames = authorString.split(","); - authorNames.forEach((authorName) => { - if (authors[`${authorName.trim().toLowerCase()}`] === undefined) { - authorArray.push(authors["default"]); - } else { - authorArray.push(authors[`${authorName.trim().toLowerCase()}`]); - } - }); - - return authorArray; -}; - -const AuthorBox = (props) => { - /// Loads the author data based on the metadata of the document - let userData; - - if (props.frontMatter.author === undefined || props.frontMatter.author === "") - userData = getAuthorInfo("default"); - else userData = getAuthorInfo(props.frontMatter.author); - - /// Builds and returns the widget - return ( -
-

Contributors on this article:

-
- {userData.map((user) => { - return ( - - ); - })} -
-
- ); -}; - -export default AuthorBox; diff --git a/src/modules/AuthorBox/AuthorBox.module.css b/src/modules/AuthorBox/AuthorBox.module.css deleted file mode 100644 index 3ea6877c5..000000000 --- a/src/modules/AuthorBox/AuthorBox.module.css +++ /dev/null @@ -1,164 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"); - -.author-container { - margin-top: 3rem; - border-top: solid 1px #414141; - padding-top: 2rem; - font-family: "Montserrat", sans-serif; -} - -.author-cards { - margin-top: 1.5rem; - display: flex; - flex-wrap: wrap; - gap: 1rem; -} - -.author-outer { - position: relative; - overflow: hidden; - width: 14rem; - min-height: 20rem; - background-color: light-dark(#fafafa, #1b1b1d); - border: solid 1px #414141; - border-radius: 20px; -} - -.author-background-pic { - width: 100%; - height: 6rem; - object-fit: cover; - border-bottom: solid 1px #000000; -} - -.author-profile-pic { - width: 7rem; - height: 7rem; - position: absolute; - z-index: 10; - transform: translateX(-150%) translateY(35%); - border-radius: 1rem; - border: dotted 1px #414141; - filter: drop-shadow(0px 0px 4px #00000033); -} - -.author-profile-default { - padding: 1rem; - background-color: #000000; -} - -.author-data { - display: flex; - flex-direction: column; - align-items: center; - width: 100%; - text-align: center; - margin-top: 3.5rem; - margin-bottom: 4rem; -} - -.author-name { - font-weight: 700; - padding: 0; - margin: 0; - font-size: 1.2rem; -} - -.author-title { - padding: 0; - margin: 0; - margin-top: -0.2rem; - font-weight: 400; - font-size: 0.9rem; -} - -.author-area { - padding: 0; - margin: 0; - margin-top: 0.5rem; - text-align: center; - text-wrap: balance; - font-size: 0.8rem; - width: 95%; - color: light-dark(#1c1e2177, #e3e3e366); -} - -.social-links { - width: 100%; - display: flex; - justify-content: center; - padding-top: 0.6rem; - position: absolute; - bottom: 1rem; -} - -.github-logo { - display: flex; - align-items: center; - justify-content: center; - width: 2.4rem; - height: 2.4rem; - background-color: #d9d9d9; - border-radius: 50%; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.15) inset; -} - -.github-logo img { - width: 2.2rem; - height: 2.2rem; -} - -@media (max-width: 520px) { - .author-outer { - width: 11rem; - min-height: 14rem; - } - - .author-background-pic { - width: 100%; - height: 6rem; - } - - .author-profile-pic { - transform: translateX(-128.5%) translateY(35%); - } - - .author-name { - font-size: 1.2rem; - } - - .author-title { - font-size: 0.9rem; - } - - .author-area { - font-size: 0.8rem; - } -} - -@media (max-width: 415px) { - .author-outer { - width: 10rem; - min-height: 14rem; - } - - .author-background-pic { - width: 100%; - height: 6rem; - } - - .author-profile-pic { - transform: translateX(-121%) translateY(35%); - } - .author-name { - font-size: 1rem; - } - - .author-title { - font-size: 0.8rem; - } - - .author-area { - font-size: 0.75rem; - } -} diff --git a/src/modules/AuthorBox/OldVersions/AuthorBox.jsx b/src/modules/AuthorBox/OldVersions/AuthorBox.jsx deleted file mode 100644 index 559540ab7..000000000 --- a/src/modules/AuthorBox/OldVersions/AuthorBox.jsx +++ /dev/null @@ -1,82 +0,0 @@ -import React from "react"; -import styles from "./AuthorBox.module.css"; -import authors from "../authorInfo.json"; -import { useColorMode } from "@docusaurus/theme-common"; -import useIsBrowser from "@docusaurus/useIsBrowser"; - -const getAuthorInfo = (authorString) => { - const authorArray = []; - const authorNames = authorString.split(","); - authorNames.forEach((authorName) => { - if (authors[`${authorName.trim().toLowerCase()}`] === undefined) { - authorArray.push(authors["default"]); - } else { - authorArray.push(authors[`${authorName.trim().toLowerCase()}`]); - } - }); - - return authorArray; -}; - -const AuthorCard = (user, index) => { - const { colorMode } = useColorMode(); - const hasHydrated = useIsBrowser(); - - const userProfilePic = - user.img === undefined || user.img === "" - ? "/img/author-default-picture.png" - : user.img; - - const profileStyles = - user.img === undefined || user.img === "" - ? `${styles["author-profile-pic"]} ${styles["author-profile-default"]}` - : `${styles["author-profile-pic"]}`; - return ( -
- Background image of the author card - Profile picture of the author -
-

{user.name}

-

{user.role}

-

{user.area}

-
- -
- ); -}; - -const AuthorBox = (props) => { - let userData; - - if (props.frontMatter.author === undefined || props.frontMatter.author === "") - userData = getAuthorInfo("default"); - else userData = getAuthorInfo(props.frontMatter.author); - - userData.map((authorInfo) => AuthorCard(authorInfo)); - return ( -
-

Contributors on this article:

-
- {userData.map((authorInfo, index) => AuthorCard(authorInfo, index))} -
-
- ); -}; - -export default AuthorBox; diff --git a/src/modules/AuthorBox/OldVersions/AuthorBox.module.css b/src/modules/AuthorBox/OldVersions/AuthorBox.module.css deleted file mode 100644 index 3ea6877c5..000000000 --- a/src/modules/AuthorBox/OldVersions/AuthorBox.module.css +++ /dev/null @@ -1,164 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"); - -.author-container { - margin-top: 3rem; - border-top: solid 1px #414141; - padding-top: 2rem; - font-family: "Montserrat", sans-serif; -} - -.author-cards { - margin-top: 1.5rem; - display: flex; - flex-wrap: wrap; - gap: 1rem; -} - -.author-outer { - position: relative; - overflow: hidden; - width: 14rem; - min-height: 20rem; - background-color: light-dark(#fafafa, #1b1b1d); - border: solid 1px #414141; - border-radius: 20px; -} - -.author-background-pic { - width: 100%; - height: 6rem; - object-fit: cover; - border-bottom: solid 1px #000000; -} - -.author-profile-pic { - width: 7rem; - height: 7rem; - position: absolute; - z-index: 10; - transform: translateX(-150%) translateY(35%); - border-radius: 1rem; - border: dotted 1px #414141; - filter: drop-shadow(0px 0px 4px #00000033); -} - -.author-profile-default { - padding: 1rem; - background-color: #000000; -} - -.author-data { - display: flex; - flex-direction: column; - align-items: center; - width: 100%; - text-align: center; - margin-top: 3.5rem; - margin-bottom: 4rem; -} - -.author-name { - font-weight: 700; - padding: 0; - margin: 0; - font-size: 1.2rem; -} - -.author-title { - padding: 0; - margin: 0; - margin-top: -0.2rem; - font-weight: 400; - font-size: 0.9rem; -} - -.author-area { - padding: 0; - margin: 0; - margin-top: 0.5rem; - text-align: center; - text-wrap: balance; - font-size: 0.8rem; - width: 95%; - color: light-dark(#1c1e2177, #e3e3e366); -} - -.social-links { - width: 100%; - display: flex; - justify-content: center; - padding-top: 0.6rem; - position: absolute; - bottom: 1rem; -} - -.github-logo { - display: flex; - align-items: center; - justify-content: center; - width: 2.4rem; - height: 2.4rem; - background-color: #d9d9d9; - border-radius: 50%; - box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.15) inset; -} - -.github-logo img { - width: 2.2rem; - height: 2.2rem; -} - -@media (max-width: 520px) { - .author-outer { - width: 11rem; - min-height: 14rem; - } - - .author-background-pic { - width: 100%; - height: 6rem; - } - - .author-profile-pic { - transform: translateX(-128.5%) translateY(35%); - } - - .author-name { - font-size: 1.2rem; - } - - .author-title { - font-size: 0.9rem; - } - - .author-area { - font-size: 0.8rem; - } -} - -@media (max-width: 415px) { - .author-outer { - width: 10rem; - min-height: 14rem; - } - - .author-background-pic { - width: 100%; - height: 6rem; - } - - .author-profile-pic { - transform: translateX(-121%) translateY(35%); - } - .author-name { - font-size: 1rem; - } - - .author-title { - font-size: 0.8rem; - } - - .author-area { - font-size: 0.75rem; - } -} diff --git a/src/modules/AuthorBox/components/AuthorCard.jsx b/src/modules/AuthorBox/components/AuthorCard.jsx deleted file mode 100644 index 343561bc9..000000000 --- a/src/modules/AuthorBox/components/AuthorCard.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from "react"; -import { useColorMode } from "@docusaurus/theme-common"; -import styles from "./AuthorCard.module.css"; -import clsx from "clsx"; -import useIsBrowser from "@docusaurus/useIsBrowser"; - -const AuthorCard = ({ avatar, name, position, area }) => { - const { colorMode } = useColorMode(); - const hasHydrated = useIsBrowser(); - - return ( -
-
- Profile picture of the contributor -
-
-

{name}

- {position} - {area} -
-
- ); -}; - -export default AuthorCard; diff --git a/src/modules/AuthorBox/components/AuthorCard.module.css b/src/modules/AuthorBox/components/AuthorCard.module.css deleted file mode 100644 index 0a3e565eb..000000000 --- a/src/modules/AuthorBox/components/AuthorCard.module.css +++ /dev/null @@ -1,66 +0,0 @@ -.author-wrapper { - width: 15rem; - display: flex; - flex-direction: column; - align-items: center; -} - -.author-avatar { - width: 5rem; - height: 5rem; - border-radius: 50%; - overflow: hidden; -} - -.author-avatar-dropshadow-light { - -webkit-box-shadow: 0px 0px 29px 0px rgba(36, 36, 36, 0.44); - -moz-box-shadow: 0px 0px 29px 0px rgba(36, 36, 36, 0.44); - box-shadow: 0px 0px 29px 0px rgba(36, 36, 36, 0.44); -} - -.author-avatar-dropshadow-dark { - -webkit-box-shadow: 0px 0px 29px 0px rgba(217, 217, 217, 0.44); - -moz-box-shadow: 0px 0px 29px 0px rgba(217, 217, 217, 0.44); - box-shadow: 0px 0px 29px 0px rgba(217, 217, 217, 0.44); -} - -.author-info { - color: #fff; - width: 100%; - height: 7.5rem; - padding: 1.5rem 1rem 0.5rem 1rem; - transform: translateY(-1rem); - z-index: -1; - display: flex; - flex-direction: column; - text-align: center; - align-items: center; - border-radius: 1rem; - align-content: stretch; -} - -.author-info-dropshadow { - background: linear-gradient( - 240deg, - var(--custom-anth-author-light) 20%, - var(--custom-anth-author-dark) 20% - ); -} - -.author-info h3 { - font-size: 1rem; - margin-bottom: 0.3rem; -} - -.author-info span { - font-size: 0.8rem; - font-weight: 600; - color: #fffc; -} - -.author-info span:last-child { - max-width: 10rem; - font-size: 0.75rem; - margin-bottom: 0.3rem; - color: #fff5; -} diff --git a/src/sidebar.js b/src/sidebar.js index 35dacbe65..3f6a23098 100644 --- a/src/sidebar.js +++ b/src/sidebar.js @@ -21,12 +21,10 @@ const sidebars = { // documentationSidebar: documentationSidebar: [ + /// Developer Portal { - // Developer Portal type: "category", label: "Developer Portal", - collapsible: true, - // collapsed: true, items: [ { type: "autogenerated", @@ -34,28 +32,21 @@ const sidebars = { }, ], }, - // Blackboard + /// Blackboard { - type: "category", - label: "Blackboard Learn", - collapsible: true, - collapsed: true, - items: [ - "blackboard/rest-apis/start-here", - "blackboard/rest-apis/rest-api-best-practices", - // Rest APIs + "Blackboard Learn": [ + "blackboard/welcome", + /// Rest APIs { - type: "category", - label: "REST APIs", - collapsible: true, - // collapsed: true, - items: [ + "REST APIs": [ // Getting Started + "blackboard/rest-apis/start-here", + "blackboard/rest-apis/rest-api-best-practices", { type: "category", label: "Getting Started", - collapsible: true, - // collapsed: true, + + // items: [ { type: "autogenerated", @@ -67,8 +58,8 @@ const sidebars = { { type: "category", label: "Hands on", - collapsible: true, - // collapsed: true, + + // items: [ { type: "autogenerated", @@ -80,8 +71,8 @@ const sidebars = { { type: "category", label: "Advanced", - collapsible: true, - // collapsed: true, + + // items: [ { type: "autogenerated", @@ -93,8 +84,7 @@ const sidebars = { { type: "category", label: "Demo code", - collapsible: true, - collapsed: true, + items: [ { type: "autogenerated", @@ -104,86 +94,113 @@ const sidebars = { }, ], }, + /// LTI { - type: "category", - label: "LTI", - collapsible: true, - // collapsed: true, - items: [ - "blackboard/lti/introduction", - "blackboard/lti/getting-started-with-lti", - "blackboard/lti/lti-registration-deployment", - "blackboard/lti/registration-deployment", - "blackboard/lti/lti-deep-linking", - "blackboard/lti/turn-on-all-switches", - { - type: "category", - label: "Core", - collapsible: true, - items: [ - { - type: "autogenerated", - dirName: "blackboard/lti/core", // Generate sidebar slice from docs path - }, - ], - }, - { - type: "category", - label: "Migrating", - collapsible: true, - items: [ - { - type: "autogenerated", - dirName: "blackboard/lti/migrating", // Generate sidebar slice from docs path - }, - ], - }, + LTI: [ + "blackboard/lti/welcome", { - type: "category", - label: "Proctoring", - collapsible: true, - items: [ + "LTI 1.3/Advantage": [ + "blackboard/lti/1.3/register-an-application", { - type: "autogenerated", - dirName: "blackboard/lti/proctoring", // Generate sidebar slice from docs path + "Core LTI 1.3": [ + { + type: "autogenerated", + dirName: "blackboard/lti/1.3/core", + }, + ], + "Deep Linking": [ + { + type: "autogenerated", + dirName: "blackboard/lti/1.3/dl", + }, + ], + "Assignments and Grades Service": [ + { + type: "autogenerated", + dirName: "blackboard/lti/1.3/ags", + }, + ], + "Names and Roles Provisioning Service": [ + { + type: "autogenerated", + dirName: "blackboard/lti/1.3/nrps", + }, + ], }, + "blackboard/lti/1.3/best-practices", ], - }, - { - type: "category", - label: "Tutorials", - collapsible: true, - items: [ + "LTI 1.1": [ { type: "autogenerated", - dirName: "blackboard/lti/tutorials", // Generate sidebar slice from docs path + dirName: "blackboard/lti/1.1", }, ], }, ], }, - // Premium APIs + /// UEF + // { + // UEF: [ + // "blackboard/uef/uef-getting-started", + // // "blackboard/premium-apis/requesting-premium-apis", + // // { + // // type: "category", + // // label: "UEF", + // // + // // items: [ + // // "blackboard/premium-apis/uef/getting-started", + // // { + // // type: "autogenerated", + // // dirName: "blackboard/premium-apis/uef/tutorials", // Generate sidebar slice from docs path + // // }, + // // { + // // type: "link", + // // label: "UEF Documentation", + // // href: "https://docs.anthology.com/uef-documentation/start.html", + // // }, + // // ], + // // }, + // ], + // }, + // /// Proctoring + // { + // Proctoring: [ + // "blackboard/premium-apis/requesting-premium-apis", + // { + // type: "category", + // label: "UEF", + + // items: [ + // "blackboard/premium-apis/uef/getting-started", + // { + // type: "autogenerated", + // dirName: "blackboard/premium-apis/uef/tutorials", // Generate sidebar slice from docs path + // }, + // { + // type: "link", + // label: "UEF Documentation", + // href: "https://docs.anthology.com/uef-documentation/start.html", + // }, + // ], + // }, + // ], + // }, + /// Standards { - type: "category", - label: "Premium APIs", - collapsible: true, - // collapsed: true, - items: [ - "blackboard/premium-apis/requesting-premium-apis", + "Other Standards": [ + "blackboard/standards/getting-started", { - type: "category", - label: "UEF", - collapsible: true, - items: [ - "blackboard/premium-apis/uef/getting-started", - { - type: "autogenerated", - dirName: "blackboard/premium-apis/uef/tutorials", // Generate sidebar slice from docs path - }, + Caliper: [ + "blackboard/standards/caliper/getting-started", + "blackboard/standards/caliper/event-store-in-learn", + "blackboard/standards/caliper/metric-profiles", { - type: "link", - label: "UEF Documentation", - href: "https://docs.anthology.com/uef-documentation/start.html", + Events: [ + { + type: "autogenerated", + dirName: "blackboard/standards/caliper/events", + }, + ], }, ], }, @@ -196,13 +213,13 @@ const sidebars = { { type: "category", label: "Student", - collapsible: true, - // collapsed: true, + + // items: [ { type: "category", label: "Getting Started", - collapsible: true, + items: [ { type: "autogenerated", @@ -213,7 +230,7 @@ const sidebars = { { type: "category", label: "Best Practices", - collapsible: true, + items: [ { type: "autogenerated", @@ -224,7 +241,7 @@ const sidebars = { { type: "category", label: "Service Catalog", - collapsible: true, + items: [ { type: "autogenerated", @@ -243,8 +260,8 @@ const sidebars = { { type: "category", label: "Ally", - collapsible: true, - // collapsed: true, + + // items: [ { type: "autogenerated", @@ -256,8 +273,8 @@ const sidebars = { { type: "category", label: "Partners", - collapsible: true, - // collapsed: true, + + // items: [ { type: "autogenerated", @@ -269,8 +286,8 @@ const sidebars = { { type: "category", label: "Community", - collapsible: true, - // collapsed: true, + + // items: [ { type: "autogenerated", diff --git a/src/theme/DocItem/Content/index.js b/src/theme/DocItem/Content/index.js index 6248aa25c..234ac653e 100644 --- a/src/theme/DocItem/Content/index.js +++ b/src/theme/DocItem/Content/index.js @@ -5,7 +5,6 @@ import { useDoc } from "@docusaurus/theme-common/internal"; import Heading from "@theme/Heading"; import MDXContent from "@theme/MDXContent"; import VersioningTracker from "../../../modules/VersioningTracker/VersioningTracker"; -import AuthorBox from "../../../modules/AuthorBox/AuthorBox"; /** Title can be declared inside md content or declared through front matter and added manually. To make both cases consistent, @@ -42,11 +41,6 @@ export default function DocItemContent({ children }) { )} {children} - {frontMatter.id !== "site-intro" ? ( - - ) : ( - "" - )} ); } diff --git a/src/theme/MDXComponents.js b/src/theme/MDXComponents.js index fd8b498d6..661e6ea22 100644 --- a/src/theme/MDXComponents.js +++ b/src/theme/MDXComponents.js @@ -1,7 +1,6 @@ import React from "react"; // Import the original mapper import MDXComponents from "@theme-original/MDXComponents"; -import AuthorBox from "../modules/AuthorBox/AuthorBox"; import VersioningTracker from "../modules/VersioningTracker/VersioningTracker"; import PasswordChecker from "../modules/PasswordChecker/PasswordChecker"; // import Card from "../pages/Components/Card/Card"; @@ -14,7 +13,6 @@ export default { ...MDXComponents, // Map the "" tag to our Highlight component // `Highlight` will receive all props that were passed to `` in MDX - AuthorBox, VersioningTracker, PasswordChecker, // Card, diff --git a/static/assets/img/lti-launch-sequence-idtoken.png b/static/assets/img/lti-launch-sequence-idtoken.png new file mode 100644 index 000000000..327b11773 Binary files /dev/null and b/static/assets/img/lti-launch-sequence-idtoken.png differ diff --git a/static/assets/img/lti-launch-sequence-oidc.png b/static/assets/img/lti-launch-sequence-oidc.png new file mode 100644 index 000000000..5617691d8 Binary files /dev/null and b/static/assets/img/lti-launch-sequence-oidc.png differ diff --git a/widgets/authorInfo.json b/widgets/authorInfo.json deleted file mode 100644 index d94932ee4..000000000 --- a/widgets/authorInfo.json +++ /dev/null @@ -1,142 +0,0 @@ -{ - "default": { - "img": "", - "name": "Anthology Inc", - "role": "Integrations, Developer Relations and Standards Team", - "area": "Anthology Inc", - "github": "blackboard" - }, - "eric preston": { - "img": "https://avatars.githubusercontent.com/u/539286?v=4", - "name": "Eric Preston", - "role": "Former Staff Software Engineer", - "area": "Integrations, Developer Relations and Standards", - "github": "ewpreston" - }, - "davey herrera": { - "img": "https://avatars.githubusercontent.com/u/2322778?v=4", - "name": "Davey Herrera", - "role": "Software Engineer", - "area": "Integrations, Developer Relations and Standards", - "github": "daveyherrera" - }, - "mark o'neil": { - "img": "https://avatars.githubusercontent.com/u/5400309?v=4", - "name": "Mark O'Neil", - "role": "Former Director", - "area": "Platform and APIs", - "github": "moneil" - }, - "sebastian silva": { - "img": "https://avatars.githubusercontent.com/u/44152511?v=4", - "name": "Sebastian Silva", - "role": "Software Engineer", - "area": "Integrations, Developer Relations and Standards", - "github": "onecomputerguy" - }, - "scott hurrey": { - "img": "https://avatars.githubusercontent.com/u/886516?v=4", - "name": "Scott Hurrey", - "role": "Former Director", - "area": "Integrations, Developer Relations and Standards", - "github": "shurrey" - }, - "mark kauffman": { - "img": "https://avatars.githubusercontent.com/u/10159872?v=4", - "name": "Mark Kauffman", - "role": "Sr. Software Engineer", - "area": "Integrations, Developer Relations and Standards", - "github": "mark-b-kauffman" - }, - "kelley macewen": { - "img": "", - "name": "Kelley MacEwen", - "role": "Former Sr. Content Designer", - "area": "Blackboard Learn - Content Team", - "github": "blackboard" - }, - "hernan ortiz": { - "img": "https://avatars.githubusercontent.com/u/10201569?v=4", - "name": "Hernan Ortiz", - "role": "Former Sr. Content Designer", - "area": "Integrations, Developer Relations and Standards", - "github": "hernanpl" - }, - "darek sady": { - "img": "https://avatars.githubusercontent.com/u/36425568?v=4", - "name": "Darek Sady", - "role": "Former Director", - "area": "Teaching and Learning", - "github": "dareksady" - }, - "simon gaeremynck": { - "img": "https://avatars.githubusercontent.com/u/63703963?v=4", - "name": "Simon Gaeremynck", - "role": "Software Engineer", - "area": "Product Development Blackboard Learn", - "github": "bbsimong" - }, - "ryan haber": { - "img": "https://avatars.githubusercontent.com/u/10554169?v=4", - "name": "Ryan Haber", - "role": "Sr. Content Designer", - "area": "Content Team - Blackboard Learn", - "github": "ryanhaber" - }, - "gokulakrishnan raman": { - "img": "", - "name": "Gokulakrishnan Raman", - "role": "Software Engineer", - "area": "Product Development Blackboard Learn", - "github": "blackboard" - }, - "subitha muniasamy": { - "img": "", - "name": "Subitha Muniasamy", - "role": "Sr. Software Engineer", - "area": "Product Development Blackboard Learn", - "github": "blackboard" - }, - "sara lehnert": { - "img": "", - "name": "Sara Lehnert", - "role": "Sr. Partner Manager", - "area": "Business Development Team", - "github": "blackboard" - }, - "vikas gupta": { - "img": "https://avatars.githubusercontent.com/u/3923532?v=4", - "name": "Vikas Gupta", - "role": "Director", - "area": "Integration Architecture, Developer Relations & Partner Support", - "github": "guptavikasgupta" - }, - "jim burns": { - "img": "", - "name": "Jim Burns", - "role": "Senior Application Architect", - "area": "Anthology Student", - "github": "jburns54712" - }, - "dan magers": { - "img": "", - "name": "Daniel Magers", - "role": "Sr. Technical Writer", - "area": "Product Development Blackboard Learn", - "github": "jburns54712" - }, - "camilo dominguez": { - "img": "", - "name": "Camilo Dominguez", - "role": "Product Manager", - "area": "Developer Portal and REST APIs", - "github": "blackboard" - }, - "daniel nieto": { - "img": "https://avatars.githubusercontent.com/u/91549595?v=4", - "name": "Daniel Nieto", - "role": "Software Engineer in Test", - "area": "Developer Relations and Standards/Devportal", - "github": "dnietoBlackBoard" - } -}