3

Well, I am trying to implement google oauth authentication with my django project.

I follow the guide here:

https://developers.google.com/accounts/docs/OAuth2Login?hl=de-DE

I have got the response from exchanging code. I got a string type json which contains multiple info like access_token, id_token, etc.

Id_token is a cryptographically-signed JSON object encoded in base 64. I try to decode id_token with python module base64, but failed.

I also tried PyJWT, failed.

Is there any way to decode and verify it?

Jerry Meng
  • 1,466
  • 3
  • 21
  • 40

3 Answers3

7

Know this is an old post but I found it via Google so I thought somebody else might drop in...

I ended up doing:

segments = response['id_token'].split('.')

if (len(segments) != 3): 
   raise Exception('Wrong number of segments in token: %s' % id_token) 

b64string = segments[1]
b64string = b64string.encode('ascii') 
padded = b64string + '=' * (4 - len(b64string) % 4) 
padded = base64.urlsafe_b64decode(padded)
Kristofer Källsbo
  • 1,047
  • 2
  • 10
  • 25
3

ID token(aka JSON Web Signature (JWS)) has 3 parts separated by . character:

Header.Payload.Signature

We can get each part by splitting the token:

parts = token.split(".")

Now I don't know the reason, but these parts do not have the base64 padding. Maybe because it is not enforced(see this)? And python base64 library requires it.

The padding character is =, and the padding should be added to the base64 string so that it is length is multiple of 4 characters. For example if the string is 14 characters, it should have the padding == at the end so that it is 16 characters in total.

So the formula to calculate correct padding is this:

4 - len(base64_string) % 4

After we add the right padding and decode the string:

payload = parts[1]
padded = payload + '=' * (4 - len(payload) % 4)

base64.b64decode(padded)

what we will get is a string representation of JSON object, we can convert it to JSON with:

json.loads(base64.b64decode(padded))

Finally we can put everything in a convenience function:

import base64
import json


def parse_id_token(token: str) -> dict:
    parts = token.split(".")
    if len(parts) != 3:
        raise Exception("Incorrect id token format")

    payload = parts[1]
    padded = payload + '=' * (4 - len(payload) % 4)
    decoded = base64.b64decode(padded)
    return json.loads(decoded)

To learn more details about id token check Takahiko Kawasaki(founder of authlete.com)'s excellent article

Caner
  • 57,267
  • 35
  • 174
  • 180
1

Well, I figured out why...

I used base64.b46decode(id_token) to decode it. However, I should split id_token by '.' and decode them separately. So I can get header, claims and signature from id_token.

I was just too stupid for ignoring those little '.' in the string....

Jerry Meng
  • 1,466
  • 3
  • 21
  • 40
  • 1
    Hi..I am going through same problem..Could you please tell me that after decoding each part separately how you put it together and send it to verify over google (at back end side).. m using this line to verify at my backend in python body = urllib.urlencode({'access_token': final_access_token}) http = httplib2.Http() resp, content = http.request("https://www.googleapis.com/oauth2/v1/tokeninfo",method="POST", body=body) – Shikha Shah Jan 10 '14 at 16:06