func getJWT(c *oidc.Client, listenAddr string) (*oauth2.Client, chan *oauth2.TokenResponse, error) { jwtChan := make(chan *oauth2.TokenResponse) l, err := net.Listen("tcp", listenAddr) if err != nil { return nil, nil, err } oac, err := c.OAuthClient() if err != nil { return nil, nil, err } f := func(w http.ResponseWriter, r *http.Request) { code := r.URL.Query().Get("code") if code == "" { return } token, err := oac.RequestToken(oauth2.GrantTypeAuthCode, code) if err != nil { fmt.Fprintf(w, "error: %s", err) return } jwtChan <- &token fmt.Fprintf(w, "Success! You can now close this window and go back to the CLI") l.Close() } go http.Serve(l, http.HandlerFunc(f)) return oac, jwtChan, err }
func handleCallbackFunc(c *oidc.Client) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { code := r.URL.Query().Get("code") if code == "" { phttp.WriteError(w, http.StatusBadRequest, "code query param must be set") return } tok, err := c.ExchangeAuthCode(code) if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to verify auth code with issuer: %v", err)) return } claims, err := tok.Claims() if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to construct claims: %v", err)) return } s := fmt.Sprintf(`<html><body><p>Token: %v</p><p>Claims: %v </p> <a href="/resend?jwt=%s">Resend Verification Email</a> </body></html>`, tok.Encode(), claims, tok.Encode()) w.Write([]byte(s)) } }
// Reads the OIDC JWT passed in the context and verifies it using the given OIDC client. // Returns the verified identity on success, error otherwise. func VerifiedIdentityFromContext(client *gooidc.Client, ctx context.Context) (*gooidc.Identity, error) { md, ok := metadata.FromContext(ctx) if !ok { return nil, errors.New("missing RPC credentials") } rawJWT, ok := md["jwt"] if !ok { return nil, errors.New("missing OIDC credentials") } if len(rawJWT) != 1 { return nil, errors.New("incorrect JWT data sent") } jwt, err := jose.ParseJWT(rawJWT[0]) if err != nil { return nil, err } if err := client.VerifyJWT(jwt); err != nil { return nil, err } claims, err := jwt.Claims() if err != nil { return nil, err } return gooidc.IdentityFromClaims(claims) }
func oidcCallback(c *oidc.Client, listenAddr string) (string, chan jose.JWT, error) { tokenChan := make(chan jose.JWT) l, err := net.Listen("tcp", listenAddr) if err != nil { return "", nil, err } oac, err := c.OAuthClient() if err != nil { return "", nil, err } f := func(w http.ResponseWriter, r *http.Request) { code := r.URL.Query().Get("code") if code == "" { return } token, err := c.ExchangeAuthCode(code) if err != nil { fmt.Fprintf(w, "error: %s", err) return } tokenChan <- token close(tokenChan) fmt.Fprintf(w, "Success! You can now close this window and go back to the CLI") l.Close() } go http.Serve(l, http.HandlerFunc(f)) return oac.AuthCodeURL("", "", ""), tokenChan, err }
// Parses and validates a JWT token, based on the client definition provided. func ValidateJWT(idToken string, client *oidc.Client) (jose.JWT, error) { jwt, err := jose.ParseJWT(idToken) if err != nil { return jose.JWT{}, err } return jwt, client.VerifyJWT(jwt) }
func exchangeAuthCode(c *oidc.Client, code string) (oauth2.TokenResponse, error) { oac, err := c.OAuthClient() if err != nil { return oauth2.TokenResponse{}, err } t, err := oac.RequestToken(oauth2.GrantTypeAuthCode, code) if err != nil { return oauth2.TokenResponse{}, err } return t, nil }
func handleLoginFunc(c *oidc.Client) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { oac, err := c.OAuthClient() if err != nil { panic("unable to proceed") } u, err := url.Parse(oac.AuthCodeURL("", "", "")) if err != nil { panic("unable to proceed") } http.Redirect(w, r, u.String(), http.StatusFound) } }
func handleRegisterFunc(c *oidc.Client) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { oac, err := c.OAuthClient() if err != nil { panic("unable to proceed") } u, err := url.Parse(oac.AuthCodeURL("", "", "")) q := u.Query() q.Set("register", "1") if err != nil { panic("unable to proceed") } u.RawQuery = q.Encode() log.Infof("URL: %v", u.String()) http.Redirect(w, r, u.String(), http.StatusFound) } }
func handleCallbackFunc(c *oidc.Client, claims *jose.Claims, refresh *string) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { code := r.URL.Query().Get("code") if code == "" { phttp.WriteError(w, http.StatusBadRequest, "code query param must be set") return } oac, err := c.OAuthClient() if err != nil { phttp.WriteError(w, http.StatusInternalServerError, fmt.Sprintf("unable to create oauth client: %v", err)) return } t, err := oac.RequestToken(oauth2.GrantTypeAuthCode, code) if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to verify auth code with issuer: %v", err)) return } // Get id token and claims. tok, err := jose.ParseJWT(t.IDToken) if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to parse id_token: %v", err)) return } if err := c.VerifyJWT(tok); err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to verify the JWT: %v", err)) return } if *claims, err = tok.Claims(); err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to construct claims: %v", err)) return } // Get refresh token. *refresh = t.RefreshToken w.WriteHeader(http.StatusOK) } }
func handleLoginFunc(c *oidc.Client) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("Could not parse request: %v", err)) } oac, err := c.OAuthClient() if err != nil { panic("unable to proceed") } u, err := url.Parse(oac.AuthCodeURL("", "", "")) if err != nil { panic("unable to proceed") } var scopes []string q := u.Query() if scope := q.Get("scope"); scope != "" { scopes = strings.Split(scope, " ") } if xClient := r.Form.Get("cross_client"); xClient != "" { xClients := strings.Split(xClient, ",") for _, x := range xClients { scopes = append(scopes, scope.ScopeGoogleCrossClient+x) } } if extraScopes := r.Form.Get("extra_scopes"); extraScopes != "" { scopes = append(scopes, strings.Split(extraScopes, ",")...) } if scopes != nil { q.Set("scope", strings.Join(scopes, " ")) u.RawQuery = q.Encode() } http.Redirect(w, r, u.String(), http.StatusFound) } }
func handleCallbackFunc(c *oidc.Client) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { code := r.URL.Query().Get("code") if code == "" { writeError(w, http.StatusBadRequest, "code query param must be set") return } tok, err := c.ExchangeAuthCode(code) if err != nil { writeError(w, http.StatusBadRequest, fmt.Sprintf("unable to verify auth code with issuer: %v", err)) return } claims, err := tok.Claims() if err != nil { writeError(w, http.StatusBadRequest, fmt.Sprintf("unable to construct claims: %v", err)) return } s := fmt.Sprintf("claims: %v", claims) w.Write([]byte(s)) } }
func handleCallbackFunc(c *oidc.Client) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { refreshToken := r.URL.Query().Get("refresh_token") code := r.URL.Query().Get("code") oac, err := c.OAuthClient() if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to create OAuth2 client: %v", err)) return } var token oauth2.TokenResponse switch { case code != "": if token, err = oac.RequestToken(oauth2.GrantTypeAuthCode, code); err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to verify auth code with issuer: %v", err)) return } case refreshToken != "": if token, err = oac.RequestToken(oauth2.GrantTypeRefreshToken, refreshToken); err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to refresh token: %v", err)) return } if token.RefreshToken == "" { token.RefreshToken = refreshToken } default: phttp.WriteError(w, http.StatusBadRequest, "code query param must be set") return } tok, err := jose.ParseJWT(token.IDToken) if err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to parse JWT: %v", err)) return } claims := new(bytes.Buffer) if err := json.Indent(claims, tok.Payload, "", " "); err != nil { phttp.WriteError(w, http.StatusBadRequest, fmt.Sprintf("unable to construct claims: %v", err)) return } s := fmt.Sprintf(` <html> <head> <style> /* make pre wrap */ pre { white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ } </style> </head> <body> <p> Token: <pre><code>%v</code></pre></p> <p> Claims: <pre><code>%v</code></pre></p> <p> Refresh Token: <pre><code>%v</code></pre></p> <p><a href="%s?refresh_token=%s">Redeem refresh token</a><p> <p><a href="/resend?jwt=%s">Resend Verification Email</a></p> </body> </html>`, tok.Encode(), claims.String(), token.RefreshToken, r.URL.Path, token.RefreshToken, tok.Encode()) w.Write([]byte(s)) } }