instructure/canvas-lms · error · OembedAuthorizationError

The current user has changed

Error message

The current user has changed

What it means

LTI OEmbed controllers validate the signed request token via JwtValidator; even with a cryptographically valid token, validate_oembed_token! additionally checks that the token's user matches the currently logged-in user (same_user?). If they differ, the error message is set to "The current user has changed", logged, and OembedAuthorizationError is raised to reject the request.

Solutions

  1. Have the LTI tool re-request/re-launch to mint a fresh token for the current user
  2. Verify same_user? comparison uses consistent identifiers (LTI user id vs Canvas id) — a mismatch in id types can falsely trigger it
  3. Avoid initiating impersonation in a session with an active LTI OEmbed flow, or relaunch the tool after starting impersonation
  4. Check that the JWT validator populated the correct user claim (sub/custom user id) at token generation

Example fix

// before
# tool reuses a cached JWT minted for the previous session user
fetchOembed(cachedToken) // -> OembedAuthorizationError
// after
# mint a token for the current user at request time
const token = await launchLti({ user: currentUser })
fetchOembed(token)
Defensive patterns

Strategy: try-catch

Validate before calling

// before making the OEmbed request, confirm the session user still matches the token
if (tokenUserId !== currentUser.ltiUserId) {
  await relaunchTool(); // mint a fresh token for the current user
  return;
}

Type guard

function tokenMatchesCurrentUser(token, currentUser) {
  const claims = decodeJwt(token);
  return claims.sub === currentUser.ltiUserId;
}

Try / catch

begin
  validate_oembed_token!
rescue Lti::OembedAuthorizationError => e
  render json: { error: e.message }, status: :unauthorized
end

Prevention

When it happens

Trigger: validate_oembed_token! runs when a user's session user differs from the user embedded in the OEmbed JWT — e.g., the token was minted for user A but the request arrives under user B's session (impersonation started mid-flow, user switched accounts in another tab, or session changed between token issuance and request).

Common situations: Admin masquerading as a user while an LTI tool iframe holds the original user's token; a user logging out and back in as another account while an OEmbed request is in flight; tools caching tokens across user sessions.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/9cccfcb00f55ab37. Report an issue: GitHub.

Appendix: source

Thrown at app/controllers/lti/concerns/oembed.rb:38

module Lti::Concerns
  module Oembed
    class OembedAuthorizationError < StandardError; end

    # Does standard JWT validation and also verifies
    # the current user is the same user that the
    # tool issued a token for
    #
    # Validating this token helps Canvas ensure that
    # an authorized tool is requesting oembed object
    # embedding.
    def validate_oembed_token!
      error_message ||= jwt_validator.error_message unless jwt_validator.valid?
      error_message = "The current user has changed" unless same_user?

      return if error_message.blank?

      log_error(error_message)
      raise OembedAuthorizationError, error_message
    end

    def log_error(message)
      logger.warn "[OEmbed] #{message}"
    end

    def jwt_validator
      @jwt_validator ||= Canvas::Security::JwtValidator.new(
        jwt: verified_jwt,
        expected_aud: Canvas::Security.config["lti_iss"],
        require_iss: true
      )
    end

    def oembed_endpoint
      uri_source[:endpoint]
    end

View on GitHub (pinned to 1c9f0bb801)