Authentication: token valid = false

Hi guys. I’m making authentication system for a site for the first time. I had no problems with getting user’s auth token. But now I need to get user’s name on Twitch to be able to register him on my site. For now I’m testing this just by opening a link in a browser, later it will be pulled via php_curl. Here’s a link (it’s test client_id and token, don’t worry):
https://api.twitch.tv/kraken?oauth_token=f5bncg7gbrhy0g8tnrkuxnvyych2tl&client_id=nghxxhkkcscw61pw1w9k6jmzqb1f3kl&scope=user_read
As you can see, I’m getting this answer:

{
    "identified":true,
    "_links":{
        "user":"https://api.twitch.tv/kraken/user",
        "channel":"https://api.twitch.tv/kraken/channel",
        "streams":"https://api.twitch.tv/kraken/streams",
        "ingests":"https://api.twitch.tv/kraken/ingests",
        "teams":"https://api.twitch.tv/kraken/teams"
    },
    "token":{
        "valid":false,
        "authorization":null
    }
}

What am I doing wrong here?

Firstly, you don’t need to include the client_id or the scope if you are already sending the oauth :slight_smile: (the request will still work, its just extra stuff that doesn’t do anything in the URL.

In your example, your link only needs to be https://api.twitch.tv/kraken?oauth_token=f5bncg7gbrhy0g8tnrkuxnvyych2tl

It may be a problem with the OAUTH that was created as when I create a OAUTH for myself with user_read scope, this is what I see at the kraken root:

{ "identified":true, "_links":{ "user":"https://api.twitch.tv/kraken/user", "channel":"https://api.twitch.tv/kraken/channel", "streams":"https://api.twitch.tv/kraken/streams/larklen", "ingests":"https://api.twitch.tv/kraken/ingests", "teams":"https://api.twitch.tv/kraken/teams", "users":"https://api.twitch.tv/kraken/users/larklen", "channels":"https://api.twitch.tv/kraken/channels/larklen", "chat":"https://api.twitch.tv/kraken/chat/larklen" }, "token":{ "valid":true, "authorization":{ "scopes":["user_read"], "created_at":"2016-12-06T15:54:50Z", "updated_at":"2016-12-06T15:54:50Z" }, "user_name":"larklen", "client_id":"CLIENTIDREPLACEMENT" } }

If you are looking to pull the user data that is provided in the scope, then the link would be https://api.twitch.tv/kraken/user?oauth_token=OAUTHTOKEN

You need to specify client_id from your app too or result will look like this:

{"error":"Bad Request","status":400,"message":"No client id specified"}

I still can’t figure out why it says that token isn’t valid. I just tried to do everything from scratch, I removed access for my app from my Twitch account, then got fresh new auth token, answer from API looked like this:

array (
  'code' => 'zx6suwv4ln8ulgmzr16do4zlnlcogy',
  'scope' => 'user_read chat_login',
)

But if you open this link, it still says token isn’t valid:
https://api.twitch.tv/kraken?oauth_token=zx6suwv4ln8ulgmzr16do4zlnlcogy&client_id=nghxxhkkcscw61pw1w9k6jmzqb1f3kl
And if you open this link:
https://api.twitch.tv/kraken/user?oauth_token=zx6suwv4ln8ulgmzr16do4zlnlcogy&client_id=nghxxhkkcscw61pw1w9k6jmzqb1f3kl
It returns:

{"error":"Unauthorized","status":401,"message":"Token invalid or missing required scope"}

This is only the case if the OAUTH is invalid. Twitch will automatically determine the proper client_id to use when you pass an OAUTH through an endpoint that doesn’t strictly require OAUTH.

The two latter examples also suggest the same thing - the problem seems to be either how you are getting the OAUTH or it may be a system issue - unfortunately my knowledge of PHP is limited and as for cURL, non-existent. I found this stackoverflow post, hopefully this might help (if not, sorry!).

Just a thought, should your ‘scope’ be written as: 'scope' => 'user_read', 'chat_login', instead of how you have it? Just throwing around a thought in hopes it helps :slight_smile:

@Larklen About client id:

In that very blog you linked, if you look at the second bolded question (Q&A style format), you will see what I am referring to :slight_smile:

If I’m including an OAuth token, do I need to include a Client-ID?
If you are passing in an OAuth token, we will figure out the Client-ID for you.

There is nothing wrong if you choose to also send the Client-ID alongside the OAUTH, I was just letting you know that it isn’t required in that case :slight_smile:

1 Like

Just to make sure: you’re not using the username for a key or login on your site, right? We’re switching over to IDs only for API calls, so I just want to make sure you’re storing the ID from the API as well so that it doesn’t break in the future. :slight_smile:

Have you tried doing a single scope and seeing if the root sends back that it is a valid token? It looks like (based on the returned value) you’re requesting two scopes. What does your request URL look like with both scopes?

I was going to. I guess I’ll also have to figure out how to get user id now. Can you take a look what’s going on with my token? Why it’s not valid? I uploaded live example:
http://phantomik.ru/catalog/ - press “Войти” in the top right corner. What will happen step by step:

  1. This link will open in popup and ask for your permissions:
    https://api.twitch.tv/kraken/oauth2/authorize?response_type=code&client_id=dkh8hc1goz4d1jkc4ekivziur4a8kq0&redirect_uri=http://phantomik.ru/oauth&scope=user_read+chat_login
  2. After you agree, Twitch will redirect inside that popup to this page, providing your code in GET:
    http://phantomik.ru/oauth?code=f8mlpl4z30yh169cdqqc22xk7v7d5t&scope=user_read+chat_login
  3. On this page I placed PHP script that will get code argument and pass it with cURL (see function above) to Twitch API on this url:
    https://api.twitch.tv/kraken/?oauth_token='.$_GET['code'].'&client_id=dkh8hc1goz4d1jkc4ekivziur4a8kq0
  4. After getting answer from Twitch API it will output answer inside that popup with PHP function var_export(). I made this just for test purposes.

Here’s function that I use to pass auth token to Twitch on step 3. I’ve added application/vnd.twitchtv.v5+json header to use API v5.

function cURL($url, $p=''){
	$ch =  curl_init();
	$options = array(
		CURLOPT_URL => $url,
		CURLOPT_HTTPHEADER => array('application/vnd.twitchtv.v5+json'),
		CURLOPT_SSL_VERIFYHOST => 0,
		CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)',
		CURLOPT_REFERER => 'http://phantomik.ru',
		CURLOPT_RETURNTRANSFER => 1,
		CURLOPT_SSL_VERIFYPEER => 0,
	);
	if ($p) {
		$options[CURLOPT_CUSTOMREQUEST] = "POST";
		$options[CURLOPT_POST] = 1;
		$options[CURLOPT_POSTFIELDS] = $p;
	}
	curl_setopt_array($ch , $options);

	$result = curl_exec($ch);
	$errorno = curl_errno($ch);
	$error = curl_error($ch);
	curl_close($ch);
	if ($errorno) {
		return array('error' => $errorno, 'result' => 'cURL Error: '.$error);
	} else {
		return json_decode($result);
	}
}

You’re using the authorization code flow and getting a code instead of a token, which is why it is coming back invalid. In the authorization code flow, you have to exchange the code to get a token. Currently, you’re trying to pass in an auth code as a token. If you want to continue using that flow, you’ll need to exchange the code for a token. Otherwise, you can get an OAuth token directly with the implicit grant flow.

Docs here for more information: https://dev.twitch.tv/docs/authentication/

3 Likes

I rly need to learn how to read lol. I totally missed step 3. Now I got it working, thanks.
One more question - what’s this?

&state=[your provided unique token]

Do I need to pass this argument? It seems like it works fine even without it. It would be better for me to not generate unique id every time someone wants to log in, less trash in my database. It’s better to generate unique id when adding new user in database, after I got everything I need from API.

It’s optional but highly recommended to prevent CSRF.

3 Likes

I guess it’s a bad idea to store token in user’s cookies + in my database and then compare those two? I have my own session id for that now. What bad can happen if someone will steal user’s token? I’m thinking about turning them into md5 hash in database.

Why do you need to compare the tokens? What are you trying to accomplish?

Losing a token is a huge deal and a violation of our Developer Agreement. A token allows you to impersonate that user and take action on their behalf. This is all tied to the scopes of the token. For example, if a token has the chat_login scope, a stolen token means the thief can chat as that user.

Do not show tokens to anyone - got it!
I’m storing my Twitch sessions locally. After I got token and info about user with token, I insert all in my database with my own generated session id. This session id also been placed in user’s cookies so he can access he’s info - nickname and avatar. This way i can identify users on my site faster, I don’t need to call Twitch API on every page. I also will be abble to block users on my site by their Twitch id or add more fields in their profiles. I think that’s a right aproach. But I’m not sure should I even store tokens in my database? I don’t see any good use of them yet.

Just set the ClientID anyway. Then ALL the headers you send to Twitch API, whether that contains a oAuth or not look the same. If in doubt just send it!

1 Like

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