Unable To Get Twitch API OAuth For PHP

I have been unable to get an OAuth token. I have spent about 4 hours trying. The various iterations and changes the Twitch API has been through is leaving me unsure and confused. The Twitch Developers now have a message posted stating V5 API being decommission on February 28th 2022. I am lost.

This is where I am at right now. The “code” below is from the Getting authorization code here.

<?php

    function file_get_contents_curl($url) {
        $curlHeader = [
            'client_id' => '"CLIENT ID"',
            'client_secret' => '"CLIENT SECRET"',
            'code' => '"POST TOKEN"',
            'grant_type' => '"AUTHENTICATION CODE"',
            'redirect_uri' => 'https://rons-home.net'
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $curlHeader);
        $data = curl_exec($ch);

        curl_close($ch);
        return $data;
    }

print_r( file_get_contents_curl( 'https://id.twitch.tv/oauth2/authorize' ) );

Response

{"status":400,"message":"missing response type"}

Any help gratefully received and appreciated.

grant_type shouldn’t be "AUTHENTICATION CODE" for start.

The linked example isn’t very good. It just goes “well heres how you pass stuff to some function that someone else wrote” nor covers the token types and likely usage, and railroads you into getting a user token.

I’m not sure if you are trying to do User tokens or an App Access Token.

This kinda looks like user token step three since you have a code but the data should not be passed as headers, they should be post fields.

This is a complete example of user authentication https://github.com/BarryCarlyon/twitch_misc/tree/main/authentication/user_access_generator/php and if you need to get an “anonomous”/public token for server to server calls, which if you are transitioning from Kraken to Helix seems more likely, then you need an App Access/Client Credentials token https://github.com/BarryCarlyon/twitch_misc/tree/main/authentication/app_access_tokens/php

So you have a number of issues in your code, firsly the fact that the data in $curlHeader should in fact be in CURLOPT_POSTFIELDS instead, additionally if this is step 3 of user oAuth, this should be a CURLOPT_POST, and right now it’s doing a GET. Hence the message you get for a invalidy created <a href for step 1 user oAuth. Which is what this code generated, loaded https://id.twitch.tv/oauth2/authorize with no paramters, when you are supposed to redirect the user here, (as all the params on step 1 need to be query string).

So, it sounds like you actually need to do is

Which will give you a token which will let you do the same thing as you were doing under v5. Since the oAuth proceedure hasn’t changed and you don’t have an existing oAuth loop to use.

The PHP code examples for generating such a token can be found here

generate_and_maintain_token.php is the most appropriate as it generates and stores a token, then resuses that token until the token is close to expiration. Which is “good practice”. This script can be setup as a cronjob, to automatically handle tokens and store the token in a DB or somewhere useful for your scripts/server calls to use.

Generally you wouldn’t store the token in a auth.json it just is in the example for simplicity of the example, and not to give an opinion on where/how to store tokens, as thats up to you.

I am initially trying to create an announcement for my web site to say I am live on Twitch. Does this change your response?

PHP is server side programming.

So you would generally use an App Access/Client Credentials token

Additionally you might want to consider EventSub instead of long polling the API

Then Twitch will tell you when your stream starts (and ends). Then store the data in your DB and do a call to your DB instead of a call to the API.

EventSub (webhook transport) also uses Client Credential tokens for this.

TLDR: No, it doesn’t change my answer.

What you are saying about EventSub makes sense.

I have a new problem. The error message has changed to:

{“status”:401,“message”:“invalid csrf token”}

Do you have any Twitch API insight as to why this might be occurring?

The current iteration of my PHP code is:

<?php

/* file_get_contents replaced with curl function - Add this function and replace any use of file_get_contents with file_get_contents_curl */

function file_get_contents_curl($url) {
    $curlField = [
        'client_id' => '"CLIENT ID"',
        'client_secret' => '"CLIENT SECRET"',
        'grant_type' => 'token',
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $curlField);
    $data = curl_exec($ch);

    curl_close($ch);
    return $data;
}

print_r( file_get_contents_curl( 'https://id.twitch.tv/oauth2/authorize' ) );

I’m not a PHP dev, but it looks like you’re attempting to GET the OAuth URL when you should be redirecting the user to that URL so that they’re on Twitch, at which point they can accept/deny the connection to your app and be redirect to your redirect uri.

Dist is correct.

For user authentication you need to redirect the user to Twitch.

But you shouldn’t be doing user authentication here. The error returned is what you get when trying to do things wrong

You need to be generating a client credentials token as outline here

Full example that chains to a streams lookup, this is semi suitable for a Cron Job. Change the // stream is live and not live lines to relevant DB writing calls.

<?php

define("CLIENT_ID", "");
define("CLIENT_SECRET", "");
define('STREAMER_ID', '');

$keys = false;
if (file_exists(__DIR__ . '/auth.json')) {
    $keys = json_decode(file_get_contents(__DIR__ . '/auth.json'));
}

$generate_token = true;
if ($keys) {
    // validate the token

    $ch = curl_init('https://id.twitch.tv/oauth2/validate');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Authorization: Bearer ' . $keys->access_token
    ));

    $r = curl_exec($ch);
    $i = curl_getinfo($ch);
    curl_close($ch);

    if ($i['http_code'] == 200) {
        // the token appears good
        $generate_token = false;

        // optional to check the expires
        $data = json_decode($r);
        if (json_last_error() == JSON_ERROR_NONE) {
            if ($data->expires_in < 3600) {
                // less than an hour left
                // make a new token
                echo 'Token close to expire. Regenerate';
                $generate_token = true;
            }
        } else {
            echo 'Failed to parse JSON. Assume dead token';
            $generate_token = true;
        }
    }
}

if ($generate_token) {
    $ch = curl_init('https://id.twitch.tv/oauth2/token');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, array(
        'client_id' => CLIENT_ID,
        'client_secret' => CLIENT_SECRET,
        'grant_type' => "client_credentials"
    ));

    $r = curl_exec($ch);
    $i = curl_getinfo($ch);
    curl_close($ch);

    if ($i['http_code'] == 200) {
        $keys = json_decode($r);
        if (json_last_error() == JSON_ERROR_NONE) {
            // store the token for next run
            file_put_contents(__DIR__ . '/auth.json', $r);
        } else {
            echo 'Failed to parse JSON';
        }
    } else {
        echo 'Failed with ' . $i['http_code'] . ' ' . $r;
        exit;
    }
}

    $ch = curl_init('https://api.twitch.tv/helix/streams?user_id='.STREAMER_ID);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Client-ID ' . CLIENT_ID,
        'Authorization: Bearer ' . $keys->access_token
    ));

    $r = curl_exec($ch);
    $i = curl_getinfo($ch);
    curl_close($ch);

    if ($i['http_code'] == 200) {
        $data = json_decode($r);
        if ($data->data && $data->data[0]) {
            // stream is live
        } else {
            // stream is not live
        }
    } else {
        echo 'Failed to get streams ' . $i['http_code'] . ' ' . $r;
    }

@Dist assumption is wrong. This code will only exist as a server API. This isn’t part of a user interface.

Then you’re using the wrong OAuth flow, the token and code flows are for User Tokens and so require sending the user to Twitch.

As Barry linked to you, you need to properly implement the client_credentials flow for an App token that can be used entirely server-side.

I am looking at https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#oauth-client-credentials-flow and Barry’s GIT ‘Notes’. Both are saying to use the URL https://id.twitch.tv/oauth2/token to get an access token. When I try this in my code and browser I get an error 404 page not found.

I did use the “Provide Feedback For This Page” link in an attempt to report this. Without this access token I don’t think I can get started. Am I right? Did the Twitch API developers break something in the removal of their API V5?

Overall what you are saying is starting to make sense to me.

For the Client Credentials flow to get an App token you don’t actually go to the URL. As shown in the documentation you make a POST request. You’re getting a 404 because you’re trying to a go to a URL in a browser that you shouldn’t be going to.

Okay. I think I am think I am down to my last question or two:

What is the “scope” I need to use for an EventSub to capture when a stream goes online?

I can easily do the coding to receive the update of going live and the stream ending in the database.

You don’t need any scope for stream online, as it’s public information. Plus scopes don’t do anything on App tokens anyway, they’re for User tokens.

You missed the part where I pointed out the different oAuth flows

Where I said you likely need the last link, not the first link.

So you mixed up on what I was telling you. Apologies for the lack of clarity

Under the heading “How To Refreshthe sample response on success doesn’t show how many seconds the new token is in effect for. Am I missing this?

The current refresh is retuend in the JSON payload that contains the Access Token itself.

Additionally App Access Tokens cannot be refreshed, you jsut get a new one

See also validating tokens Authentication | Twitch Developers

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