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
- Have the LTI tool re-request/re-launch to mint a fresh token for the current user
- Verify same_user? comparison uses consistent identifiers (LTI user id vs Canvas id) — a mismatch in id types can falsely trigger it
- Avoid initiating impersonation in a session with an active LTI OEmbed flow, or relaunch the tool after starting impersonation
- 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
- Relaunch LTI tools after impersonation starts or account switches
- Never cache OEmbed JWTs across user sessions
- Use consistent user identifier types between token claims and session
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
- Access token expired
- Access token invalid - signature likely incorrect
- either the tool proxy or developer key were not found
- iat must be in the past
- Invalid access token field/s: #
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)