github.com/thetreep/go-swagger@v0.0.0-20240223100711-35af64f14f01/examples/oauth2/restapi/implementation.go (about)

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