Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Classroom API Object Authentication

I am successfully using the Google Classroom API in the browser to act on behalf of a user who has granted permissions to do so through OAuth2 using the Google Client library. I'm trying to figure out how to trust API results sent to my server from the browser. Here's a story to explain the end-to-end problem I'm trying to solve.

  1. User X logs into my website using Google Login, and I save that user's Google Login object (which is transferred to my server in the form of an id_token and decoded to ensure authenticity as described in detail here) in my database. That response ends up looking something like this heavily redacted object:

{
   "iss": "accounts.google.com",
   "azp": "redacted-string",
   "aud": "redacted-string",
   "sub": "redacted-string",
   "hd": "redacted-string",
   "email": "redacted-string",
   "email_verified": true,
   "at_hash": "redacted-string",
   "name": "redacted-string",
   "picture": "redacted-string",
   "given_name": "redacted-string",
   "family_name": "redacted-string",
   "locale": "en",
   "iat": redacted-number,
   "exp": redacted-number,
   "jti": "redacted-string"
}
  1. I want to do something in Google Classroom on behalf of the user, like list classrooms. So I ask for permission to do that by sending them through the appropriate OAuth2 workflow that Google provides. Then, having received consent, I make the desired Google Classrooms API call to list classrooms, and receive back a list of classrooms, something like this:

{
 "courses": [
  {
   "id": "redacted-number",
   "name": "redacted-string",
   "ownerId": "redacted-number",
   "creationTime": "2019-01-09T19:04:28.084Z",
   "updateTime": "2019-01-09T19:04:56.828Z",
   "enrollmentCode": "redacted-string",
   "courseState": "DECLINED",
   "alternateLink": "https://classroom.google.com/c/redacted-string",
   "teacherGroupEmail": "redacted-string",
   "courseGroupEmail": "redacted-string",
   "teacherFolder": {
    "id": "redacted-string"
   },
   "guardiansEnabled": false
  },
  {
   "id": "redacted-number",
   "name": "redacted-string",
   "ownerId": "redacted-number",
   "creationTime": "2019-01-09T19:03:06.321Z",
   "updateTime": "2019-01-09T19:03:05.328Z",
   "enrollmentCode": "redacted-string",
   "courseState": "PROVISIONED",
   "alternateLink": "https://classroom.google.com/c/redacted-string",
   "teacherGroupEmail": "redacted-string",
   "courseGroupEmail": "redacted-string",
   "teacherFolder": {
    "id": "redacted-string"
   },
   "guardiansEnabled": false
  }
 ]
}
  1. Now I'd like to convey this information to my server and store it in a database associated with the user. I'm using JWT already to authenticate the user so when the request reaches my server I know which user sent it. What I don't know is how to trust the Google Classroom object they are sending me actually came from Google.

Maybe I'm over-thinking it, and I shouldn't worry about a user propagating fake Google object data into my database? I would have thought the objects were signed in some way that my server might be able to verify the authenticity of the Google objects given my application credentials and the proxy user's verified Google sign-in object. I would think this process would be similar to how Google Login allows me to verify the authenticity of the sign-in on my server side.

If there's a clear way to do that, I don't see it. Can anyone help me put things into focus?

P. S. This is a follow up to this question which never got a decent answer, unfortunately.

like image 728
vicatcu Avatar asked Jan 22 '19 20:01

vicatcu


2 Answers

There is no way to guard against a valid user posting phony data to your server from the users client browser.

One option is to update your application to enable server-side access to Google's API.

There is documentation on how to do that here: https://developers.google.com/identity/sign-in/android/offline-access

If you have access to the Access Token from the client side requests you can also perform the following request pattern:

1) Client Makes the following HTTP request to an API endpoint on your application server

GET /api/list_courses HTTP/1.1
Host: yourapp.example.com
Content-length: 0
Authorization: Bearer googles_api_access_token_here

2) The /api/list_courses endpoint on your application server makes the following request to googles API server:

GET /v1/courses HTTP/1.1
Host: classroom.googleapis.com
Content-length: 0
Authorization: Bearer googles_api_access_token_here

3) The response from (2) is sent back to your application server

4) your application server responds with the list of courses to the client.

like image 141
sirlanceoflompoc Avatar answered Oct 16 '22 01:10

sirlanceoflompoc


the problem might not be a problem at all, as you've wrote:

What I don't know is how to trust the Google Classroom object they are sending me actually came from Google.

assuming API communication, they are not even sending it, but you fetch it via SSL or TLS (the host's certificate can also be validated, while this is not required, because when it does not match the A record in DNS, it's invalid). ID tokens of the users also could be validated; see the documentation.

like image 40
Martin Zeitler Avatar answered Oct 16 '22 02:10

Martin Zeitler