github.com/hashicorp/cap@v0.6.0/oidc/examples/spa/route_success.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package main 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "net/http" 11 "os" 12 "time" 13 14 "github.com/hashicorp/cap/oidc" 15 ) 16 17 func SuccessHandler(ctx context.Context, rc *requestCache) http.HandlerFunc { 18 const op = "SuccessHandler" 19 return func(w http.ResponseWriter, r *http.Request) { 20 state := r.FormValue("state") 21 oidcRequest, err := rc.Read(ctx, state) 22 if err != nil { 23 fmt.Fprintf(os.Stderr, "error reading state during successful response: %s", err) 24 http.Error(w, err.Error(), http.StatusInternalServerError) 25 return 26 } 27 defer rc.Delete(state) 28 extended, ok := oidcRequest.(extendedRequest) 29 if !ok { 30 err := fmt.Errorf("%s: not an extended state", op) 31 fmt.Fprint(os.Stderr, err) 32 http.Error(w, err.Error(), http.StatusInternalServerError) 33 return 34 } 35 36 t := printableToken(extended.t) 37 tokenData, err := json.MarshalIndent(t, "", " ") 38 if err != nil { 39 fmt.Fprint(os.Stderr, err) 40 http.Error(w, err.Error(), http.StatusInternalServerError) 41 return 42 } 43 if _, err := w.Write(tokenData); err != nil { 44 http.Error(w, err.Error(), http.StatusInternalServerError) 45 } 46 } 47 } 48 49 type respToken struct { 50 IDToken string 51 AccessToken string 52 RefreshToken string 53 Expiry time.Time 54 } 55 56 // printableToken is needed because the oidc.Token redacts the IDToken, 57 // AccessToken and RefreshToken 58 func printableToken(t oidc.Token) respToken { 59 return respToken{ 60 IDToken: string(t.IDToken()), 61 AccessToken: string(t.AccessToken()), 62 RefreshToken: string(t.RefreshToken()), 63 Expiry: t.Expiry(), 64 } 65 }