1

I have a Unity project making API calls to sites like Patreon and other video streaming websites no problem, but when I use the same method to use YouTube Data API v3, it doesn't seem to recognize the access token I am passing to the endpoint.

// MyYouTubeAPI.cs

[Serializable]
struct formData
{
    public string part;
    public string broadcastType;
    public string mine;
    public string key;
}

void Start()
{
    StartCoroutine(GetLatestLiveChatID());
}

IEnumerator GetLatestLiveChatID()
{
    // create instance of our class with our values

    formData data = new formData
    {
        part = "snippet%2CcontentDetails%2Cstatus",
        broadcastType = "all",
        mine = "true",
        key = apiKey
    };
    
    // convert our class to json
    string JsonData = JsonUtility.ToJson(data);

    // instance of unity web request
    UnityWebRequest www = UnityWebRequest.Post("https://youtube.googleapis.com/youtube/v3/liveBroadcasts", "GET");

    // setup upload/download headers (this is what sets the json body)
    byte[] bodyRaw = Encoding.UTF8.GetBytes(JsonData);
    www.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
    www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();

    // set your headers
    www.SetRequestHeader("Authorization", "Bearer " + accessToken); // MY ACCESS TOKEN ACTUALLY IS VALID THOUGH
    www.SetRequestHeader("Content-Type", "application/json");
    yield return www.SendWebRequest();

    if (www.isNetworkError || www.isHttpError)
    {
        Debug.Log(www.error);
        Debug.Log(www.downloadHandler.text);  // I GET THESE ERRORS IN UNITY CONSOLE
    }
    else
    {
        // Debug.Log(www.downloadHandler.text);
        jsonString = www.downloadHandler.text;
        Debug.Log(jsonString);
    }


}

However I get the following error inside the Unity console:

{
  "error": {
    "code": 401,
    "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "errors": [
      {
        "message": "Invalid Credentials",
        "domain": "global",
        "reason": "authError",
        "location": "Authorization",
        "locationType": "header"
      }
    ],
    "status": "UNAUTHENTICATED"
  }
}

My access token is completely valid, because I get the following when checking its status:

{
  "issued_to": [MY CLIENT ID],
  "audience": [MY CLIENT ID],
  "scope": "https://www.googleapis.com/auth/youtube.force-ssl",
  "expires_in": 3586,
  "access_type": "offline"
}

Sorry for my formatting, I don't post much here. Would anyone have any clue why I am running into this problem? I can't for the life of me figure out why my access token isn't being seen or recognized or passed through. But I am at my wits end. Thank you so much for anyone's help!

stvar
  • 6,551
  • 2
  • 13
  • 28
  • @stvar Hey thank you for your quick response. I did curl in Windows command prompt and it worked. I actually have been Debug.Log(accessToken) to make sure it returned something, and it always did, but looking closer I noticed the returned string is actually shorter and _different_ from my real, working access token. So somewhere at some point my accessToken variable is being altered and it shouldn't be. I hardcoded the access token next to "Bearer " in the headers and now getting a new error 400 "Title is required". So it seems authorization is working now at least. – Jon Kun2323 Sep 24 '21 at 07:36
  • @svtar Sorry ran out of characters, just wanted to say thanks again, your suspicion led to me looking closer at the accessToken variable. I'm not sure how to accept your comment as the answer. – Jon Kun2323 Sep 24 '21 at 07:38
  • Alright so if anyone is interested why I was getting the Error 400 "Title is required". I realized that the documentation says "do not include a body in the request" https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/list#request-body So I removed all the form data and reformatted my endpoint url like **ENDPOINT_PREFIX+parameters_in_a_string+ENDPOINT_SUFFIX+accessToken** And now I am getting proper JSON response with info about my channel. – Jon Kun2323 Sep 24 '21 at 08:25

1 Answers1

0

If you have access to a bash prompt (or Windows command prompt for that matter), then try the following command:

curl "https://youtube.googleapis.com/youtube/v3/liveBroadcasts?part=snippet,contentDetails,status&broadcastType=all&mine=true&access_token=YOUR_ACCESS_TOKEN".

Also try adding the access token to your composed URL: add access_token: accessToken to your formData data and remove the call to www.SetRequestHeader.

I suspect though that your variable accessToken is null or empty.

stvar
  • 6,551
  • 2
  • 13
  • 28
  • Thanks, yes my accessToken wasn't empty or null, but it is being changed or altered for some reason. I declare it as **public string accessToken = [MY ACCESS TOKEN]** at the top. But when I Debug.Log(accessToken) in the Start(), its completely different. I will try and update here if I ever find out why this is happening. – Jon Kun2323 Sep 24 '21 at 07:56
  • That's because your function `GetLatestLiveChatID` is [`yield`ing](https://stackoverflow.com/a/15977474/8327971). What is your intention there? – stvar Sep 24 '21 at 08:05
  • I am basically trying to set up my stand-alone desktop unity app to automatically start checking for my latest live video stream info, so I can get the live chat id from it, and start pulling in comments from that stream. – Jon Kun2323 Sep 24 '21 at 08:20
  • That's a higher-level description of your intention. I was asking you why are you doing `yield return www.SendWebRequest()`? – stvar Sep 24 '21 at 08:27
  • I was previously using WWW request in Unity, and this is a copy and paste method I was trying to get working to move away from obsolete WWW. I am pretty amateur so it takes me awhile to see things that aren't necessary for my needs especially when I am copying and pasting possible solutions from others. But, isn't the yield there to wait for the request to come back in order to send JSON or any errors to the console? – Jon Kun2323 Sep 24 '21 at 08:40
  • No (quote): *isn't the yield there to wait for the request to come back in order to send JSON or any errors to the console*. See: [What is yield and how does it work in C#?](https://pvs-studio.com/en/blog/posts/csharp/0808/) – stvar Sep 24 '21 at 08:48