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