Thanks @justinball , this a great info for the community and should help with the ask for code examples.
Just to clarify, in case it wasn't already, the refresh token will never change unless you run through the entire OAuth2 process again.
Regarding storage, you at least have to store the user's token temporarily in order to use it, you can store it in a permanent DB as well. The refresh token should be stored permanantly; Just to clarify, in case it wasn't already, the refresh token will never change unless you run through the entire OAuth2 process again, so you can keep re-using it.
Storing the expiration time isn't really necessary if you take the responsive approach that Justin has discussed. Personally, I prefer to store the expiration time of the token. To do this, when I get the token, I just set a field "expires_at" to the current time + 1 hour. During each API call. I then run a pre-check to determine wether the current time is exceeded, and if so, I run the refresh process and update the stored API token in the DB before running the API request.
Both ways work (pro-active and re-active), it's not clear to me whether one is better than the other in terms of system performance. I imagine checking current time against the expiration time for every request could add up to more processing power for your servers, but I'll leave that to the computer scientists to determine where or if that starts to cause issues.
I personally like to store the API token in my User table with the following columns:
id: this is my own internal ID
primary_email:
canvas_user_id: the user id in the canvas url
user_id: the opaque user id sent during launch,
canvas_api_token: the token obtained during either the first OAuth2 flow or the refresh flow
canvas_api_refresh_token: the refresh token obtained during the last complete OAuth2 flow
token_expires_at: the time at which the token expires
When the app launches, I look up the canvas_api_token based on the user_id field since this never changes in Canvas.