github.com/circl-dev/go-swagger@v0.31.0/examples/oauth2/restapi/implementation.go (about) 1 package restapi 2 3 // THIS CODE HAS NOT BEEN GENERATED 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "log" 9 "net/http" 10 11 "github.com/circl-dev/runtime" 12 "github.com/circl-dev/runtime/middleware" 13 oidc "github.com/coreos/go-oidc" 14 "golang.org/x/net/context" 15 "golang.org/x/oauth2" 16 ) 17 18 var ( 19 // state carries an internal token during the oauth2 workflow 20 // we just need a non empty initial value 21 state = "foobar" // Don't make this a global in production. 22 23 // the credentials for this API (adapt values when registering API) 24 clientID = "" // <= enter registered API client ID here 25 clientSecret = "" // <= enter registered API client secret here 26 27 // unused in this example: the signer of the delivered token 28 // issuer = "https://accounts.google.com" 29 30 // the Google login URL 31 authURL = "https://accounts.google.com/o/oauth2/v2/auth" 32 33 // the Google OAuth2 resource provider which delivers access tokens 34 /* #nosec */ 35 tokenURL = "https://www.googleapis.com/oauth2/v4/token" 36 userInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo" 37 38 // our endpoint to be called back by the redirected client 39 callbackURL = "http://127.0.0.1:12345/api/auth/callback" 40 41 // the description of the OAuth2 flow 42 endpoint = oauth2.Endpoint{ 43 AuthURL: authURL, 44 TokenURL: tokenURL, 45 } 46 47 config = oauth2.Config{ 48 ClientID: clientID, 49 ClientSecret: clientSecret, 50 Endpoint: endpoint, 51 RedirectURL: callbackURL, 52 Scopes: []string{oidc.ScopeOpenID, "profile", "email"}, 53 } 54 ) 55 56 func login(r *http.Request) middleware.Responder { 57 // implements the login with a redirection 58 return middleware.ResponderFunc( 59 func(w http.ResponseWriter, pr runtime.Producer) { 60 http.Redirect(w, r, config.AuthCodeURL(state), http.StatusFound) 61 }) 62 } 63 64 func callback(r *http.Request) (string, error) { 65 // we expect the redirected client to call us back 66 // with 2 query params: state and code. 67 // We use directly the Request params here, since we did not 68 // bother to document these parameters in the spec. 69 70 if r.URL.Query().Get("state") != state { 71 log.Println("state did not match") 72 return "", fmt.Errorf("state did not match") 73 } 74 75 myClient := &http.Client{} 76 77 parentContext := context.Background() 78 ctx := oidc.ClientContext(parentContext, myClient) 79 80 authCode := r.URL.Query().Get("code") 81 log.Printf("Authorization code: %v\n", authCode) 82 83 // Exchange converts an authorization code into a token. 84 // Under the hood, the oauth2 client POST a request to do so 85 // at tokenURL, then redirects... 86 oauth2Token, err := config.Exchange(ctx, authCode) 87 if err != nil { 88 log.Println("failed to exchange token", err.Error()) 89 return "", fmt.Errorf("failed to exchange token") 90 } 91 92 // the authorization server's returned token 93 log.Println("Raw token data:", oauth2Token) 94 return oauth2Token.AccessToken, nil 95 } 96 97 func authenticated(token string) (bool, error) { 98 // validates the token by sending a request at userInfoURL 99 bearToken := "Bearer " + token 100 req, err := http.NewRequest("GET", userInfoURL, nil) 101 if err != nil { 102 return false, fmt.Errorf("http request: %v", err) 103 } 104 105 req.Header.Add("Authorization", bearToken) 106 107 cli := &http.Client{} 108 resp, err := cli.Do(req) 109 if err != nil { 110 return false, fmt.Errorf("http request: %v", err) 111 } 112 defer resp.Body.Close() 113 114 _, err = ioutil.ReadAll(resp.Body) 115 if err != nil { 116 return false, fmt.Errorf("fail to get response: %v", err) 117 } 118 if resp.StatusCode != 200 { 119 return false, nil 120 } 121 return true, nil 122 }