# Oauth2 authorization-code, multiple devices, recommended flow?

**URL:** <https://staging-discuss.dev.twitch.com/t/oauth2-authorization-code-multiple-devices-recommended-flow/46497>\
**Category:** API\
**Created:** [July 14, 2023, 5:32pm UTC](https://staging-discuss.dev.twitch.com/t/oauth2-authorization-code-multiple-devices-recommended-flow/46497 "2023-07-14T17:32:10Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![zero](https://avatars.discourse-cdn.com/v4/letter/z/a88e57/32.png) [@zero](https://staging-discuss.dev.twitch.com/u/zero)\
**Post date:** [July 14, 2023, 5:32pm UTC](https://staging-discuss.dev.twitch.com/t/oauth2-authorization-code-multiple-devices-recommended-flow/46497/1 "2023-07-14T17:32:10Z")

</div>

Hi!

**Context**  
I’m working on a webapp that provides a Log-in with Twitch, as the main authentication method, I’m both: using the oauth2 authorization server to manage my user’s sessions (maintaining state) and using sometimes some Twitch API endpoints with their user tokens. So I decided to go with the authorization-code flow.

**Problem**  
The docs are very clear and helpful with the auth flow but when it comes to user tokens they always refer to the access/refresh token pair in singular and that makes the logic easier. But In practice users can login into a website from different devices/user-agents and they would get a different token pair for each one. What is the recommended flow then? Store all the tokens pair belonging to the user in the database? I believe that some time ago, logging into one device would invalidate the rest of your tokens, this is no longer the case, but that’s why I want to make sure that my approach is right, in case this changes again in the future.

My current planned architecture that I’m working on is something like the following:

- When a user logs in from a new user-agent via authorization code flow, store the user\_id in an encrypted, httpOnly cookie, and also store the access/refresh token pair in the encrypted cookie to save some roundtrips when reading some requests (more specifically, the requests that will originate requests to Twitch API since in those cases we would get a 401 if it is invalid).
- Store in database all the tokens pair belonging to the user. One pair per device/user-agent. This is to maintain and validate session state for stateful features, as twitch requires.
- Have a service run every hour in theory (in practice the load is balanced across the hour minutes so I don’t validate all the users in the same minute). First delete all the expired access\_tokens, then use /validate endpoint for every non-expired access token found for every user. Delete non-valid non-expired access tokens.
- When using features that use Twitch API: when the request comes in, read user\_id and token pair from encrypted cookie, if it is expired try to refresh it with the refresh token, update the corresponding token pair in the database/cookie. Database is only needed for update if expired, not reading. Use Twitch API as expected, if 401 is returned anywhere, delete all the cookies and the corresponding token pair for the user in the database, requiring user to log in again in the corresponding device.
- When using local features that don’t need Twitch API and which are stateful; for example creating an item in my app or accessing a protected resource, check if user is still valid in my database to ensure my app hasn’t been disconnected from twitch (if it’s something really important/sensible, like payment, maybe check directly with twitch api instead of database). Check if the current access\_token in the cookie matches a valid one in the database for the given user\_id, if not try to refresh, if refreshed update db/cookies, if it returns 401 when using the refresh\_token, delete all the cookies and ALL the tokens in the database, consider that the user has disconnected my app and redirect it to authorization code flow again. Since we run a service to validate them every hour an invalid token would last at most 1h.

Edit. Probably, it is way safer if refresh tokens are never stored in database (?)

**Questions**

1. Is this the recommended flow? Is there any potential flaw in my architecture that you’d recommend changing? Since this is about security, I’m very interested in your opinions and other developers’ experiences.
2. What is the rate limit for the /validate endpoint. As I said, I’m balancing the validations across the hour cycle period to be more gentle with twitch servers and not performing all the access\_token validations at once, also I’m excluding expired access\_tokens which I expect to lower the number of validations by a lot and also that would exclude non-active users, but I’m still interested in the rate limit so I can adjust better my balancer parameters and have plans to scale better, etc.

While the authentication examples are very helpful I miss some examples with the refresh token logic and mentioning what to do with multiple tokens from multiple devices/browsers, since the logic in practice is more complicated that the presented in the examples and the relation user:token is no longer 1:1, but 1:n, this changes many things and takes many considerations, many decisions directly related with security and left up to the developer’s interpretation.

---

<div class="post-metadata">

**Author:** ![DevMcGee](https://avatars.discourse-cdn.com/v4/letter/d/839c29/32.png) [@DevMcGee](https://staging-discuss.dev.twitch.com/u/DevMcGee)\
**Post date:** [July 15, 2023, 7:23pm UTC](https://staging-discuss.dev.twitch.com/t/oauth2-authorization-code-multiple-devices-recommended-flow/46497/2 "2023-07-15T19:23:55Z")

</div>

> [@zero](#):
>
> Store all the tokens pair belonging to the user in the database?

Store all token pairs _you will be using_ in the database.

> [@zero](#):
>
> in case this changes again in the future.

I think it’s unlikely this will change, but it might, and we’ll either find out when they tell us or 5 minutes after everything breaks.

> [@zero](#):
>
> When a user logs in from a new user-agent via authorization code flow, store the user\_id in an encrypted, httpOnly cookie, and also store the access/refresh token pair in the encrypted cookie

Are you using this instead of storing the authentication session in a database? In that case, you cannot log out other sessions.  
But if it’s more convenient for you to store the user’s OAuth tokens in their client-side token to save a database lookup, that isn’t _wrong_.

> [@zero](#):
>
> First delete all the expired access\_tokens

> [@zero](#):
>
> if it is expired try to refresh it with the refresh token, update the corresponding token pair in the database/cookie.

I guess you are assuming that expired tokens will remain expired unless you receive another request that requires them? In practice, you will frequently delete tokens from the database, only to re-add them later.

> [@zero](#):
>
> delete all the cookies and ALL the tokens in the database

Huh? I don’t understand deleting the cookies from the database. The cookies are stored in the user’s browsers, so you can’t anyway, but what are you storing in the database? I thought the purpose of putting all that information in the cookie is to avoid a database lookup.

> [@zero](#):
>
> Edit. Probably, it is way safer if refresh tokens are never stored in database (?)

In the worst-case scenario, where your whole application is compromised, not storing refresh tokens may limit the damage to some extent. On the other hand, you are supposed to be able to revoke refresh tokens, which will revoke all associated access tokens. _But_ the documentation implies that Twitch does not support that and I haven’t tested it.

> [@zero](#):
>
> Is this the recommended flow? Is there any potential flaw in my architecture that you’d recommend changing? Since this is about security, I’m very interested in your opinions and other developers’ experiences.

Do what works for you. Since you are concerned about security, I recommend using flowcharts, tests, and as simple code as possible.

> [@zero](#):
>
> What is the rate limit for the /validate endpoint.

IIRC, the rate limit is along the lines of “try to be reasonable”.

> [@zero](#):
>
> the relation user:token is no longer 1:1, but 1:n, this changes many things and takes many considerations, many decisions directly related with security and left up to the developer’s interpretation.

On the other hand, it provides additional flexibility to do things in ways that work best for your application. For example, if it would work for you, it may be much easier to use a single token for most of your work and let the user log in with tokens you only use once (for verifying they are a Twitch user and who they are) and then discard.

---

<div class="post-metadata">

**Author:** ![system](https://d2spem0quai2ol.cloudfront.net/original/2X/0/05909729875cce3b53e59d5561c4d23bb14948fc.png) [@system](https://staging-discuss.dev.twitch.com/u/system)\
**Post date:** [August 14, 2023, 7:24pm UTC](https://staging-discuss.dev.twitch.com/t/oauth2-authorization-code-multiple-devices-recommended-flow/46497/3 "2023-08-14T19:24:36Z")

</div>

Closed on August 14, 2023, 7:24pm UTC

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
