Mac Hooper
Mac Hooper

Reputation: 93

Understand why uploading video via curl returns an authentication error

I am trying to upload to YouTube via the API. I am doing so with curl and when am running following command I receive an error saying that am not unauthenticated, even though I have filled out the authentication details.

My code is:

curl -XPOST -H 'client_id: CLIENT_ID' -H 'client_secret: CLIENT_SECRET' -H 'auth_uri: https://accounts.google.com/o/oauth2/auth' -H 'token_uri: https://oauth2.googleapis.com/token' -H "Content-type: application/json" -d '{
    "snippet": {
        "title": "Test Title",
        "description": "Test description",
        "tags": ["test", "tags"],
        "categoryId": 20
    },
    "status": {
        "privacyStatus": "unlisted"
    }
}' 'https://www.googleapis.com/upload/youtube/v3/videos'

Error message is 401:

Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.

I have 100% put in the client_id and client_secret correctly.

Upvotes: 1

Views: 973

Answers (2)

Linda Lawton - DaImTo
Linda Lawton - DaImTo

Reputation: 117116

If you go to the documentation for video.insert you will find an example of how the upload works in curl.

curl --request POST \
  'https://youtube.googleapis.com/youtube/v3/videos?key=[YOUR_API_KEY]' \
  --header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{}' \
  --compressed

You appear to be missing a number of the headers that are required mainly that of the access token which is passed as a bearer token. What you need to understand is that the client_id and client_secret are used to CREATE the access token they do not by themselves grant you access to any data.

An access token needs to be created using the Oauth2 flow. I have a gist that shows how this can be done. YOu will need to use the https://www.googleapis.com/auth/youtube.upload scope

# Client id from Google Developer console
# Client Secret from Google Developer console
# Scope this is a space seprated list of the scopes of access you are requesting.

# Authorization link.  Place this in a browser and copy the code that is returned after you accept the scopes.
https://accounts.google.com/o/oauth2/auth?client_id=[Application Client Id]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=[Scopes]&response_type=code

# Exchange Authorization code for an access token and a refresh token.

curl \
--request POST \
--data "code=[Authentcation code from authorization link]&client_id=[Application Client Id]&client_secret=[Application Client Secret]&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code" \
https://accounts.google.com/o/oauth2/token

# Exchange a refresh token for a new access token.
curl \
--request POST \
--data 'client_id=[Application Client Id]&client_secret=[Application Client Secret]&refresh_token=[Refresh token granted by second step]&grant_type=refresh_token' \
https://accounts.google.com/o/oauth2/token

Upvotes: 0

stvar
stvar

Reputation: 6975

Unfortunately, @Mac Hooper, your code suffers very badly from a whole lot of issues. Please bear with me for a while:

  1. You have to acknowledge that video uploading (that is using the Videos.insert API endpoint) has to be properly authorized:

Authorization
This request requires authorization with at least one of the following scopes (read more about authentication and authorization).

Scope
https://www.googleapis.com/auth/youtube.upload
https://www.googleapis.com/auth/youtube
https://www.googleapis.com/auth/youtubepartner
https://www.googleapis.com/auth/youtube.force-ssl

  1. Uploading videos using the YouTube Data API cannot be done as simple as you're trying to do it. Although not officially documented as such, the API supports two kinds of uploading procedures:

    a. Resumable uploads, and
    b. One-go uploads.

The resumable uploads are achieved by means of the officially documented Resumable Uploading Protocol.

The resumable uploading protocol is quite tricky to correctly be implemented regardless of the implementation language/environment. Google provides open-source code that implements the protocol for a plethora of languages/environments. Although it is achievable, I'd recommend against implementing this protocol in shell scripts using curl.

On the other hand, uploading videos in one go is what you'll have to do if expecting to issue only one curl call per video upload (excluding the calls implied by the procedure of obtaining an access token). But that curl call requires certain things to be prepared beforehand.

There's this answer of mine that indicated the path to be taken when employing curl in one-go uploads.

Basically, your curl call would look like the one below:

$ curl \
--data-binary "@$MULTIPART_RELATED" \
--header "Content-Type: $CONTENT_TYPE" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
'https://www.googleapis.com/upload/youtube/v3/videos?uploadType=multipart&part=snippet,status'

(Do note that above I presume issuing curl at a bash command line prompt. When being at a Windows command line prompt things work similarly, but the above curl command should properly be adapted.)

The curl command above has three parameters: $MULTIPART_RELATED, $CONTENT_TYPE and $ACCESS_TOKEN. The latter is your credentials data that gets passed on to YouTube's server such that your API call be authorized.

Do read the section Obtaining OAuth 2.0 access tokens of the official document OAuth 2.0 for Mobile & Desktop Apps for to see how to obtain a valid (non-expired) access token upon completing successfully an OAuth 2 authentication/authorization flow.

The parameter $MULTIPART_RELATED is the name of the file you should have composed (programmatically) before issuing the actual curl call. The format of this file is not documented officially as such, but is derived upon inspecting Google's own open-source code.

The parameter $CONTENT_TYPE is a string that specifies the Content-Type header needed by the HTTP POST method to be issued via curl.

Again, my answer to the SO question How to upload video to youtube using google api. Without libraries provides all the details for one to be able to generate properly the file $MULTIPART_RELATED and the string $CONTENT_TYPE.

Upvotes: 1

Related Questions