0

Ok, I am working with Google APIs and they use OAuth2. I need to have multiple API calls of my own that do different things with the Classroom API. All of the examples I have seen for C# make the user authenticate THEN they use the google service.

I need to authenticate one time and send that access token to the API for additional calls.

My end goal is something like this:

  • User logs in with google.. they give back the access token and such
  • Pass that token in an authorization header
  • API takes that and pulls out the credentials and passes them to the google service (THIS is where I am stuck)

I can get the access token pretty easily using Postman, or with my own web app.

When I send that over in the Authorization header (Postman sends it as bearer) I don't know what to do with it from there.

Do I parse it? Is there something in the .Net Google API library that makes this easy?

Seems like this should be a common scenario, but I can't find any tutorials or guides on this.

Thanks!

David
  • 2,173
  • 3
  • 25
  • 36
  • You should exchange the Google token for an API token of your own (your API) – ProgrammingLlama Mar 13 '18 at 23:57
  • Hey John, thanks for the reply. Not sure I understand. I need to talk to Google's APIs (specifically Classroom) so I need to get the user credentials that allow that to happen. – David Mar 14 '18 at 00:23
  • You need to create an access token on your backend using your Google token. – ProgrammingLlama Mar 14 '18 at 01:03
  • That is exactly my question. How do I use the token in my Authorization header in a new google API call? – David Mar 14 '18 at 01:46
  • I don't think it was. You should use _your API's token_ in the Authorization header when communicating with _your API_. This does not prevent you including the Google API token in your access token so that your APIs can use it. – ProgrammingLlama Mar 14 '18 at 01:47
  • Sorry, I am confused. My client is used to log into Google and get the access token. I then send that token in the Authorization Header to my API. My problem is... how do I use the token in that header to create a valid UserCredential object for Google? If I use my API's token, then how do I know who the user is? – David Mar 14 '18 at 01:49
  • @David do you want to use the same token from one of your API and authenticate a user on top of that ? – Kavindu Dodanduwa Mar 14 '18 at 04:31
  • please edit your question and include your c# code i can explain how the .net client library works – Linda Lawton - DaImTo Mar 14 '18 at 09:49
  • 1
    Check this answer - https://stackoverflow.com/questions/38390197/how-to-create-a-instance-of-usercredential-if-i-already-have-the-value-of-access – Kavindu Dodanduwa Mar 14 '18 at 14:12

1 Answers1

0

Ok... in the end, I solved it like this (with help from this question).

How to create a instance of UserCredential if I already have the value of Access Token?

First I get the google oauth goodies like so.

    public async Task<UserCredential> GetUserCredential()
    {
        try
        {
            UserCredential credential;

            credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                       new ClientSecrets
                       {
                           ClientId = ConfigurationManager.AppSettings["GoogleClassroomClientID"],
                           ClientSecret = ConfigurationManager.AppSettings["GoogleClassroomSecret"]
                       }, _scopes, "user", CancellationToken.None, new FileDataStore("Web.Google.Classroom.Api.Store"));

            return credential;
        }
        catch (Exception ex)
        {
            HandleError(ex);
            return null;
        }
    }

From here I parse out the Access Token and the Refresh Token.

Then I send both of those as headers in all of my subsequent API calls.

From my API calls I use the authentication and refresh tokens to get a UserCredential object needed to touch any of Google's APIs (in my case the classroom API). The magic is in my AuthorizeGoogleUser function.

All of my calls are through SSL so I am pretty sure I don't have any security issues with this approach, but I am all for any improvements y'all have.

    static string[] _scopes = { ClassroomService.Scope.ClassroomCoursesReadonly };
    static string _applicationName = "DiBS Google Classroom API";

    private static readonly IAuthorizationCodeFlow flow =
        new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
        {
            ClientSecrets = new ClientSecrets
            {
                ClientId = ConfigurationManager.AppSettings["GoogleClassroomClientID"],
                ClientSecret = ConfigurationManager.AppSettings["GoogleClassroomSecret"]
            },
            Scopes = _scopes
        });


    [Route("google/getcourses")]
    [HttpGet] 
    public void GetCourses()
    {
        try
        {
            LogInfo($"Google GetCourses: Start");

            UserCredential creds = AuthorizeGoogleUser();
            if (creds == null)
                throw new Exception("Invalid Google User");

            // Create Classroom API service.
            var service = new ClassroomService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = creds,
                ApplicationName = _applicationName,
            });

            // Define request parameters.
            CoursesResource.ListRequest request = service.Courses.List();
            request.PageSize = 10;

            // List courses.
            ListCoursesResponse response = request.Execute();
            if (response.Courses != null && response.Courses.Count > 0)
            {
                foreach (var course in response.Courses)
                {
                    LogInfo($"Google GetCourses: {course.Name}, {course.Id}");
                }
            }
            else
            {
                LogInfo("Google GetCourses: No courses found.");
            }
        }
        catch (Exception ex)
        {
            HandleError(null, ex);
        }
    }

    private UserCredential AuthorizeGoogleUser()
    {
        try
        {
            string GAT = HttpContext.Current.Request.Headers["GAT"];
            string GRT = HttpContext.Current.Request.Headers["GRT"];

            if (GAT == null || GRT == null)
                return null;

            var token = new TokenResponse
            {
                AccessToken = GAT,
                RefreshToken = GRT
            };

            var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
            {
                ClientSecrets = new ClientSecrets
                {
                    ClientId = ConfigurationManager.AppSettings["GoogleClassroomClientID"],
                    ClientSecret = ConfigurationManager.AppSettings["GoogleClassroomSecret"]
                },
                Scopes = _scopes,
                DataStore = new FileDataStore("DiBS-Web.Google.Classroom.Api.Store")
            });

            UserCredential credential = new UserCredential(flow, "me", token);
            return credential;
        }
        catch
        {
            return null;
        }
    }
David
  • 2,173
  • 3
  • 25
  • 36