Integrate Google Classroom In ASP.NET Core 3.0 Web Application

Introduction - Google Classroom

 
Wikipedia says,  Google Classroom is a free web service, developed by Google for schools, that aims to simplify creating, distributing, and grading assignments in a paperless way. The primary purpose of Google Classroom is to streamline the process of sharing files between teachers and students. There are many more features of  the Google classroom --  click here to learn more.
 
In this article, we are going to learn how to integrate the Google classroom with our school information system application. For demo purposes let's consider my sample ASP.NET Core 3.0 as an SIS application, and we will integrate Google classroom with this sample application by pulling out the Google classroom information using Google classroom API’s. 
 

Create a Google Classroom Project

 
Step 1
 
 
Step 2
 
Create a new project and name it as GoogleClassRoom
 
 
Step 3
 
Enable API by clicking on Enable APIS and Services
  
Step 4
 
Now, let’s create a credential (OAuth client ID), where we can get a Client ID and App key which is used to enable the Google authentication in a third party application.
 
Step 5
 
In this screen, it will ask you to configure the OAuth consent screen, since we are in the development phase it’s enough to provide the application name and scope details which we are using for our project, as shown below:
 
 
 
Scope
 
 
 
classroom.course.readonly is the scope which is used fetch the Google classroom details, add the scope and click on save to save the changes, it will take you to Create OAuth client ID Screen.
 
Step 6
 
In Create OAuth client ID screen provide application type as a web application, name the application, in my case I named it as GC client. I will provide authorized Javascript Origins after creating our application. Now click on create, it will generate a Client ID and Client Secret, which should be used in our application for authentication.
 
 
 
 
 

Integrate Google Classroom

 
Step 1
 
Open Visual Studio -> Create New Project -> Select ASP.NET Core Web Application template, as shown in the below figure.
 
 
Step 2
 
Give a name for a project. In my case, I named it as GoogleClassRoomDemo, Click on next and select Web Application template, as shown in the below figure.
 
 
  1. public IActionResult Index() {  
  2.   return View();  
  3. }  
View->GoogleClassRoom->Index.cshtml
  1. <script src="https://code.jquery.com/jquery-3.4.1.min.js"    
  2.         integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="    
  3.         crossorigin="anonymous"></script>    
  4. <script src="https://apis.google.com/js/client:platform.js?onload=start" async defer></script>    
  5. <button id="btnSignIn" class="btn-default" onclick="GoogleAuthenticationPage()">Sign in</button>    
  6. <button class="btn-default" id="googleAuth">Get Course</button>    
  7. <script type="text/javascript">     
  8.     function start() {    
  9.         gapi.load('auth2'function () {    
  10.             auth2 = gapi.auth2.init({    
  11.                 client_id: "[Provide your client id]",    
  12.                 scope: 'https://www.googleapis.com/auth/classroom.courses.readonly',    
  13.             });    
  14.         });    
  15.     }    
  16.     function GoogleAuthenticationPage() {    
  17.         auth2.grantOfflineAccess().then(signInCallback);    
  18.     }    
  19.     function IsSignedIn() {         
  20.          $.ajax({    
  21.              url: "/GoogleClassRoom/IsSignedIn", success: function (result) {    
  22.                  if (result) {    
  23.                      $("#btnSignIn").hide();    
  24.                  }    
  25.                  else {    
  26.                      $("#googleAuth").hide();    
  27.                  }    
  28.             }    
  29.         })    
  30.     }    
  31.     function signInCallback(authResult) {          
  32.         var token = authResult['code'];    
  33.         var access_token = '';    
  34.         var refresh_token = '';    
  35.         $.ajax({    
  36.             url: 'https://www.googleapis.com/oauth2/v4/token',    
  37.             type: "post",    
  38.             datatype: "json",    
  39.             contentType: "application/x-www-form-urlencoded; charset=utf-8",    
  40.             async: true,    
  41.             data: {    
  42.                 code: authResult['code'], client_id: "[provide client ID ]", client_secret: "[Provide client secret]", redirect_uri: 'https://localhost:44357', grant_type: 'authorization_code'    
  43.             },    
  44.             success: function (response) {               
  45.                 access_token =  response.access_token;    
  46.                 refresh_token = response.refresh_token;    
  47.                 googleCallback(token, access_token, refresh_token);    
  48.             }    
  49.         })    
  50.             .fail(function (err) {    
  51.                 alert("error" + err);    
  52.                 console.log("error" + err);    
  53.             });    
  54.     }    
  55.     function googleCallback(authCode, accessToken, refreshToken) {            
  56.         if (authCode) {    
  57.             $.ajax({    
  58.                 url: '/GoogleClassRoom/GoogleAuthorizationCallback',    
  59.                 type: "POST",                    
  60.                 contentType: 'application/json',    
  61.                 data: JSON.stringify({ Auth_Code: authCode, Access_token: accessToken, Refresh_token: refreshToken }),    
  62.                 success: function (res) {    
  63.                     location.reload();    
  64.                 },    
  65.                 error: function (xhr) {    
  66.                     alert("Error" + xhr.responseText);    
  67.                 }    
  68.             });    
  69.         } else {    
  70.             alert('error');    
  71.         }    
  72.     }    
  73. </script>  
client:platform.js is the Google Client API js, when loading this JS we are calling Start() to initiate auth2 object.
 
When user clicks on SignIn button it calls GoogleAuthenticationPage(), where we are doing ajax call to trigger 'https://www.googleapis.com/oauth2/v4/token’ google API with clientId and Client secret as one of the parameters in a payload. After successful login from user it will return access token, and refresh token as a response. We are saving these values in the database with a googleCallback() callback.
 
GoogleClassRoomController.cs
  1. [HttpPost]    
  2. public  void GoogleAuthorizationCallback([FromBody]Token token)    
  3. {    
  4.     SqlConnection con = new SqlConnection(@"Data Source=DESKTOP-585QGBN;Initial Catalog=Test;Integrated Security=True");    
  5.     SqlCommand cmd = new SqlCommand("Stp_InsertGoogleAccessDetails", con);    
  6.     cmd.CommandType = CommandType.StoredProcedure;    
  7.     cmd.Parameters.AddWithValue("@nvAuthCode", token.Auth_code);    
  8.     cmd.Parameters.AddWithValue("@nvRefreshToken", token.Refresh_token);    
  9.     cmd.Parameters.AddWithValue("@nvAccessCode", token.Access_token);    
  10.     cmd.Parameters.AddWithValue("@inUserID", 1);    
  11.     con.Open();    
  12.     cmd.ExecuteNonQuery();    
  13.     con.Close();                
  14. }    
GoogleAuthorizationCallback() method is used to save the Auth code, refresh token and access token and current user id which is maintained in our session into our database, now for time being I hardcoded the value for UserId, basically this unmanaged ADO.NET code should be in a separate data access layer. Make sure you are taking care of it.
 
SQL script Table
  1. CREATE TABLE [dbo].[GoogleUserInfo](    
  2.     [UserID] [intNOT NULL,    
  3.     [AuthCode] [nvarchar](maxNULL,    
  4.     [ReferehToken] [nvarchar](maxNULL,    
  5.     [AccessCode] [nvarchar](maxNULL,    
  6.  CONSTRAINT [pk_user_id] PRIMARY KEY CLUSTERED     
  7. (    
  8.     [UserID] ASC    
  9. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ONON [PRIMARY]    
  10. ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]    
Stored Procedure to insert a record 
  1. CREATE procedure [dbo].[Stp_InsertGoogleAccessDetails]    
  2. (    
  3.  @nvAuthCode nvarchar(max) ,    
  4.  @nvRefreshToken nvarchar(max),    
  5.  @nvAccessCode nvarchar(max),    
  6.  @inUserID int    
  7. )    
  8. as    
  9. begin     
  10. insert into GoogleUserInfo values(@inUserID,@nvAuthCode,@nvRefreshToken,@nvAccessCode)     
  11. end   
Stored Procedure to get a refresh token 
  1. Create procedure [dbo].[Stp_GetGoogleUserInfo]    
  2. ( @inUserID int    
  3. )    
  4. as    
  5. begin     
  6. select ReferehToken from GoogleUserInfo where UserID=@inUserID    
  7. end    
Once user has successfully logged with Google, now he/she can  retrieve their Google classroom list,
 
Clicking on Get Course button will call the function which is returned below,
  1. $("#googleAuth").click(function (e) {    
  2.      $.ajax({    
  3.          url: "/GoogleClassRoom/GetCourse", success: function (result) {    
  4.          }    
  5.      })    
  6.  })   
This click event will do the ajax call "/GoogleClassRoom/GetCourse"
 
GoogleClassRoomController.cs
  1. public class GoogleClassRoomController: Controller {  
  2.  private static readonly string ClientId =  
  3.   "[Provide client ID]";  
  4.  private static readonly string ClientSecret =  
  5.   "[Provide client secret]";  
  6.  private static readonly string GoogleApplicationName =  
  7.   "GoogleClass";  
  8.  public IActionResult Index() {  
  9.   return View();  
  10.  }  
  11.  public bool IsSignedIn() {  
  12.   string refreshToken = GetRefershToken(1);  
  13.   if (string.IsNullOrEmpty(refreshToken)) {  
  14.    return true;  
  15.   } else {  
  16.    return false;  
  17.   }  
  18.  }  
  19.  public List < Course > GetCourse() {  
  20.   var Token = GetAuthenticator();  
  21.   var token = new TokenResponse() {  
  22.    AccessToken = Token,  
  23.     ExpiresInSeconds = 3600,  
  24.     IssuedUtc = DateTime.UtcNow  
  25.   };  
  26.   var authflow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer {  
  27.    ClientSecrets = new ClientSecrets {  
  28.     ClientId = ClientId,  
  29.      ClientSecret = ClientSecret  
  30.    }  
  31.   });  
  32.   var credential = new UserCredential(authflow, "0", token);  
  33.   var serviceInitializer = new BaseClientService.Initializer() {  
  34.    ApplicationName = GoogleApplicationName,  
  35.     HttpClientInitializer = credential  
  36.   };  
  37.   var googleService = new ClassroomService(serviceInitializer);  
  38.   
  39.   string pageToken = null;  
  40.   var courses = new List < Course > ();  
  41.   do {  
  42.    var request = googleService.Courses.List();  
  43.    request.PageSize = 100;  
  44.    request.PageToken = pageToken;  
  45.    var response = request.Execute();  
  46.    courses.AddRange(response.Courses);  
  47.    pageToken = response.NextPageToken;  
  48.   } while (pageToken != null);  
  49.   return courses;  
  50.  }  
  51.  public static string GetAuthenticator() {  
  52.    string refreshToken = GetRefershToken(1);  
  53.    var content = "refresh_token=" + refreshToken + "&client_id=" + ClientId + "&client_secret=" + ClientSecret + "&grant_type=refresh_token";  
  54.    var request = WebRequest.Create("https://accounts.google.com/o/oauth2/token");  
  55.    request.Method = "POST";  
  56.    byte[] byteArray = Encoding.UTF8.GetBytes(content);  
  57.    request.ContentType = "application/x-www-form-urlencoded";  
  58.    request.ContentLength = byteArray.Length;  
  59.    using(var dataStream = request.GetRequestStream()) {  
  60.     dataStream.Write(byteArray, 0, byteArray.Length);  
  61.     dataStream.Close();  
  62.    }  
  63.    var response = (HttpWebResponse) request.GetResponse();  
  64.    var responseDataStream = response.GetResponseStream();  
  65.    var reader = new StreamReader(responseDataStream);  
  66.    var responseData = reader.ReadToEnd();  
  67.    reader.Close();  
  68.    responseDataStream.Close();  
  69.    string accessToken;  
  70.    if (response.StatusCode == HttpStatusCode.OK) {  
  71.     var returnedToken = JsonConvert.DeserializeObject < Token > (responseData);  
  72.     accessToken = returnedToken.Access_token;  
  73.    } else {  
  74.     return string.Empty;  
  75.    }  
  76.    response.Close();  
  77.    return accessToken;  
  78.   }  
  79.   [HttpPost]  
  80.  public void GoogleAuthorizationCallback([FromBody] Token token) {  
  81.   SqlConnection con = new SqlConnection(@ "Data Source=DESKTOP-585QGBN;Initial Catalog=Test;Integrated Security=True");  
  82.   SqlCommand cmd = new SqlCommand("Stp_InsertGoogleAccessDetails", con);  
  83.   cmd.CommandType = CommandType.StoredProcedure;  
  84.   cmd.Parameters.AddWithValue("@nvAuthCode", token.Auth_code);  
  85.   cmd.Parameters.AddWithValue("@nvRefreshToken", token.Refresh_token);  
  86.   cmd.Parameters.AddWithValue("@nvAccessCode", token.Access_token);  
  87.   cmd.Parameters.AddWithValue("@inUserID", 1);  
  88.   con.Open();  
  89.   cmd.ExecuteNonQuery();  
  90.   con.Close();  
  91.  }  
  92.  public static string GetRefershToken(int userId) {  
  93.   string refreshToken = string.Empty;  
  94.   SqlConnection con = new SqlConnection(@ "Data Source=DESKTOP-585QGBN;Initial Catalog=Test;Integrated Security=True");  
  95.   SqlCommand sqlCommand = new SqlCommand("Stp_GetGoogleUserInfo", con) {  
  96.    CommandType = CommandType.StoredProcedure  
  97.   };  
  98.   SqlCommand cmd = sqlCommand;  
  99.   cmd.Parameters.AddWithValue("@inUserID", userId);  
  100.   con.Open();  
  101.   SqlDataReader rdr = cmd.ExecuteReader();  
  102.   while (rdr.Read()) {  
  103.    refreshToken = rdr["ReferehToken"].ToString();  
  104.   }  
  105.   return refreshToken;  
  106.  }  
  107. }  
Install Google Classroom API’s package from Nuget package manager
 
 
 
When GetCourse Method is called, it will use GetAutheticator function to get the new accessToken for the current user based on the Refresh token which is saved in our database.
 
GetRefreshToken() is used to return the refresh token for the current user.
 
GoogleAuthorizationCodeFlow is used to construct the Google auth flow by initializing the client secrets
 
UserCredential is used to construct the new credential instance with authflow and token
 
The ClassroomService class is used to retrieve all Google classroom services based on the service initializer which holds the credentials.
 
https://accounts.google.com/o/oauth2/token this Google API is used to get the new access token based on a refresh token.
 
Before testing the application, login into the Google developer console and register our localhost (https://localhost:44357) which is used for development against the OAuth credential which we created.
 
 
 
Now run the application,
 
Click on Sign in button, it will take you to the Google authentication page, after successful login, the user tokens are saved in our database.
 
 
 
 
 
Now, click on Get Course button to get the Google classroom list.
 
 
 
The above figure shows the response from GetCourse().
 
The list of classrooms that are available in my Google classroom, as shown in the below figure.
 
 
Reference
 
https://developers.google.com/classroom/quickstart/dotnet
 

Summary

 
We have gone through,
  • Creating the project in Google developer console and enabling the google classroom API.
  • Creating the OAuth Credential for the authentication which is used for integration with our application using the developer console.
  • Integrating Google API’s in our web application.
  • Retrieving the Google classroom course using the google classroom API’s from our ASP.NET Core web application.
Click here for the source code.