skip to Main Content

Haiya all! I have the following code that sets up my Google API:

                // Open the FileStream to the related file.
                using FileStream stream = new("Credentials.json", FileMode.Open, FileAccess.Read);

                // The file token.json stores the user's access and refresh tokens, and is created
                // automatically when the authorization flow completes for the first time.

                UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.FromStream(stream).Secrets,
                    new[] { SheetsService.Scope.Spreadsheets, YouTubeService.Scope.YoutubeReadonly },
                    "admin",
                    CancellationToken.None,
                    new FileDataStore("Token", true),
                    new PromptCodeReceiver()
                );

                // Create Google Sheets API service.
                builder.Services.AddSingleton(new SheetsService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = name,
                }));

                // Create Youtube API service.
                builder.Services.AddSingleton(new YouTubeService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = name,
                }));

With this code, all my services are injected properly into the service provider I’m using. However, after 7 days of being up the ASP.Net website seems to not refresh the token, even though my token file has a refresh token. This is, as I would imagine, due to the fact OAuth tokens only last 7 days.

So, how would I get Google’s API to automatically refresh my token? As this is a website, it needs to be online for long amounts of time without going down due to an expired token.

2

Answers


  1. Is the idea to let the ASP.NET app access Youtube and Sheets…

    1. on behalf of the end user or
    2. on behalf of itself (no end user involved?

    In case of (1), using GoogleWebAuthorizationBroker to start an OAuth authorization flow is the right way to go, but you probably shouldn’t store the refresh token permanently. Either store it for the duration of the end user session only, or don’t store it at all and trigger a new OAuth authorization flow every time the access token expires.

    In case of (2), you should use a service account and load credentials by using GoogleCredentials.GetApplicationDefaultAsync(). If the app runs on Google Cloud, attach a service account to the underlying compute resource; if it’s running elsewhere you can use Workload identity federation or service account keys.

    Login or Signup to reply.
  2. If your app is still in testing refresh tokens expire after 7 days. To have them expire longer you will need to set your app into production, and possibly verify it.

    Refresh token expiration

    A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days.

    enter image description here

    web app vs installed app

    I’m surprised that your code is working hosted on a website.
    GoogleWebAuthorizationBroker.AuthorizeAsync is intended for installed applications. Its not going to work for Asp .net hosted on a web site. The reson it wont work is that it causes the consent browser to open on the machine the code is running on. This will work in development but as soon as you try to host it on a webserver its not going to work as the server cant spawn a local web browser.

    You should be following Web applications (ASP.NET Core 3)

    Which will use dependency injection

    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};
            });
    }
          
    

    You dont need to worry about refreshing your access token the library will handle that for you.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search