401: Missing User OAUTH Token (get-custom-rewards)

Hey, I’m working on a SE widget for a person, one of the steps require to get-custom-rewards, that’s why I asked him to log in to Twitch Developers, then creating a Project and share with me his Client ID and Secret.

With these two elements I’ve requested a Bearer access token.

url = 'https://id.twitch.tv/oauth2/token';
  	data = {
    	client_id: TWITCH_CLIENT_ID,
        client_secret: TWITCH_SECRET,
        grant_type: 'client_credentials'
    }
	result = await fetch(url, {
        method: 'POST',
      	headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify(data)
    });

Now I’m looking to get the channel’s rewards.

url = `https://api.twitch.tv/helix/channel_points/custom_rewards?broadcaster_id=xxxxxx`
  	result = await fetch(url, {
        method: 'GET',
      	headers: {
          'Client-ID': TWITCH_CLIENT_ID,
          'Authorization': TWITCH_TOKEN
        }
    });
  	result = await result.json();

Twitch APIs respond with the following error.
{error: 'Unauthorized', status: 401, message: 'Missing User OAUTH Token'}

What am I missing?

You’re using the wrong OAuth flow. client_credentials creates an App Access Token, meaning it represents the app itself and not a user, and so does not have any user permissions associated with it.

As the developer, you shouldn’t need to be asking users of your service to create their own apps on the TwitchDev console.

You should use your app for the project, and either the Auth Code flow if you want to get tokens that can be refreshed on your server, or the Implicit flow if you want to use the tokens client-side (these can’t be refreshed, so you’d need to send the user through the auth flow each time the token expires). Also, for the endpoint you’re using you’d need the channel:read:redemptions scope, so make sure that’s set on the auth process so that Twitch will explicitly ask the user if they wish to grant that access to your app.

I’m not bulding a public service, he would have been the only one to use it.

I wanted an easy way to retrieve its rewards to display them in a widget, but I’m facing a lot of problems:
• the unnecessarily complex authentication flow, I said unnecessarily since the rewards are displayed in public anyway and I saw a lot of people having the same problem as me into the forum or on google search.
• the fact that I can’t access rewards created from other clients event if I just want to GET them and not edit anything and everyone is creating their rewards from the dashboard!

You can get but not manage, rewards you don’t own.
EventSub/PubSub will also broadcast all redeems that occur regardless of owner.

So this is false.

You mean industry standard oAuth used by most things that provide an API?

Once you have a working “template” of oAuth, you can use the same code for a bunch of services, you just feed it different URL’s and scopes

1 Like

That’s great, thanks for pointing that out.

Now I’m asking for help about the Authentication part, how should I proceed?
I would like to use just the widget from SE for everything.

Then if you are using StreamElements you need support from StreamElements which is a different API to Twitch

I don’t know what a SE Widget can or can’t do since I don’t use SE I run my own system

So I can’t access get-custom-rewards directly as the user? I need to ask as an application the permission to the above-mentioned user to access its data?

I would like to develop an automated script, so having the user authenticate isn’t probably the best way. Also I don’t have a server where to host the Auth service. Isn’t there a solution to act like the user?

Where should I specify this?

I feel like I first need to understand what I’ve to do in order to achieve my goals, I’ve tried reading Auth Code as @Dist suggested but I didn’t understand much, please read my doubts in the first rows of this answer.

Basically StreamElements host custom widgets into jailed iframes, widgets are built with HTML, CSS and JS; you can see some further information into their GitHub repo. From there I’m able to create GET/POST requests. Let me know if you need more information, I would love to provide them.

I feel like we can provide a huge contribution to the community solving this thread since I’ve seen people having my same doubts but didn’t see a really conclusion into their threads.

Correct, to utilise the API on behalf of a broadcaster you need permission from the data owner, in this case the broadcaster.

The streamer “owns” the rewards and redemptions.

You authenticate/get a token from the streamer once.

This gives you a user token and a refresh token.
When the user token expires, you use the refresh token to get a new token.

if the refresh token dies or becomes invalid, you will need to get the broadcaster to reauthenticate

See this oAuth flow: Getting OAuth Access Tokens | Twitch Developers

Yes, you run a server hosting your Auth service to get a token from the user. Then you can act as the user.

This is an industry standard security mechanism called oAuth.

No auth service? Then no way to get a user token.

Sure you could go the implicit route and have the user copy/paste the token somewhere, but this sort of token cannot be refreshed.

In the <a href="" that the broadcaster clicks on to Authenticate your Applications access to their account

You can see on this implict auth example

https://barrycarlyon.github.io/twitch_misc/authentication/implicit_auth/

There are two links, one that is scopeless and one with the email scope (user:read:email)

If needed you can refer to some examples

I have written two examples for user authentication, one for node and one for PHP

Other examples may exist on Community Resources | Twitch Developers

oAuth is very straight forward

  • user comes to your website
  • user decides to use your service
  • user clicks on a <a href to login (sometimes this might be a /login/ that then redirects to Twitch so you can set a state param in the session nicely)
  • that link takes then to the service
  • the user accepts (or declines the link)
  • user comes back to your site and if they accepted a ?code will be present in the query string (other wise an ?error/error description)
  • you exchange the ?code for an access and refresh token
  • you store these tokens and use those tokens

This works for a number of serices, you just swap in the different token URL’s and scopes as needed

If I’m building a widget/overlay I don’t use SE. I use all my own stuff.

No need to go via their system if I can build the widget and communication layers myself. It seems excessive to use their system when you built everything else but the communication layer. And I can optimise traffic and communications without being stuck inside their jail.

I don’t need more information on a system I’ll never use when I can build my own.

And this means I can use EventSub or PubSub or the API, I’m not limited to what you can glue together in SE’s widget system. And I can do whatever I need/want to protect the streamers access tokens.

So you cripple yourself and deny your self access to Twitch PubSub and EventSub, if you can only make Get/Post requests.

EventSub is the optimal way to obtain Redemptions in real time. (As will EventSub websocket when it arrives).

PubSub is passable, but I’d wait for EventSub over websockets rather than PubSub here.

I feel users cripple themseleves trying to bend things to work inside other peoples systems.

When it’s easier to just build your own system that dones’t involve making x talk to y. When x speaks english and y speaks french for example.

People get stuck on oAuth and if/when the solve it they spend ages trying to figure out how to glue that into another system like SE when you could save time and build your own without hooking into SE.

What if I wanted to access the API as the broadcaster and not on behalf of him? Like can I access my data without asking myself the permission? I don’t know if that makes sense.

Great, when the APIs return error 401 I usually ask for a new token to Twitch and re-do the requests. I’m not 100% sure that error 401 get raised only when the token is expired, but it always worked since now.

That’s seems to be my main problem: I don’t own a server to create the Aouth service. Do you know any public online service that can help me doing that? Can’t I just share the link with the broadcaster and he returns me the URL he gots after sign in? Basically, any method without owning a server?

Obviously this kind of token will expire and I will need to ask the broadcast to get another one for me, so not doable. It will be great if it doesn’t expire, but it does, right?

I see your point, but I’m not doing this for my self. Most of the people don’t run their own service because they’re not able to mantain it: that why services like SE went viral.

Actually there are examples of people using PubSub on SE too, here you got an example, I wanted to take this an example for retrieving Redemptions in real time through SE systems.

Only if the Braodcaster gives you their account password and 2fa code.

Which is clearlly impractical and not good for security.

Hence oAuth exists to provide this instead.

Rent a server from any reputable server provider, or VPS provider or cloud provider and deploy your code.

The same server will also store your access and refresh tokens for the streamer.

Without owning “hosting” of some sort you are stuck. Since you need to secure those streamer keys.

Since you intend to deploy to SE Widgets, where are you going to store/host the streamers access tokens and refresh tokens? And any API/EventSub/PubSub interface you need?

In theory, yes, but then where do you host/store your access keys and any scripts to refresh those access keys and your API/PubSub/EventSub interface?

Without a hosting solutions you run into problems.

No hosting provider? Well then you go implict auth to get a key, but that key is not refreshable and the broadcaster needs to manually provide a new key periodically.

Hence, you should use regular oAuth to get a token and refresh token and host an API/PubSub/Eventsub interface layers.

Without the server, you have to use the “wrong kind” of oAuth and then the streamer has to manually give a new key periodically, instead of automagically.

Correct, all tokens expire.

For security reasons. If you leak a token, you don’t want someone to be able to abuse that token forever. Sure then the streamer will disconnect the app and start all over again.

But as long as you didn’t revoke the refresh token (and client secret) then you are fine. As you use those to generate a new access token, if the leaked token gets revoked (via the revoke API for example)

Forever tokens are bad for security.

I run these services for streamers.

So streamers use my instead of SE. I’m able to provide whatever for those streamers in a way that is not constriained by the limitations of SE Widgets or what SE provides

Sure this could work.

But you still have the problem of where do you host your oAuth interface? And the thing that stores the Access and refresh tokens? To make the access token available for the pure front end SE Widget to use the access token?

In this example I’d make the SE Widget call my own system so it doesn’t leak the access token. Granted it’s perfectly fine to show the streamers own access token to themself, but again you want to protect the access token from others viewing it. So my Overlays/widgets call my server with a unique Key and that matches to data internally, so if my Overlay URL gets leaked, no one acquires the access token.

Which is possibly what could happen with this SE Widget as you describe.

With an SE Widget, it will need to be able to call, the hosting you don’t want, to get the access token and/or the updated access token when it’s refreshed.

Which takes us back to the no hosting solution or using implict auth, which means when the token dies, the streamer will need to interact with the overlay to provide/obtain the new token, as you don’t want to provider hosting.

So you are stuck in a loop due to how you wish to implement.

The only safe way is with implicit auth, which means the streamer will need to give a new token periodically, thats if they even notice that their widget stops working due to a dead token!

Actually SE provide a sicure system to store data into their databases, as you can see here, I said sicure because this method requires SE token to work and just the owner does know its token. So I will choose this a system to store access keys or more in general sensitive data. As far as the script for refreshing the token, I’ve already have functioning scripts talking to Twitch APIs from SE’s widgets.

As far as now this seems the most doable thing without having a server for hosting the oAuth process and leaning on SE for the storing part. Could you please help me building the link?

Talking about this solution here, how long does this keys last and where should the broadcaster take/request them?

I already did

Use the validate endpoint to check the current expiration of a token. Or check expires_in when a token is obtained

Generailly speaking:

  • implict token - 60 days - can’t be refreshed, manual remake
  • regular token - 4 hours - has refresh token to auto obtain a new token
  • app access - 60 days - just get a new token, doesn’t represent a user (included for completeness it’s not usable for what you want to do, unless talking to eventsub)

If you were using EventSub webhook transport:

  • authenticate the user
  • discard the token
  • use an app access token to create Topics
  • then it works forever! No token faffery.

But you can’t eventsub with an SE Widget.

Odd that they don’t include access to the SE token that SE has, and/or they don’t provide a way to get an oAuth token anyway

The oAuth link that fits this situation should looks like the following one, could you double check it please?

https://id.twitch.tv/oauth2/authorize?client_id=${app_client_id}&redirect_uri=${redirect_url}&response_type=code&scope=channel:read:redemptions

Now we should able to proceed as the OAuth authorization code flow state, and at the end of the process I will have the token + refresh token without having a server setup. Am I right?

The only big difference is gonna be that I will not obtain the authorization code directly but I’ll need the broadcaster to copy and past it from the redirect page URL, no?

That looks correct

as per step 1

Sure the redirect URI could be a dead URL that does nothing/has no server at and the broadcaster could copy and paste the ?code to you and you can do the exchange locally, but this is impractical as the TTL on the ?code= isn’t paticuarally long for security reasons.

It’s designed to be instantly exchanged. Not after some time. So this the copy/paste of the code method may be impractical.

It’s not ideal but it may work. it’s just a mess as if the token (and refresh token) dies. The user can’t just go to your website to fix the widget, they have to wait for you to be available to provide the ?code via copy/paste. So there will then be downtime on your widget.

Damn, this can break the whole plan. Is ?code TTL knowed or do we know that is just short?

I did understand that was quite impossible to have the token + refresh token die. Why would tokens die?

iirc the specification states it’s 5 minute.

The user changed their twitch password
The user used the forgotton password routine.
The user unlinked their account
Something else happened to break links or tokens
You generated 51 tokens which killed token 1 and you still have token 1 in use somewhere due to how you are handling oAuth.

Are a few things that could result in access and/or refresh token death.

Ok, I will make sure to warn the broadcaster about this possibility. As far now I managed to finally retrieve his Channel Custom Rewards (I’ve just learned that the ones there by default are not returned).

However I think we should talk about the other “serverless” option where the user is able to “refresh” his token without the developer’s assistance, is this the implicit route? Can you tell me more about it?

Because I feel like having to help the broadcaster whenever the tokens die it will be a pain.

Default rewards, like “highlight message” and “unlock emote” are not “custom”. So yeah they are not reported as a Custom Reward (nor are their redemptions)

You’d need a way for the widget to ask for oAuth and be able to write to the storage system SE uses.

Like I mentioned trying to use SE’s system is crippling you.

Without a server to handle oAuth, you are going “round the houses” to create a round about way to achieve the end result.

In this example:

https://barrycarlyon.github.io/twitch_misc/authentication/implicit_auth/

You can login via Twitch, and the page will use the returned implicit auth token, but it doesn’t try to store it anywhere else.

Concievable your SE widget could say “I have no token please click here”, then the broadcaster has to (in OBS) interact with the source,
click the link
login with Twitch
2fa with Twitch
then the SE Widget has the token
Then the SE widget could write the token to the SE Storage (in theory if thats supported to write to the secure storage from a “public” widget which sounds dangerous to me)

But, the token could die mid stream, then the streamer has to do all this faff whilst live,
and run the risk of accidentally leaking their password (if they don’t hide the widget and/or end up typing in the wrong field for example).

It’s a very not optimal solution.

Will the redemptions of default rewards be detected via PubSub? Or can them be detected somehow?

I feel like I can use OIDC implicit code flow the following way: since I need that token just to retrieve custom rewards and this can be done occasionally, I can create a small form (input text box + button) where the broadcaster will be able to insert the token and with the click the script will make the call to Twitch APIs. This way the broadcaster will be able to update their rewards when needed.
What do you think about this?

No

If it raises a chat message from a user entered message (such as highlighter of subonly) then you can get them via chat.

sounds plausible.

But only if that same form can send the token to SE to be stored in SE’s system so SE’s system can consume redeem events.