ASP.NET Core - The OAuth YouTube Data API Dance
Tags: aspnetcore, youtube, razor, oauth
Published: 2020-08-24 02:34:09

---
title: ASP.NET Core - The OAuth YouTube Data API Dance
published: true
description: "Steps through the process of working with YouTube Data API  using OAuth2.0 HTTP/REST to upload YouTube videos using an ASP.NET Core Razor pages application."
tags: ["aspnetcore", "YouTube", "Razor", "oauth"]
canonical_url: https://kags.me.ke/post/youtube-data-api-razor-project/
---

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rihyk053suw3lq88n69p.png)

## Introduction

 YouTube Data API allows developers to add YouTube features to their applications. Using the API, a developer can upload and search for videos among many other features on behalf of the YouTube channel owner. In this post, we start by creating a Google project so that we can acquire credentials to access the YouTube API. We then create a Razor Pages application and use HTTP/REST to  call the OAuth 2.0 endpoints. The Razor Pages application user feedback will rely on the logging output from the Visual Studio Code Debug Console for feedback.

## Prerequisites

- A Google account (not a Brand Account) and an existing YouTube Channel. Though not necessary,  a  [verified account](https://support.google.com/youtube/answer/171664) will allow you to upload videos larger than 15 minutes, add custom thumbnails among other features.

- Downloaded and installed the .NET SDK (Software Development Kit). You need .NET SDK to create the Razor Pages application.

-  A text editor for editing source code. We will be using [Visual Studio Code](https://code.visualstudio.com/) but you are free to follow along using your favourite editor.

## The YouTube Data API Dance

We can broadly break down the process of working with the YouTube Data API  into two phases:

**A. Configure Google YouTube Data API project** 

  The following are steps to complete this phase:

  1. Create a Google application project. A project is a grouping of settings and API access information.

  1. Enable YouTube Data API v3 service

  1. Configure User Consent Screen for the YouTube channel owner authorization. 

  1. Create OAuth client Credentials. 

**B. Using YouTube Data API In Your Application**.

  1. Create ASP.NET Core Razor Pages application

  1. Request Temporary Authorization Code

  1. Exchange Authorization Code With Access Token

  1. Use access token to upload videos

## A. Configure Google YouTube Data API Project

### Create Google Project

1. Navigate to [create new project page](https://console.developers.google.com/projectcreate).

2. Google generates a project name and project ID for you. You can customize the project name and ID or accept the suggested values. Take note that you cannot change a project's ID after creation.  For this post, let's name the project as **YouTubeApiTest**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ttsrqhy15enutcim0qc4.png)

3. Click on **CREATE** button. A notification dialog appears when the project creation completes. Click on **VIEW** link on the notifications dialog. This will take you to the project's page.

1. Click on the hamburger menu (top left of page preceding the Google APIs logo)  and select **APIs & Services** > **Library**. This will display a listing of Google APIs. Scroll down and select  **YouTube Data API v3** and click on **ENABLE** button to enable YouTube Data API v3.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/pxstjsoxcretete33tlz.png)

You can also search for the YouTube Data API by typing in the search box.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1a7mfips06odey0sderu.png)

###  Configure User Consent Screen 

Before an application can use the YouTube Data API to upload videos on behalf of the YouTube channel's owner, the owner has to grant an authorization. Google authorization server presents a consent request to the owner. The owner may allow or cancel the consent;  authorization needs to happen only once. 

1. Click on **Credentials** from sidebar menu.

2. Click on **CONFIGURE CONSENT SCREEN** button.

3. Under **User Type**, select **External** and then click on **CREATE** button.  This will open a new page where you can provide further information about the application.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/f93m5f0jh5cv1cbem3b6.png)

4. Type your **Application Name**. You can use the same  name as your project's name (YouTubeApiTest) or type a more descriptive name

5. Provide a logo for your application. This step is optional. If you however add or modify a logo, your consent screen will require verification by Google. Take note that no option exists for removing a logo. You can however schedule a project for deletion (shut down) after 30 days.

6. Under  **Scopes for Google APIs**, click on **Add scope** button.  Select **YouTube Data API v3** which has a description of **Manage your YouTube videos** and click on **ADD** button. Scopes grant an applications different levels of access on behalf of the end user.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wwhr9p36vveqndxki8et.png)

7. Scroll down and click on **Save** button. After the saving process has completed, a summary page of the project with its limitations displays.

### Create OAuth client Credentials

When using an application on behalf of a user to upload videos, edit playlists or anything that would require a user  log in, authorized access using an OAuth 2.0 workflow is required (Client Id and a Secret Key). In situations where your interest would be only in searching for publicly available videos and playlists, then an API key would have been the most appropriate.

1. Click on **Credentials** on the sidebar menu

1. Click on **+ CREATE CREDENTIALS** (at top of page) and select **OAuth client ID**. 

1. Under **Application type**, select an application type. Select **Web application**. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/21aau7m27szl1gmaeeyp.png)

1. Type a name for the application or use the value of the suggested application name.

1. Under **Authorized redirect URIs**, click on **+ ADD URI** button. Redirect URIs will be the endpoints where the authorizing server will redirect responses from the YouTube Data API for errors, authorization code and access tokens.  For this  post, our redirect will be **https://localhost:5001/videos/upload?handler=authorize**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/z40898lnoeuixq7tl3ya.png)

1. Click on **CREATE** button. This will display an OAuth client created modal window.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t7d27ncziy14zlvy3ic6.png)

1. Click **OK** to close the OAuth client created confirmation window

1. Under **OAuth 2.0 Client IDs** section, select the client ID you have created and click on the download file icon (far right) to   download the Client OAuth ID json file. After the download completes, rename the file to _client_secrets.json_. You can use  a different name or use the assigned name.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/cqlmu6hyygv7bwkk8jvt.png)

That concludes the first phase of setting up the YouTube Data API project.

## B. Using YouTube Data API In Your Application

### Create ASP.NET Core Razor Pages Application

1. Open a Terminal window and navigate to the location where you wish to create your project

1. Create a Razor project by running the following command `dotnet new razor -o YouTubeApiTest`

1. Open the project by running `code YouTubeApiTest`. 

1. Click **Yes** when the **Required assets to build and debug are missing from 'YouTubeApiTest'. Add them?** dialog is displayed.

### Create Video Upload Page

1. Create a _Videos_ folder within the _Pages_ folder. This is not mandatory; you can create the upload page in a folder of your liking. For this post, we will place files related to the YouTube upload in this folder.

1. Create _Upload.cshtml_ content page within the _Videos_ folder. This first line of the file will contain `@page {handler?}` directive. This will allow us to access the upload route using `https://localhost:5001/videos/upload` or using the optional method handler `https://localhost:5001/videos/upload/authorize`. Update the file with the following code: 
{% gist https://gist.github.com/kagundajm/5466098a9090e80c6e7cd1058bae1d63 %}

1. Create a new a page model file _Upload.cshtml.cs_. This file will contain code relating to processing of user input data. Update the file using the following code:  
{% gist https://gist.github.com/kagundajm/e15ea7d5e679d2f44ecac64a66219004 %}

1. Just for aesthetics, let's update *wwwroot\css\site.css* with the following:
{% gist https://gist.github.com/kagundajm/34872808b06b63e379fbcc48e8afba49 %}

1. Open _\Pages\Shared\_Layout.cshtml_ layout page and add a link for opening the YouTube uploads page.
{% gist https://gist.github.com/kagundajm/aefbf11bc534e4dbcb5213d3221bf444 %}

1. Run the project by selecting **Run** > **Run Without Debugging** from the menu or by pressing **Ctrl + F5** and click on YouTube link to open the the videos upload page
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ky95huqixs0vx9clv4ou.png)

### Request Temporary Authorization Code

The request for the temporary authorization code will require approval from the owner of the YouTube  channel. For this to happen, we redirect the request for the code  to Google Authorization Server. A redirect will include the user credentials contained in the JSON file we downloaded when we created the Google project in the first phase. Request for the code will only be necessary if no token file exists.

1. If you did not download the OAuth credentials file, download the file, copy/move it to the root of the project and rename to *client_secrets.json*. If you are using a version control system for the project, make sure to exclude the file from versioning.

1. Create *OAuthClientInfo.cs* file  at the root of the project. We will use this class to read and store the contents of the _client_secrets.json_. Update the file using following code:
{% gist https://gist.github.com/kagundajm/a3ad74f8564e2bd9bc624bdc7c2046f7 %}

1. Open the terminal window and add the YouTube Data API package to the project by running `dotnet add package Google.Apis.YouTube.v3` command.

1. Within _Upload.cshtml.cs_ page model file, add a `OnGetRequestCode()` method. This method will read the contents of the OAuth credentials file and use the contained values to authenticate and request an authorization code from the Google Authorization server. When the user allows the authorization, the authorization server will return a temporary authorization code (`response_type`). A cancellation of authorization will return an error. Google authorization server will send the error or temporary authorization code response to the `redirect_url` we specified during Google project creation. Setting `access_type` to `offline` will ensure our application can refresh access tokens without the user being present at the browser.
{% gist https://gist.github.com/kagundajm/123f826b73a628ca730d7c0991f97850 %}

We require to create a constant for the token file name `const string TOKEN_FILE = "youtube_token.json";` and add `using System.Linq;`, `using System;`, `using System.Collections.Generic;`, `using Microsoft.AspNetCore.WebUtilities;` and `using Google.Apis.YouTube.v3;` namespaces to the page model.

### Exchange Authorization Code With Access Token

This step is dependant on the owner/user of the YouTube channel granting or denying access to our application. If the owner cancels the request, Google authorization server sends an error response to our application's redirect uri and the story ends there. If on the other hand the owner allows access, we parse the authorization code from  the query string of the response, exchange the authorization code for a short-lived (one hour) access token and long-lived (six months) refresh token and persist these to a file for future retrieval and usage.

1. Create the redirect URI endpoint by adding a _OnGetAuthorize_ handler method within the _Upload.cshtml.cs_ file.

1. Add code to handle error responses. The code will also log the errors so we can get feedback on the errors.
{% gist https://gist.github.com/kagundajm/4576115ca916bdc9895e97e8659f9767 %}

1. Let's test errors can hit our redirect URI. Run the project, click on the YouTube link and finally click **Request authorization code** button. On the **Sign in with Google** page, select your account. A warning **This app isn't verified** page appears. Click **Advanced** > **Go to YouTube API Test (unsafe)**. Click on **Cancel**. You get returned to the  video upload page and an error log entry will appear on the **DEBUG CONSOLE**.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ys1acrovse5qvfumifdw.png)

1. Before we can write code to handle exchanging the authorization code for a token, we need to make  some changes to _Startup.cs_ in the root of the project. We need to  add `services.AddHttpClient();` to the `ConfigureServices`. This will enable us to make requests using HttpClient. 

1. The next change will be in the constructor of the upload page model (_Upload.cshtml.cs_). Replace the current constructor method signature with `public UploadModel(ILogger<UploadModel> logger, IHttpClientFactory clientFactory, IWebHostEnvironment hostingEnvironment)`, import required namespaces (`using System.Net.Http;` and `using Microsoft.AspNetCore.Hosting;`)    and add relevant field variables. `IWebHostEnvironment` will be used in generation of the token file name.

1. Add code within `OnGetAuthorize` method for extracting the authorization code from the request. The code calls `ExchangeCodeForTokenAsync` which we will add in the next step.
{% gist https://gist.github.com/kagundajm/61270ede243fd4c70cf83b4a890684b8 %}

1. Add a method `ExchangeCodeForTokenAsync` which will request for the code/token exchange and on success, persist the token data to a token file. This method will require you import `using System.Text;` namespace in order to use UTF8 encoding.
{% gist https://gist.github.com/kagundajm/ecc5a193bf3aeac48a453a40f027d994 %}

1. Run the project, click on the YouTube link and finally click **Request authorization code** button. Follow the process we performed above while testing for errors but this time click on **Allow** button so that the authorization server can grant an authorization code. When the process completes, you will see **authorization code granted** and **Token exchanged with access token** messages on the **DEBUG CONSOLE**. Also, within project's root folder, _youtube_token.json_ file will  is created.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b3aj7s1dgho2iovvbekd.png)

The following are the contents of the token file:

{% gist https://gist.github.com/kagundajm/5410c62cbd8f9069a038bbbaec8aaae5 %}

We will use the `access_token` to make requests to YouTube Data API for authorization. Note that any application code that shares the same client ID and secret pair can use the same access token. The access token will expire after one hour after which we will renew the token using the `refresh_token`. 

A refresh token may also [become invalid](https://developers.google.com/identity/protocols/oauth2#expiration) under the following conditions: 
  - The user has revoked the application's access.
  - The refresh token remains unused for six months.
  - The user changed passwords and the refresh token contains Gmail scopes.
  - Granted refresh tokens for the user's account have been exceeded (limited to 50 refresh tokens per user account per client). 
  - a new refresh token has been granted

### Use Access Token To Upload Videos

The final step will be using the access token to upload YouTube videos. This step will involve selecting the video you wish to upload, providing the title and description for the video and clicking on the upload video button.

When the upload video button gets clicked, we fetch the video data and persist the video file data in a temporary file. Next we fetch and validate the token. If the token is no longer valid, we obtain a new token using the refresh token. Finally, we use the YouTube Data API and delete the temporary video file.

1. To persist the video file to a temporary file, create a field variable `private string _tempFilePath;` within _Upload.cshtml.cs_ for the filename and then override the `OnPageHandlerExecuting` page filter. This method will get called after model binding but before the code for video uploading runs. You will also require to import the following namespaces, `System.IO` and `Microsoft.AspNetCore.Mvc.Filters`.
{% gist https://gist.github.com/kagundajm/ec693e89029ed7da4ea3506b0214c1c7 %}

1. Create a `OnPostAsync` handler method. This handler method gets invoked when the uploaded video button gets clicked. This handler method calls various support methods to perform different tasks.
{% gist https://gist.github.com/kagundajm/80dbee44e82053e6f753b6b5f0fd40f1 %}

`GetVideoData` does nothing much except creating an instance of YouTube video. It requires importation of the `Google.Apis.YouTube.v3.Data` namespace.

{% gist https://gist.github.com/kagundajm/53cdcdde25f49dc54b3e4595dba38007 %}

`FetchToken` reads token data from the token file, validates the token and if not valid fetches a new token using the refresh token. This method relies on `IsValid` and `RefreshToken` helper methods. The method requires `System.Threading.Tasks`, `System.Text.Json` and `Google.Apis.Auth.OAuth2.Responses` namespaces.

{% gist https://gist.github.com/kagundajm/e1cab6564138be6dcce5fbad49ea1fb7 %}

`IsValid` validates the token with the Google Authorization server. If the response does not contain an `error_description` then the token is valid.

{% gist https://gist.github.com/kagundajm/384e3323a804f9e2712028980c622b4c %}

The `RefreshToken` method gets called only if the persisted token is not valid. Using the user credentials and the refresh token, the method requests for a new token from the Google Authorization server and persist the new token to a file replacing the invalid token.
  
{% gist https://gist.github.com/kagundajm/03b2dffad1c4c7cce5d691ab208c9b9c %}

`FetchYouTubeService` creates an instance of the `YouTubeService` which we use to upload the selected video. This method requires the importation of `Google.Apis.Auth.OAuth2.Flows`, `Google.Apis.Auth.OAuth2`, `Google.Apis.Services` and `System.Reflection` namespaces. 
  
{% gist https://gist.github.com/kagundajm/ddff9b7717d64ca603678419862463b6 %}

Finally, we register a `ProgressChanged` changed event (will require importation of `Google.Apis.Upload` namespace) to monitor the upload process

{% gist https://gist.github.com/kagundajm/87196bf94c907663ced2f89053b78361 %}

and `ResponseReceived` event which gets  invoked after video upload completes. After  video upload completes, we  delete the temporary video file.

{% gist https://gist.github.com/kagundajm/8532361d372a7c8c8ed631751b066b5e %}

To test uploading videos, run the application, open the YouTube videos upload page, search for the video you want to upload, complete title and description of the video and click on the **Video upload** button. Make sure to select a video that [does not exceed 28.6MB](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel#maximum-request-body-size) otherwise you will end up getting a  **BadHttpRequestException:Request body too large** exception. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/91e73qa5tck7f9nb1nds.png)

That brings us to the end of uploading YouTube videos using HTTP/REST and I hope  the post has been helpful.

## Additional Links

- [Using OAuth 2.0 for Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server)
- [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)