> ## Documentation Index
> Fetch the complete documentation index at: https://docs.veydra.io/llms.txt
> Use this file to discover all available pages before exploring further.

# LMS Integration

> Connect Veydra to your Learning Management System with LTI 1.3

## Overview

Veydra supports **LTI 1.3** (Learning Tools Interoperability), the industry standard for connecting learning tools to Learning Management Systems. Once configured, students can launch Veydra labs directly from their LMS course — no separate login required.

<Info>
  LTI 1.3 is an [IMS Global standard](https://www.imsglobal.org/activity/learning-tools-interoperability) supported by virtually every modern LMS including Moodle, Canvas, Blackboard, Brightspace, Sakai, Schoology, and Open edX.
</Info>

### How It Works

When a student clicks a Veydra activity in their LMS:

1. The LMS sends a secure, signed request to Veydra (OIDC login + JWT)
2. Veydra verifies the request and identifies the student
3. A Veydra account is automatically created (or linked) for the student
4. The student is granted access to the assigned lab with the configured role
5. The student lands directly in the lab — no additional sign-up needed

### Supported LMS Platforms

<CardGroup cols={3}>
  <Card title="Moodle" icon="graduation-cap">
    Full LTI 1.3 support with auto-fill configuration
  </Card>

  <Card title="Canvas" icon="chalkboard">
    Instructure Canvas with Developer Key integration
  </Card>

  <Card title="Blackboard" icon="building-columns">
    Blackboard Learn Ultra with REST API integration
  </Card>

  <Card title="D2L Brightspace" icon="sun">
    Brightspace with standard LTI Advantage
  </Card>

  <Card title="Sakai" icon="book-open">
    Open-source LMS with LTI 1.3 support
  </Card>

  <Card title="Schoology" icon="school">
    PowerSchool Schoology LTI 1.3 apps
  </Card>
</CardGroup>

Additional platforms: **Open edX** and **OLI Torus** are also supported with built-in auto-fill presets.

***

## Prerequisites

Before configuring LTI:

<Check>You have a Veydra account with lab management permissions</Check>
<Check>You have at least one lab created in Veydra (Account → Manage Labs)</Check>
<Check>You have administrator access to your LMS</Check>
<Check>Your LMS supports **LTI 1.3** (not the older LTI 1.1)</Check>

***

## Step 1: Get Your Tool Configuration

Every Veydra account has a set of public URLs that you'll enter into your LMS. These identify Veydra as an external tool provider.

<Steps>
  <Step title="Open LTI Integrations">
    Sign in at [app.veydra.io](https://app.veydra.io) and go to **Account → LTI Integrations** in the sidebar (under the Labs section).
  </Step>

  <Step title="Copy the Tool Configuration URLs">
    At the top of the page you'll see the **Your Tool Configuration** card with four values:

    | Field                        | Description                                     | Example                            |
    | ---------------------------- | ----------------------------------------------- | ---------------------------------- |
    | **Tool URL / Launch URL**    | Where the LMS sends the launch request          | `https://api.veydra.io/lti/launch` |
    | **Login Initiation URL**     | Where the LMS begins the OIDC flow              | `https://api.veydra.io/lti/login`  |
    | **Redirect URI(s)**          | Allowed redirect targets after login            | `https://api.veydra.io/lti/launch` |
    | **Public Keyset URL (JWKS)** | Veydra's public keys for signature verification | `https://api.veydra.io/lti/jwks`   |

    Use the **Copy** button next to each value.
  </Step>
</Steps>

<Tip>
  These URLs are the same for every platform registration — you only need to copy them once.
</Tip>

***

## Step 2: Register Veydra in Your LMS

This step happens inside your LMS admin panel. The exact steps vary by platform — choose your LMS below:

<AccordionGroup>
  <Accordion icon="graduation-cap" title="Moodle">
    1. Go to **Site administration → Plugins → Activity modules → External tool → Manage tools**
    2. Click **configure a tool manually**
    3. Fill in:
       * **Tool name**: `Veydra` (or any name you prefer)
       * **Tool URL**: paste the **Tool URL / Launch URL** from Veydra
       * **LTI version**: select **LTI 1.3**
       * **Public key type**: select **Keyset URL**
       * **Public keyset**: paste the **Public Keyset URL (JWKS)** from Veydra
       * **Initiate login URL**: paste the **Login Initiation URL** from Veydra
       * **Redirection URI(s)**: paste the **Redirect URI(s)** from Veydra
    4. Under **Tool configuration usage**, select **Show as preconfigured tool when adding an external tool**
    5. Click **Save changes**
    6. Moodle will display the tool's configuration details — **copy the Client ID** (you'll need it in Step 3)

    <Note>
      You can also find the Client ID later by clicking "View configuration details" on the tool's entry in the Manage tools list.
    </Note>
  </Accordion>

  <Accordion icon="chalkboard" title="Canvas">
    <Warning>
      Do NOT use "Add App → By LTI 2 Registration URL" in Canvas — that uses the deprecated LTI 2.0 protocol. Use the Developer Key method below instead.
    </Warning>

    **Step 1: Create Developer Key**

    1. Go to **Admin → Developer Keys** (at the root account level)
    2. Click **+ Developer Key → + LTI Key**
    3. Choose **Enter URL** and paste Veydra's **Dynamic Registration URL** (shown in Veydra's LTI Integrations page)
    4. Click **Save** — Canvas auto-fills most settings from the URL

    **Step 2: Configure Privacy & User Data (Required)**

    1. Click **Edit** on the newly created key
    2. Expand **Additional Settings** and configure:
       * Set **Privacy Level** to **Public** (enables sharing of user names and email addresses)
       * In the **Custom Fields** box, paste the following lines to explicitly map user data:
         ```
         email=$Person.email.primary
         name=$Person.name.full
         given_name=$Person.name.given
         family_name=$Person.name.family
         ```
    3. Expand **LTI Advantage Services** and enable:
       * "Can retrieve user data associated with the context the tool is installed in"
       * *(Optional for grades)* "Can create and view assignment data in the gradebook associated with the tool"
       * *(Optional for grades)* "Can create and update submission results for assignments associated with the tool"

    <Note>
      Veydra requires user email to create accounts. Without the Privacy Level set to Public and Custom Fields configured, students will see an error when launching.
    </Note>

    **Step 3: Configure Placements (Enable Deep Linking)**

    1. Scroll to **Placements** and add at least one:
       * **Link Selection** — allows instructors to select Veydra content when adding module items
       * **Assignment Selection** — allows instructors to select Veydra content when creating assignments
    2. For each placement, set:
       * **Target Link URI**: `https://api.veydra.io/lti/launch`
       * **Message Type**: `LtiDeepLinkingRequest`
       * *(Optional)* **Icon URL**: `https://app.veydra.io/favicon.png`
    3. Click **Save**

    **Step 4: Enable and Install**

    1. Toggle the key's **State** to **ON**
    2. Copy the **Client ID** (long number like `10000000000123`)
    3. Go to your **Course → Settings → Apps → + App**
    4. Select **By Client ID**, paste the ID, and click **Submit**

    **Step 5: Register in Veydra**

    1. Return to Veydra's **Account → LTI Integrations** page
    2. Click **Register Platform**, select **Canvas**, enter your Canvas URL and the Client ID
    3. Click **Register Platform**

    <Tip>
      After installation, instructors can add Veydra content by going to **Modules → + → External Tool → Veydra** or **Assignments → + Assignment → External Tool**. A content picker will appear showing available activities.
    </Tip>
  </Accordion>

  <Accordion icon="building-columns" title="Blackboard Learn (Ultra)">
    1. Go to **System Admin → Integrations → LTI Tool Providers → Register LTI 1.3 Tool**
    2. Enter the **Client ID** (you may need to register the application first via the Developer Portal to obtain one)
    3. Fill in:
       * **Tool Provider URL**: paste the **Tool URL / Launch URL**
       * **Login Initiation URL**: paste the **Login Initiation URL**
       * **Tool Redirect URL(s)**: paste the **Redirect URI(s)**
       * **Tool JWKS URL**: paste the **Public Keyset URL (JWKS)**
    4. Set **Tool Status** to **Approved**
    5. Copy the **Client ID** and **Deployment ID** shown in the confirmation

    <Warning>
      Blackboard's exact admin screens differ between Original and Ultra experiences. The steps above follow the Ultra workflow.
    </Warning>
  </Accordion>

  <Accordion icon="sun" title="D2L Brightspace">
    1. Go to **Manage Extensibility → LTI Advantage** (or **External Learning Tools → Manage Tool Providers**)
    2. Click **New Registration / Register Tool**
    3. Fill in:
       * **Name**: `Veydra`
       * **Domain**: `api.veydra.io`
       * **Redirect URLs**: paste the **Redirect URI(s)**
       * **OpenID Connect Login URL**: paste the **Login Initiation URL**
       * **Keyset URL**: paste the **Public Keyset URL (JWKS)**
       * **Target Link URI**: paste the **Tool URL / Launch URL**
    4. Click **Register** — Brightspace generates a **Client ID** and **Deployment ID**. Copy both.
    5. Create a **Deployment** and link it to the desired org units (courses)
  </Accordion>

  <Accordion icon="book-open" title="Sakai">
    1. Go to **Administration Workspace → External Tools (LTI)** or the site's **External Tools** page
    2. Click **Install LTI 1.x Tool**
    3. Fill in:
       * **Tool Title**: `Veydra`
       * **Launch URL**: paste the **Tool URL / Launch URL**
       * **LTI 1.3**: check the checkbox
       * **OIDC Auth Endpoint**: paste the **Login Initiation URL**
       * **OIDC Token Endpoint**: *(leave blank — Veydra uses key-based validation)*
       * **OIDC Keyset URL**: paste the **Public Keyset URL (JWKS)**
       * **Redirect URL(s)**: paste the **Redirect URI(s)**
    4. Click **Save** — copy the generated **Client ID**
  </Accordion>

  <Accordion icon="school" title="Schoology (PowerSchool)">
    1. Go to **System Settings → Integration → External Tools → Add External Tool Provider**
    2. Set the **LTI version** to **1.3**
    3. Fill in:
       * **Tool Name**: `Veydra`
       * **Launch URL**: paste the **Tool URL / Launch URL**
       * **OpenID Connect Login**: paste the **Login Initiation URL**
       * **Redirect URIs**: paste the **Redirect URI(s)**
       * **JWKS URL**: paste the **Public Keyset URL (JWKS)**
    4. Save and copy the generated **Client ID**
  </Accordion>

  <Accordion icon="globe" title="Open edX">
    1. Go to **Django Admin → LTI 1.3 (via `/admin/`)** or **Studio → Advanced Settings**
    2. Add a new **LtiToolKey** with:
       * **Name**: `Veydra`
       * **Key type**: `jwk_url`
       * **JWK URL**: paste the **Public Keyset URL (JWKS)**
    3. Add a new **LtiTool** and fill in:
       * **Tool Name**: `Veydra`
       * **Launch URL**: paste the **Tool URL / Launch URL**
       * **OIDC Login URL**: paste the **Login Initiation URL**
       * **Redirect URIs**: paste the **Redirect URI(s)**
    4. Copy the **Client ID** from the created tool entry
  </Accordion>

  <Accordion icon="flask" title="OLI Torus">
    1. In Torus admin, go to **Institutions → Registration** or **LTI 1.3 Tool Configuration**
    2. Fill in:
       * **Tool Name**: `Veydra`
       * **Target Link URI**: paste the **Tool URL / Launch URL**
       * **OIDC Login Init URL**: paste the **Login Initiation URL**
       * **Redirect URIs**: paste the **Redirect URI(s)**
       * **JWK Set URL**: paste the **Public Keyset URL (JWKS)**
    3. Save and copy the generated **Client ID** and **Deployment ID**
  </Accordion>
</AccordionGroup>

***

## Step 3: Register the Platform in Veydra

Now go back to Veydra and tell it about your LMS so it can validate incoming launch requests.

<Steps>
  <Step title="Click Register Platform">
    On the **LTI Integrations** page (`Account → LTI Integrations`), click the **Register Platform** button.
  </Step>

  <Step title="Select Your LMS Type">
    Choose your LMS from the **LMS Type** dropdown. This auto-fills the endpoint URL paths so you only need to enter your LMS base URL.

    Supported presets: Moodle, Canvas, Blackboard Learn (Ultra), D2L Brightspace, Sakai, Schoology (PowerSchool), Open edX, OLI Torus.

    <Tip>
      If your LMS is not listed, leave the dropdown empty and fill in the URLs manually. Your LMS admin documentation will have the correct endpoint paths.
    </Tip>
  </Step>

  <Step title="Fill in Platform Details">
    | Field                        | Required | Description                                                                                                                       |
    | ---------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
    | **Platform Name**            | Yes      | A friendly name (e.g. "My University Moodle")                                                                                     |
    | **Issuer (Platform ID)**     | Yes      | Your LMS base URL (e.g. `https://moodle.university.edu`). When you type this with a preset selected, the endpoint URLs auto-fill. |
    | **Client ID**                | Yes      | The ID your LMS generated in Step 2                                                                                               |
    | **Deployment ID**            | No       | Some LMS platforms provide this alongside the Client ID                                                                           |
    | **Authentication Login URL** | Yes      | Auto-filled by preset, or enter manually                                                                                          |
    | **Access Token URL**         | Yes      | Auto-filled by preset, or enter manually                                                                                          |
    | **Public Keyset URL (JWKS)** | Yes      | Auto-filled by preset, or enter manually                                                                                          |
    | **Default Lab**              | No       | The lab that students land on by default when launching from this LMS                                                             |
    | **Default Role**             | No       | **Student** (default), Viewer, or Instructor — the Veydra role assigned to users who launch via LTI                               |
  </Step>

  <Step title="Save">
    Click **Register Platform**. The platform appears in your **Registered Platforms** table and is immediately active.
  </Step>
</Steps>

<Warning>
  Double-check that the **Client ID** and **Issuer** match exactly what your LMS shows. A mismatch will cause launch requests to be rejected.
</Warning>

***

## Step 4: Add Veydra to a Course

With the platform registered, you can now add Veydra as an activity in your LMS courses.

<AccordionGroup>
  <Accordion icon="graduation-cap" title="Moodle">
    1. Go to your course → **Turn editing on**
    2. Click **Add an activity or resource → External tool**
    3. Select **Veydra** from the **Preconfigured tool** dropdown
    4. Optionally set a custom **Activity name** (e.g. "System Dynamics Lab — Population Model")
    5. To send students to a specific lab, expand **Tool configuration → Custom parameters** and add:
       ```
       lab_slug=your-lab-slug
       ```
    6. Click **Save and display** to test the launch
  </Accordion>

  <Accordion icon="chalkboard" title="Canvas (with Deep Linking)">
    If you configured **Link Selection** or **Assignment Selection** placements with `LtiDeepLinkingRequest`:

    1. Go to your course → **Modules → + → External Tool** (or **Assignments → + Assignment → External Tool**)
    2. Select **Veydra** from the list
    3. A **content picker** opens showing content grouped by **Project → Model → Activity**
    4. Select **exactly one activity** and click **Add Activity to Course**
    5. The selected content is embedded as a link - students click it to launch directly into that activity

    <Note>
      The content picker shows models belonging to the user who registered the LTI platform in Veydra. To show a different user's models, edit the platform registration and set the **Owner Filter** field.
    </Note>
  </Accordion>

  <Accordion icon="building-columns" title="Blackboard / Brightspace / Sakai / Schoology">
    The general process is the same across platforms:

    1. Navigate to your course content area
    2. Add a new **External Tool / LTI Link** activity
    3. Select the registered **Veydra** tool
    4. Optionally configure the `lab_slug` custom parameter to target a specific lab
    5. Save and test the launch as a student
  </Accordion>
</AccordionGroup>

<Tip>
  **Custom parameters vs Deep Linking**: You can target specific content by either:

  * Using the **Deep Linking content picker** (Canvas, Moodle 4.0+) — visual selection, no URL editing
  * Setting `lab_slug`, `model_id`, and (for activity launches) `activity_id` as custom LTI parameters — works on any LMS
</Tip>

***

## Deep Linking Content Picker

When configured for Deep Linking, Veydra displays an interactive content picker inside your LMS. This lets instructors visually browse and select which activity to embed.

### How Deep Linking Works

1. Instructor clicks **Add External Tool → Veydra** in the LMS
2. The LMS sends a `LtiDeepLinkingRequest` to Veydra
3. Veydra displays a content picker showing available content grouped by **Project → Model → Activity**
4. Instructor selects **one activity** and clicks **Add Activity to Course**
5. Veydra sends a signed response back to the LMS with the selected content
6. The LMS creates a link/assignment pointing to that specific activity

### Selection Rules

* Exactly one activity can be selected per Deep Linking action.
* Sandbox entries (for example, **Model Playground** / **Sandbox**) are excluded from the picker and cannot be linked.
* Deep Linking responses include both `model_id` and `activity_id` so launches open the selected activity directly.

### Configuring Deep Linking

Deep Linking requires your LMS to be configured with the correct **placement** and **message type**:

| LMS             | Where to Configure                                     | Message Type Setting           |
| --------------- | ------------------------------------------------------ | ------------------------------ |
| **Canvas**      | Developer Key → Placements → Link/Assignment Selection | Set to `LtiDeepLinkingRequest` |
| **Moodle**      | External tool → Content Selection URL                  | Auto-detected from tool config |
| **Blackboard**  | LTI Tool → Deep Linking Settings                       | Enable "Deep Linking"          |
| **Brightspace** | LTI Tool → Deployment → Deep Linking                   | Enable and set return URLs     |

### Content Visibility

The content picker shows activities belonging to:

1. The **Owner Filter** configured on the platform (if set)
2. Otherwise, the **user who registered** the LTI platform in Veydra

To change which activities appear, edit your platform registration in **Account → LTI Integrations** and set the **Owner Filter** to the desired user ID.

### Deep Linking Custom Parameters

When an instructor selects content through the picker, Veydra returns LTI custom parameters on the placement:

* `model_id`: the parent model
* `activity_id`: the selected activity (required for activity launch)
* `lab_slug`: optional lab context when configured

Veydra prioritizes activity launches when `activity_id` is present.

***

## Managing Platforms

### Editing a Registration

From **Account → LTI Integrations**, click **Edit** on any registered platform to update its details (name, URLs, default lab, or default role). Changes take effect immediately.

### Deleting a Registration

Click **Delete** on a platform registration. You'll be asked to confirm. Once deleted, students will no longer be able to launch from that LMS.

<Warning>
  Deleting a platform does not remove the student accounts that were created via LTI. Students who were auto-provisioned can still sign in to [app.veydra.io](https://app.veydra.io) directly.
</Warning>

### Viewing & Changing Default Lab

The **Default Lab** column in the platforms table shows which lab students land on after launch. To change it, edit the platform and select a different lab from the dropdown. You can also leave it blank and rely on the `lab_slug` custom parameter per activity.

***

## User Provisioning

When a student launches Veydra from an LMS for the first time, the system automatically:

1. **Looks for an existing linked account** — if the student has launched before, they're signed in immediately
2. **Checks by email** — if the student's LMS email matches an existing Veydra account that is not yet linked, the user is prompted for a **one-time sign-in confirmation** before linking
3. **Creates a new account** — if no email match is found, a new Veydra account is created automatically using the student's LMS profile

The student is then granted access to the target lab with the configured role (Student, Viewer, or Instructor).

<Note>
  Instructors in the LMS are mapped to the Veydra role configured on the platform registration (default: Student). To give LMS instructors elevated access, you can change the default role or grant them permissions manually in **Account → Manage Labs**.
</Note>

***

## Roles & Permissions

The role assigned to LTI users determines what they can do inside a lab:

| Role           | Can View Models | Can Adjust Parameters | Can Edit Structure | Can Manage Users |
| -------------- | :-------------: | :-------------------: | :----------------: | :--------------: |
| **Student**    |        ✓        |           ✓           |          ✗         |         ✗        |
| **Viewer**     |        ✓        |           ✗           |          ✗         |         ✗        |
| **Instructor** |        ✓        |           ✓           |          ✓         |         ✓        |

The default role is set per-platform when you register it. Individual users can be promoted or changed in **Account → Manage Labs → \[Lab] → Users**.

***

## Automatic Grade Passback

Veydra supports **LTI Assignment and Grade Services (AGS)** to automatically send grades back to your LMS gradebook when students complete activities.

### How It Works

1. Student launches a Veydra activity from the LMS
2. Student works through the model playground (presentation, calibration, experimentation, etc.)
3. When the student clicks **Submit** in the embedded LTI top bar, Veydra:
   * Calculates a score based on completed steps
   * Sends the grade directly to the LMS gradebook via AGS

<Info>
  Grades are submitted as a fraction of the maximum score (e.g., completing 3 of 4 steps = 0.75 out of 1.0). The LMS converts this to its own grading scale.
</Info>

### LMS Configuration for Grade Passback

For grades to sync back, your LMS must be configured to accept them. The exact settings vary by platform:

<AccordionGroup>
  <Accordion icon="graduation-cap" title="Moodle">
    **Site-level settings:**

    1. Go to **Site administration → Plugins → Activity modules → External tool → Manage tools**
    2. Click the gear icon on your Veydra tool → **Edit**
    3. Under **Services**, set **IMS LTI Assignment and Grade Services** to **Use this service for grade sync**
    4. Under **Privacy**, set **Accept grades from the tool** to **Always**
    5. Save changes

    **Activity-level settings:**

    1. When adding or editing the External tool activity, expand **Grade**
    2. Set **Grade → Type** to **Point** (not "None")
    3. Set **Maximum grade** to your desired value (e.g., 100)
  </Accordion>

  <Accordion icon="chalkboard" title="Canvas">
    1. When creating the External Tool assignment, check **Enable grading**
    2. Set the point value for the assignment
    3. Canvas will automatically accept grades from LTI tools configured with AGS scope
  </Accordion>

  <Accordion icon="building-columns" title="Blackboard / Brightspace / Other">
    Most LMS platforms enable grade passback by default for LTI 1.3 tools. Check your LMS documentation for:

    * Enabling "Accept grades from tool" or "Grade sync" in tool settings
    * Setting the activity/assignment to be gradable (point-based, not pass/fail or ungraded)
  </Accordion>
</AccordionGroup>

### Grade Calculation

Veydra calculates the score based on the number of completed steps in the activity:

| Steps Completed | Score |
| --------------- | ----- |
| 0 of 4          | 0%    |
| 1 of 4          | 25%   |
| 2 of 4          | 50%   |
| 3 of 4          | 75%   |
| 4 of 4          | 100%  |

<Note>
  The number of available steps depends on the model's configured modes (e.g., presentation, calibrate, experiment, decide). Models with fewer modes will have fewer steps to complete.
</Note>

### Troubleshooting Grade Passback

<Accordion title="Grades not appearing in LMS gradebook">
  Check the following:

  * **LMS tool settings**: Ensure "Accept grades from tool" is enabled
  * **Activity grade type**: Must be "Point" (not "None" or "Scale")
  * **Console logs**: Open browser DevTools and check for `[LTI] Grade submitted successfully` or error messages
  * **Backend logs**: Check Cloud Run logs for `[LTI AGS]` messages showing the grade submission status
</Accordion>

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Launch fails with &#x22;Platform not found&#x22;">
    The Issuer URL in Veydra doesn't match what the LMS is sending. Verify:

    * The **Issuer** field matches your LMS base URL exactly (including `https://` and no trailing slash)
    * The **Client ID** matches the one your LMS generated
  </Accordion>

  <Accordion title="Launch fails with &#x22;Invalid token&#x22;">
    The JWT signature couldn't be verified. Check:

    * The **Public Keyset URL (JWKS)** on the platform registration points to the correct LMS endpoint
    * Your LMS's keyset URL is accessible from the internet (not behind a firewall)
  </Accordion>

  <Accordion title="Students land on the wrong lab (or no lab)">
    * Check the **Default Lab** setting on the platform registration
    * Verify the `lab_slug` custom parameter in the LMS activity configuration
    * Ensure the lab exists and is active in **Account → Manage Labs**
  </Accordion>

  <Accordion title="Students get &#x22;Access denied&#x22; after launch">
    The student's account was created but not granted access. This can happen if the lab's access control changed after the initial launch. Go to **Account → Manage Labs → \[Lab] → Users** and verify the student's role.
  </Accordion>

  <Accordion title="&#x22;Authentication required&#x22; on platform management endpoints">
    You must be signed in to Veydra to manage platform registrations. The Tool Configuration URLs (JWKS, Login, Launch) are public and don't require authentication.
  </Accordion>
</AccordionGroup>

***

## Security

Veydra's LTI implementation follows IMS Global security best practices:

* **OIDC + JWT**: Every launch is authenticated via OpenID Connect with signed JWTs — no shared secrets
* **RSA key pairs**: Veydra maintains its own RSA keypair; the public key is served via a standard JWKS endpoint
* **Nonce validation**: Each login request includes a one-time nonce that expires after 10 minutes
* **No password storage**: LTI users authenticate through their LMS; Veydra never sees or stores LMS passwords
* **Firebase Auth**: After JWT validation, users receive a standard Firebase session — the same authentication used by all Veydra users
