This document describes OAuth 2.0,
when to use it,
how to acquire client IDs,
and how to use it with the Google API Client Library for .NET.

## OAuth 2.0 Protocol


OAuth 2.0 is the authorization protocol used by Google APIs.
You should get familiar with the protocol by reading the following links:

- [The OAuth 2.0 Authorization Protocol](https://tools.ietf.org/html/rfc6749)
- [Using OAuth 2.0 to Access Google APIs](https://developers.google.com/accounts/docs/OAuth2)

## Acquire client IDs and secrets


You can get client IDs and secrets on the [Google API Console](https://console.cloud.google.com/).
There are different types of client IDs,
so be sure to get the correct type for your application:

- [Web application](https://developers.google.com/accounts/docs/OAuth2WebServer) client IDs
- [Installed application](https://developers.google.com/accounts/docs/OAuth2InstalledApp) client IDs
- [Service account](https://developers.google.com/accounts/docs/OAuth2ServiceAccount) client IDs

> [!WARNING]
> **Warning**: Keep your client secret private. If someone obtains your client secret, they could use it to consume your quota, incur charges against your Google API Console project, and request access to user data.


In each of the code snippets shown (except the Service account one), you have to download the
client secret and store it as `client_secrets.json` in your project.

> [!NOTE]
> **Note:** You must change the Build action to "Content" and the Copy to Output Directory to "Copy if newer" in the IDE for `client_secrets.json`. For more information about client secrets take a look in the [Client Secrets](https://developers.google.com/api-client-library/dotnet/guide/aaa_client_secrets) page.

## Credentials

> [!WARNING]
> **Important:** : If you accept a credential configuration (credential JSON/File/Stream) from an external source for authentication to Google Cloud, you must validate it before providing it to any Google API or library. Providing an unvalidated credential configuration to Google APIs can compromise the security of your systems and data. For more information, refer to [Validate credential configurations from external sources](https://cloud.google.com/docs/authentication/external/externally-sourced-credentials).

### User credentials


[`UserCredential`](https://googleapis.dev/dotnet/Google.Apis.Auth/latest/api/Google.Apis.Auth.OAuth2.UserCredential.html)
is a thread-safe helper class for using an access token to access protected resources.
An access token typically expires after 1 hour,
after which you will get an error if you try to use it.


[`UserCredential`](https://googleapis.dev/dotnet/Google.Apis.Auth/latest/api/Google.Apis.Auth.OAuth2.UserCredential.html)
and
[`AuthorizationCodeFlow`](https://googleapis.dev/dotnet/Google.Apis.Auth/latest/api/Google.Apis.Auth.OAuth2.Flows.AuthorizationCodeFlow.html)
take care of automatically "refreshing" the token, which means getting
a new access token.
This is done using a long-lived refresh token, which you receive along with the
access token if you use the
[`access_type=offline`](https://developers.google.com/accounts/docs/OAuth2Login#refresh-tokens)
parameter during the authorization code flow.


In most applications, it is advisable to store the
credential's access token and refresh token in persistent storage.
Otherwise, you will need to present the end user with an
authorization page in the browser every hour, because the access
token expires an hour after you've received it.


To make sure the access and refresh tokens persist,
you can provide your own implementation of
[`IDataStore`](https://googleapis.dev/dotnet/Google.Apis.Core/latest/api/Google.Apis.Util.Store.IDataStore.html),
or you can use one of the following implementations provided by the library:

- [`FileDataStore`](https://googleapis.dev/dotnet/Google.Apis/latest/api/Google.Apis.Util.Store.FileDataStore.html) for .NET ensures that the credential will be persistent in a file.

### ServiceAccountCredential


[`ServiceAccountCredential`](https://googleapis.dev/dotnet/Google.Apis.Auth/latest/api/Google.Apis.Auth.OAuth2.ServiceAccountCredential.html)
is similar to `UserCredential`, but it serves a different purpose.
Google OAuth 2.0 supports server-to-server interactions such as those between a web application and Google Cloud Storage.
The requesting application has to prove its own identity to gain access to an API, and an end user doesn't have to be involved.
`ServiceAccountCredential` stores a private key, which is used to sign a request to get a new access token.


Both `UserCredential` and `ServiceAccountCredential` implement
[`IConfigurableHttpClientInitializer`](https://googleapis.dev/dotnet/Google.Apis.Core/latest/api/Google.Apis.Http.IConfigurableHttpClientInitializer.html)
so you can register each of these as:

- An unsuccessful response handler, so it will refresh the token if it receives an HTTP `401` status code.
- An interceptor, to intercept the `Authorization` header on every request.

## Installed applications


Sample code using the [Books API](https://developers.google.com/books/docs/v1/getting_started):

```
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Books.v1;
using Google.Apis.Books.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;

namespace Books.ListMyLibrary
{
    /// <summary>
    /// Sample which demonstrates how to use the Books API.
    /// https://developers.google.com/books/docs/v1/getting_started
    /// <summary>
    internal class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Books API Sample: List MyLibrary");
            Console.WriteLine("================================");
            try
            {
                new Program().Run().Wait();
            }
            catch (AggregateException ex)
            {
                foreach (var e in ex.InnerExceptions)
                {
                    Console.WriteLine("ERROR: " + e.Message);
                }
            }
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }

        private async Task Run()
        {
            UserCredential credential;
            using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
            {
                credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    new[] { BooksService.Scope.Books },
                    "user", CancellationToken.None, new FileDataStore("Books.ListMyLibrary"));
            }

            // Create the service.
            var service = new BooksService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "Books API Sample",
                });

            var bookshelves = await service.Mylibrary.Bookshelves.List().ExecuteAsync();
            ...
        }
    }
}
  
```

-
  In this sample code a new `UserCredential` instance is created by calling the
  `GoogleWebAuthorizationBroker.AuthorizeAsync` method.
  This static method gets the following:

  - The client secret (or a stream to the client secret).
  - The required scopes.
  - The user identifier.
  - The cancellation token for cancelling an operation.
  - An optional datastore. If the datastore is not specified, the default is a `FileDataStore` with a default `Google.Apis.Auth` folder. The folder is created in `Environment.SpecialFolder.ApplicationData`.
-
  The `UserCredential` that is returned by this method is set as a `HttpClientInitializer`
  on the `BooksService` (using the initializer).
  As explained earlier, `UserCredential` implements an
  [HTTP client initializer](https://googleapis.dev/dotnet/Google.Apis.Core/latest/api/Google.Apis.Http.IConfigurableHttpClientInitializer.html).

-
  Notice that in the sample code, the client secret information is loaded from a file,
  but you can also do the following:

  ```
  credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
      new ClientSecrets
      {
          ClientId = "PUT_CLIENT_ID_HERE",
          ClientSecret = "PUT_CLIENT_SECRETS_HERE"
      },
      new[] { BooksService.Scope.Books },
      "user",
      CancellationToken.None,
      new FileDataStore("Books.ListMyLibrary"));
        
  ```


Take a look at our [Books sample](https://github.com/google/google-api-dotnet-client-samples/tree/master/Books.ListMyLibrary).

## Web applications (ASP.NET Core 3)


Google APIs support
[OAuth 2.0 for Web Server Applications](https://developers.google.com/accounts/docs/OAuth2WebServer).


The [Google.Apis.Auth.AspNetCore3](https://www.nuget.org/packages/Google.Apis.Auth.AspNetCore3/) is the recommended library to use for most Google based
OAuth 2.0 scenarios in ASP.NET Core 3 applications. It implements a Google-specific
`OpenIdConnect` auth handler. It supports incremental auth, and defines an injectable
`IGoogleAuthProvider` to supply Google credentials that can be used with Google APIs.


This section describes how to configure and use Google.Apis.Auth.AspNetCore3. The code shown
here is based on
[Google.Apis.Auth.AspNetCore3.IntegrationTests](https://github.com/googleapis/google-api-dotnet-client/tree/master/Src/Support/Google.Apis.Auth.AspNetCore3.IntegrationTests) which is a fully working, standard ASP.NET
Core 3 application.


If you want to follow along this documentation as a tutorial, you will need your own ASP.NET
Core 3 application and to complete these steps as a prerequisite.

### Prerequisites

- Install the [Google.Apis.Auth.AspNetCore3](https://www.nuget.org/packages/Google.Apis.Auth.AspNetCore3/) package.
- We are using the [Google Drive API](https://developers.google.com/drive) so you'll also need to install the [Google.Apis.Drive.v3](https://www.nuget.org/packages/Google.Apis.Drive.v3/) package.
- Create a Google Cloud project if you don't have one already. Follow [these instructions](https://cloud.google.com/resource-manager/docs/creating-managing-projects) to do so. This will be the project your app is identified with.
- Make sure to enable the Google Drive API. To enable APIs, follow [these instructions](https://developers.google.com/identity/protocols/oauth2/web-server#enable-apis).
- Create authorization credentials that will identify your app to Google. Follow [these instructions](https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred) to create authorization credentials and download the `client_secrets.json` file. Two highlights:
  - Notice that the credentials' type must be *Web application*.
  - For running this app, the only redirect URI you need to add is `https://localhost:5001/signin-oidc`.

### Configure your application to use Google.Apis.Auth.AspNetCore3


Google.Apis.Auth.AspNetCore3 is configured in the `Startup` class or similar
alternative you might be using. The following snippets are extracted from
[`Startup.cs`](https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth.AspNetCore3.IntegrationTests/Startup.cs) in the Google.Apis.Auth.AspNetCore3.IntegrationTests project.

- Add the following using directive to your `Startup.cs` file.

  ```
  using Google.Apis.Auth.AspNetCore3;
  ```
- In the `Startup.ConfigureServices` method add the following code, changin the Client ID and Client Secret placeholders with the values contained in the `client_secrets.json` file. You can load these values directly from the JSON file or you can store them in any other secure manner. Take a look at the [`ClientInfo.Load`](https://github.com/googleapis/google-api-dotnet-client/blob/d79fd199a45ed803348ab8c8381a527a8ad447cf/Src/Support/Google.Apis.Auth.AspNetCore3.IntegrationTests/ClientInfo.cs#L31) method in the Google.Apis.Auth.AspNetCore3.IntegrationTests project for an example on how to load these values directly from the JSON file.

  ```
  public void ConfigureServices(IServiceCollection services)
  {
      ...

      // This configures Google.Apis.Auth.AspNetCore3 for use in this app.
      services
          .AddAuthentication(o =>
          {
              // This forces challenge results to be handled by Google OpenID Handler, so there's no
              // need to add an AccountController that emits challenges for Login.
              o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
              // This forces forbid results to be handled by Google OpenID Handler, which checks if
              // extra scopes are required and does automatic incremental auth.
              o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
              // Default scheme that will handle everything else.
              // Once a user is authenticated, the OAuth2 token info is stored in cookies.
              o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          })
          .AddCookie()
          .AddGoogleOpenIdConnect(options =>
          {
              options.ClientId = {YOUR_CLIENT_ID};
              options.ClientSecret = {YOUR_CLIENT_SECRET};
          });
  }
        
  ```
- In the `Startup.Configure` method make sure to add ASP.NET Core 3 authentication and authorization middleware components to the pipeline, as well as HTTPS redirections:

  ```
  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
  {
      ...
      app.UseHttpsRedirection();
      ...

      app.UseAuthentication();
      app.UseAuthorization();

      ...
  }
        
  ```

  > [!NOTE]
  > **Note:** To understand why you need to use HTTPS redirection, read the docs around [SameSite cookie changes](https://docs.microsoft.com/en-us/aspnet/core/migration/30-to-31#react-to-samesite-cookie-changes) introduced in ASP.NET Core 3.1. Basically, for OpenId authentication scenarios to work, cookies exchanged with the identity server must be set to `SameSite=None` which also requires these cookies to be secured. If your application supports HTTP requests, then you can secure identity cookies supporting HTTPS also and configuring HTTPS redirection.

### Use the user credential to access Google APIs on their behalf


You are now ready to add action methods to your controllers that require the user credential to
access Google APIs on their behalf. The following snippet shows how to list the files on the
authenticated user's Google Drive account. Notice two things mostly:

- The user not only needs to be authenticated, but they also need to have granted the `https://www.googleapis.com/auth/drive.readonly` scope to your application, which you specify using the `GoogleScopedAuthorize` attribute.
- We are using ASP.NET Core 3's standard dependency injection mechanism to receive an `IGoogleAuthProvider` that we use to obtain the user's credentials.


The code:

- First add the following using directives to your controller.

  ```
  using Google.Apis.Auth.AspNetCore3;
  using Google.Apis.Auth.OAuth2;
  using Google.Apis.Drive.v3;
  using Google.Apis.Services;
        
  ```
- Add the controller action, as follows (and accompany it with a view that receives a `IList<string>` model):

  ```
  /// <summary>
  /// Lists the authenticated user's Google Drive files.
  /// Specifying the <see cref="GoogleScopedAuthorizeAttribute"> will guarantee that the code
  /// executes only if the user is authenticated and has granted the scope specified in the attribute
  /// to this application.
  /// </summary>
  /// <param name="auth">The Google authorization provider.
  /// This can also be injected on the controller constructor.</param>
  [GoogleScopedAuthorize(DriveService.ScopeConstants.DriveReadonly)]
  public async Task<IActionResult> DriveFileList([FromServices] IGoogleAuthProvider auth)
  {
      GoogleCredential cred = await auth.GetCredentialAsync();
      var service = new DriveService(new BaseClientService.Initializer
      {
          HttpClientInitializer = cred
      });
      var files = await service.Files.List().ExecuteAsync();
      var fileNames = files.Files.Select(x => x.Name).ToList();
      return View(fileNames);
  }
        
  ```


And these are the basics. You can take a look at
[`HomeController.cs`](https://github.com/googleapis/google-api-dotnet-client/blob/master/Src/Support/Google.Apis.Auth.AspNetCore3.IntegrationTests/Controllers/HomeController.cs) from the Google.Apis.Auth.AspNetCore3.IntegrationTests project
to find out how you can achieve:

- User authentication only, with no specific scopes
- User logout
- Incremental authorization with code. Notice that the sample shows incremental authorization with attributes.
- Examine granted scopes
- Examine access and refresh tokens
- Force refresh the access token. Notice that you don't have to do this yourself because Google.Apis.Auth.AspNetCore3 will detect if the access token is expired or close to expiring and will automatically refresh it.

## Service account


Google APIs also support
[Service accounts](https://developers.google.com/accounts/docs/OAuth2ServiceAccount).
Unlike the scenario in which a client application requests access to an end-user's data,
service accounts provide access to the client application's own data.


Your client application signs the request for an access token using a private key downloaded
from the [Google API Console](https://console.cloud.google.com/).
After creating a new client ID, you should choose a Service Account
application type and then you can download the private key.
Take a look at our
[service account sample using Google Plus API](https://github.com/google/google-api-dotnet-client-samples/tree/master/Plus.ServiceAccount).

```
using System;
using System.Security.Cryptography.X509Certificates;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Plus.v1;
using Google.Apis.Plus.v1.Data;
using Google.Apis.Services;

namespace Google.Apis.Samples.PlusServiceAccount
{
    /// <summary>
    /// This sample demonstrates the simplest use case for a Service Account service.
    /// The certificate needs to be downloaded from the Google API Console
    /// <see cref="https://console.cloud.google.com/">
    ///   "Create another client ID..." -> "Service Account" -> Download the certificate,
    ///   rename it as "key.p12" and add it to the project. Don't forget to change the Build action
    ///   to "Content" and the Copy to Output Directory to "Copy if newer".
    /// </summary>
    public class Program
    {
        // A known public activity.
        private static String ACTIVITY_ID = "z12gtjhq3qn2xxl2o224exwiqruvtda0i";

        public static void Main(string[] args)
        {
            Console.WriteLine("Plus API - Service Account");
            Console.WriteLine("==========================");

            String serviceAccountEmail = "SERVICE_ACCOUNT_EMAIL_HERE";

            var certificate = new X509Certificate2(@"key.p12", "notasecret", X509KeyStorageFlags.Exportable);

            ServiceAccountCredential credential = new ServiceAccountCredential(
               new ServiceAccountCredential.Initializer(serviceAccountEmail)
               {
                   Scopes = new[] { PlusService.Scope.PlusMe }
               }.FromCertificate(certificate));

            // Create the service.
            var service = new PlusService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = "Plus API Sample",
            });

            Activity activity = service.Activities.Get(ACTIVITY_ID).Execute();
            Console.WriteLine("  Activity: " + activity.Object.Content);
            Console.WriteLine("  Video: " + activity.Object.Attachments[0].Url);

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}
```


This sample creates a
[`ServiceAccountCredential`](https://googleapis.dev/dotnet/Google.Apis.Auth/latest/api/Google.Apis.Auth.OAuth2.ServiceAccountCredential.html).
The required scopes are set and there is a call to `FromCertificate`,
which loads the private key from the given `X509Certificate2`.
As in all other samples code, the credential is set as `HttpClientInitializer`.