I'm trying to get User info from OpenID
https://developers.google.com/identity/protocols/OpenIDConnect#exchangecode
I get a token response from:
tok, err := bookshelf.OAuthConfig.Exchange(context.Background(), code)
I can inspect tok
and see there is an id_token
element with:
log.Printf("************ tok contains %#v", tok)
2019/05/13 15:11:24 ************ tok contains &oauth2.Token{AccessToken:"XXXXXXXXXXX", TokenType:"Bearer", RefreshToken:"", Expiry:time.Time{wall:0xbf2f2c6b181f7b0f, ext:3608126524112, loc:(*time.Location)(0x18516e0)}, raw:map[string]interface {}{"scope":"openid https://www.googleapis.com/auth/profile.emails.read", "token_type":"Bearer", "id_token":"Base64-encodedJSONobject", "access_token":"HASH", "expires_in":3600}}
I don't understand how to extract the Claims from the id_token
. Where can I find examples of getting the payload from the JWT id_token
?
When I attempted to Decode the id_token
id_token := base64.StdEncoding.DecodeString(tok.id_token)
I get these errors:
multiple-value base64.StdEncoding.DecodeString() in single-value context
/var/folders/mw/0y88j8_54bjc93d_lg3120qw0000gp/T/tmpbPyjTZappengine-go-bin/auth.go:133:49: tok.id_token undefined (type *oauth2.Token has no field or method id_token)
How do I achieve the equivalent of the fetchProfile function below with OpenID instead of Google+?
The only examples I could find use the deprecated Google+ library:
func oauthCallbackHandler(w http.ResponseWriter, r *http.Request) *appError {
oauthFlowSession, err := bookshelf.SessionStore.Get(r, r.FormValue("state"))
if err != nil {
return appErrorf(err, "invalid state parameter. try logging in again.")
}
redirectURL, ok := oauthFlowSession.Values[oauthFlowRedirectKey].(string)
// Validate this callback request came from the app.
if !ok {
return appErrorf(err, "invalid state parameter. try logging in again.")
}
code := r.FormValue("code")
tok, err := bookshelf.OAuthConfig.Exchange(context.Background(), code)
if err != nil {
return appErrorf(err, "could not get auth token: %v", err)
}
session, err := bookshelf.SessionStore.New(r, defaultSessionID)
if err != nil {
return appErrorf(err, "could not get default session: %v", err)
}
ctx := context.Background()
profile, err := fetchProfile(ctx, tok)
if err != nil {
return appErrorf(err, "could not fetch Google profile: %v", err)
}
session.Values[oauthTokenSessionKey] = tok
// Strip the profile to only the fields we need. Otherwise the struct is too big.
session.Values[googleProfileSessionKey] = stripProfile(profile)
if err := session.Save(r, w); err != nil {
return appErrorf(err, "could not save session: %v", err)
}
http.Redirect(w, r, redirectURL, http.StatusFound)
return nil
}
// fetchProfile retrieves the Google+ profile of the user associated with the
// provided OAuth token.
func fetchProfile(ctx context.Context, tok *oauth2.Token) (*plus.Person, error) {
client := oauth2.NewClient(ctx, bookshelf.OAuthConfig.TokenSource(ctx, tok))
plusService, err := plus.New(client)
if err != nil {
return nil, err
}
return plusService.People.Get("me").Do()
}
It's amazing how many holes there are in the Golang Documentation.
ID Tokens. An id_token is a JWT, per the OIDC Specification. This means that: identity information about the user is encoded right into the token and. the token can be definitively verified to prove that it hasn't been tampered with.
Try this:
type jwtClaims struct {
Iss string `json:"iss"`
Azp string `json:"azp"`
Aud string `json:"aud"`
Sub string `json:"sub"`
Hd string `json:"hd"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
AtHash string `json:"at_hash"`
Nonce string `json:"nonce"`
Iat int `json:"iat"`
Exp int `json:"exp"`
}
func extractJwtClaims(token string) (*jwtClaims, error) {
tokenStruct := &jwtClaims{}
jwtParts := strings.Split(token, ".")
out, _ := base64.RawURLEncoding.DecodeString(jwtParts[1])
err := json.Unmarshal(out, &tokenStruct)
if err != nil {
return nil, err
}
return tokenStruct, nil
}
func main() {
token, _ := extractJwtClaims(tok.id_token)
}
I get the "id_token", just like the code below.
import "golang.org/x/oauth2"
func GetIDTokenWithTokenInfo(tokenInfo *oauth2.Token) string {
rawIDToken := tokenInfo.Extra("id_token").(string)
return rawIDToken
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With