Search code examples
c#google-apiasp.net-coregoogle-calendar-apigoogle-oauth

Retrieving Access and Refresh Token for Google Api


Fundamentally, I'm not understanding something about OAuth, Google, and the Google Apis. I'm working the v3 library in Asp.Net Core 1.0. I use Google Authentication:

        app.UseGoogleAuthentication(new GoogleOptions
        {
            ClientId = Configuration["Google:ClientId"],
            ClientSecret = Configuration["Google:ClientSecret"],
            Scope = {
            "email",
            "https://www.googleapis.com/auth/userinfo.email",
            "profile",
            "https://www.googleapis.com/auth/userinfo.profile",
            "openid",
            "https://www.googleapis.com/auth/calendar",
        },
            AccessType = "offline",
            SaveTokens = true,
        });

Simple enough. Then I want to use Google Calendar. However, I cannot consistently get back the Access/Refresh tokens (honestly at this point I'm not sure I understand what these are). I use this code to get back a Calendar Service from google:

    private AuthorizationCodeFlow CreateFlow(IEnumerable<string> scopes)
    {
        return new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer()
        {
            ClientSecrets = new Google.Apis.Auth.OAuth2.ClientSecrets
            {
                ClientId = _ClientId,
                ClientSecret = _ClientSecret
            },
            DataStore = new MemoryDataStore(),
            Scopes = scopes
        });
    }

    private async Task<UserCredential> CreateUserCredential(HttpContext context, string providerKey, IEnumerable<string> scopes)
    {
        var flow = CreateFlow(scopes);
        var token = await context.GetGoogleTokenResponse();

        UserCredential credential = new UserCredential(flow, providerKey, token);
        return credential;
    }

    public async Task<CalendarService> CreateCalendarServiceAsync(HttpContext context, string providerKey)
    {
        if (string.IsNullOrWhiteSpace(providerKey)) return null;
        if (context == null) return null;

        var credential = await CreateUserCredential(context, providerKey, new[] { "https://www.googleapis.com/auth/calendar" });
        CalendarService service = new CalendarService(new BaseClientService.Initializer
        {
            HttpClientInitializer = credential,
            ApplicationName = _ApplicationName,
        });

        return service;
    }

    public static async Task<TokenResponse> GetGoogleTokenResponse(this HttpContext context)
    {
        var info = await context.Authentication.GetAuthenticateInfoAsync("Google");
        if (info == null) return null;

        var token = new TokenResponse
        {
            AccessToken = info.Properties.Items[".Token.access_token"],
            RefreshToken = info.Properties.Items[".Token.refresh_token"],
            TokenType = info.Properties.Items[".Token.token_type"],
            Issued = DateTime.Parse(info.Properties.Items[".issued"]),
        };

        return token;
    }

This is the only way I know how to get back the current access/refresh tokens. What am I missing. Sometimes they exist, others times not. Documentation for the .Net Core 1.0 version is slim at best. Any help on a better way to access Google Apis via Asp.Net core?


Solution

  • Since you already set SaveTokens = true, you can get access_token like this: await context.Authentication.GetTokenAsync("access_token");

    So changing your method like below probably solves your problem:

    private async Task<UserCredential> CreateUserCredential(HttpContext context, string providerKey, IEnumerable<string> scopes)
    {
        var flow = CreateFlow(scopes);
        var token = await context.Authentication.GetTokenAsync("access_token");
    
        UserCredential credential = new UserCredential(flow, providerKey, token);
        return credential;
    }