I would like to use twitch as an authentication server for my app: people would login with their twitch account and the app would authorize them if their account is on the app’s whitelist.
I could achieve that using the OIDC implicit flow:
the front-end directs the user to https://id.twitch.tv/oauth2/authorize?client_id=<client_id>&redirect_uri=http://localhost:3000/admin/login&response_type=token+id_token&scope=openid
the front-end gets an id_token when the callback url is called
the node backend validates the token on each API call (with the libs express-jwt and jwks-rsa)
the node backend gets the username from the token to check if the user is authorized
My problem is: the ID token expires after 15 minutes, at this point the user must login again.
How could I achieve an authentication system like that without this limitation?
A JWT via Twitch’s OpenID is valid for 15 minutes, after that it’s just “distrusted” as true. Since the JWT is just a representation of the users profile, it’s unlikely to have changed.
Generally speaking you use Twitch to login then hand off to your own session manager. Just because the JWT is no longer valid doesn’t mean you have to go round the oAuth loop again.
If you’re using Twitch for logging in to a website, you should be doing periodic checks to see if the user is still connected to your app.
So every 15 minutes, when the JWT expires, that’s often a good time to just send the user through the OAuth flow again, which unless you force them through the Accept/Deny screen it’ll just be seamless tot he end user as Twitch will just redirect them instantly back to you.
So every 15 minutes, when the JWT expires, that’s often a good time to just send the user through the OAuth flow again
That does seem more clean as I wouldn’t need to store anything server-side, but it seems difficult to restore the front-end state after the redirect to make it really seamless. For example if the user is completing a form they wouldn’t like to lose what they were typing.
It’s no different than if a session expires while the user is browsing a page. You wouldn’t suddenly force the user to go through the OAuth flow, you’d wait until they performed an action (ie, navigating to a new page, or submitting the form).
You can use the state param to store user-state so even if the user was attempting to access domain.com/some/path, you can store where they were going in the state so that after they get redirected back to you, your server can then look at the state param and send them to domain.com/some/path so they end up exactly where they wanted to go. To the user all that will happen is that it will appear as if the loading took a second longer, as they were redirected to Twitch then instantly back to your site (unless they disconnected from your app).
The point of this is so that if a user logs into your site using Twitch, then can’t then disconnect from your app and still keep using your site for a long period of time, still logged in, despite having disconnected and so should not be logged in.
Also worth noting is the docs on this subject:
Going through the auth flow is just one way to revalidate btw, it’s one of the common reasons why many sites that use Twitch to login have short lived sessions (between 15 and 30 minutes) as it’s an easy way to revalidate the users connection. Alternatively you could periodically poll the validation endpoint while the user is logged in.
I see how I could preserve the path after the redirect, but if the user submits a form with an expired token, I don’t see how I can preserve the content of the form
Huuuh while testing this validation endpoint (https://id.twitch.tv/oauth2/validate) I noticed that the access token is valid for several days, maybe I should validate this token instead of the id token