AnsweredAssumed Answered

401 Error with LTI 1.3 Service Tokens

Question asked by William Diehl on Jul 23, 2019
Latest reply on Oct 28, 2019 by Elias Ayele

Greetings all,

I'm writing an LTI 1.3 implementation and have the basics up and running but no matter what I do I cannot get service tokens to work.

I can successfully generate a token by POSTing a request to /login/oauth2/token with a grant_type of client_credentials and a properly formed JWT signed with my private key. The server returns what looks like a legitimate token - the response has valid token_type, expires_in, scope, and of course access_token values. The access_token is itself a HS256 JWT that has what look like the expected values for things (but that doesn't matter as the token content is supposed to be opaque to an LTI tool).

The problem is no matter where I try to use the thing I get a 401 Unauthenticated "user authorization required" error with a WWW-Authenticate: Bearer realm="canvas-lms" header. I'm adding the generated access_token value as an "Authorization: Bearer xxxxxx" HTTP header (I've also tried it as a URL parameter with the same result).

I've tried the token with the Line Items, Scores, Results, and Names and Roles /lti/ APIs but all with the same result. There's so little documentation out there (which is mind boggling to me) but as far as I can tell by picking apart the IMS LTI 1.3 standards and OAuth docs I'm doing things right... but of course I must not be.

I realize this is a really basic error question without a lot of additional details, but the error response doesn't tell me if the token is invalid, expired, or if I have insufficient permissions - it's almost like it's not seeing it at all. But I've replayed the same request in fiddler to other, non-LTI REST API calls and it tells me the token is invalid (as it's a different kind than the normal OAuth2 tokens used by the rest of the API) so my HTTP requests are at least formed properly.

Here's the token I get back:

     access_token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2NhbnZhcy5iZXRhLmluc3RydWN0dXJlLmNvbSIsInN1YiI6IjExMzY4MDAwMDAwMDAwMDAzOCIsImF1ZCI6Imh0dHBzOi8vY2FudmFzLmJldGEuaW5zdHJ1Y3R1cmUuY29tL2xvZ2luL29hdXRoMi90b2tlbiIsImlhdCI6MTU2MzkwODQwMiwiZXhwIjoxNTYzOTEyMDAyLCJqdGkiOiI3MjI4MDk0MC1lMzk3LTRhNmEtYmFiMy1jMjUxZGM5MTFmZGQiLCJzY29wZXMiOiJodHRwczovL3B1cmwuaW1zZ2xvYmFsLm9yZy9zcGVjL2x0aS1hZ3Mvc2NvcGUvbGluZWl0ZW0gaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9sdGktYWdzL3Njb3BlL3Jlc3VsdC5yZWFkb25seSBodHRwczovL3B1cmwuaW1zZ2xvYmFsLm9yZy9zcGVjL2x0aS1hZ3Mvc2NvcGUvc2NvcmUifQ.RXOV4UfmcDWafLBQ5M2VZcmWFPww1Htd966ajLF2jzY,
     token_type = Bearer,
     expires_in = 3600,
     scope = https: //

All I can think of is that I'm either getting the token from the wrong endpoint (I'm using which is the initial iss value in the Canvas signed JWT I get from the authentication process. I've also used our own beta instance but the tokens appear identical so I just used the iss value since it seemed safer), I'm using the token wrong, or I'm calling the /lti/ APIs wrong in the Canvas REST endpoints.


Any advice?

Thanks very much!!