Repository: deepmap/oapi-codegen
Pull request #175 (2020-04-23 07:13:03)

Update security provider function signature
Unfortunately https://github.com/deepmap/oapi-codegen/pull/148 broke the security providers.

lukekhamilton: Another thing that I think would also be super useful for people is some actually example implantations of how the `securitySchemes` are built out. I am currently trying to work this side of this package out right now, and its not 100% to me. I personally would appreciate this from someone that already has their head in the space. :)
srueg: The wrong function signature was exactly the bug I was talking about. So swapping the values solves it. This change was introduced in https://github.com/deepmap/oapi-codegen/pull/148 and unfortunately not updated accordingly everywhere (hence the tests so this can't happen again).

The usage of these security providers is already documented in the README: https://github.com/deepmap/oapi-codegen#using-securityproviders
lukekhamilton: Question, So is this only for the client side of this package? @srueg 

Sorry still getting my head across the security provider stuff here. 
srueg: Yes exactly. From what I've seen there's no implementation for security providers on the server side code.
lukekhamilton: Yeah cool, that what it looks like to me, but wasnt sure if I was reading the code correctly. Thank
srueg: Anything I can do to get this merged?
ping @deepmap-marcinr 

Patch:
diff --git a/pkg/codegen/templates/chi-middleware.tmpl b/pkg/codegen/templates/chi-middleware.tmpl
index 68d8664..4ec3b39 100644
--- a/pkg/codegen/templates/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi-middleware.tmpl
@@ -113,7 +113,7 @@ func {{$opid}}Ctx(next http.Handler) http.Handler {
             params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
 
           } {{if .Required}}else {
-              http.Error(w, fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found", err), http.StatusBadRequest)
+              http.Error(w, fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest)
               return
           }{{end}}
 
diff --git a/pkg/codegen/templates/templates.gen.go b/pkg/codegen/templates/templates.gen.go
index a7d8eb4..04e7fc3 100644
--- a/pkg/codegen/templates/templates.gen.go
+++ b/pkg/codegen/templates/templates.gen.go
@@ -209,7 +209,7 @@ func {{$opid}}Ctx(next http.Handler) http.Handler {
             params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
 
           } {{if .Required}}else {
-              http.Error(w, fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found", err), http.StatusBadRequest)
+              http.Error(w, fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found: %s", err), http.StatusBadRequest)
               return
           }{{end}}
 
diff --git a/pkg/securityprovider/securityprovider.go b/pkg/securityprovider/securityprovider.go
index 265d788..940fc5b 100644
--- a/pkg/securityprovider/securityprovider.go
+++ b/pkg/securityprovider/securityprovider.go
@@ -41,7 +41,7 @@ type SecurityProviderBasicAuth struct {
 
 // Intercept will attach an Authorization header to the request and ensures that
 // the username, password are base64 encoded and attached to the header.
-func (s *SecurityProviderBasicAuth) Intercept(req *http.Request, ctx context.Context) error {
+func (s *SecurityProviderBasicAuth) Intercept(ctx context.Context, req *http.Request) error {
 	req.SetBasicAuth(s.username, s.password)
 	return nil
 }
@@ -62,7 +62,7 @@ type SecurityProviderBearerToken struct {
 
 // Intercept will attach an Authorization header to the request
 // and ensures that the bearer token is attached to the header.
-func (s *SecurityProviderBearerToken) Intercept(req *http.Request, ctx context.Context) error {
+func (s *SecurityProviderBearerToken) Intercept(ctx context.Context, req *http.Request) error {
 	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", s.token))
 	return nil
 }
@@ -70,16 +70,16 @@ func (s *SecurityProviderBearerToken) Intercept(req *http.Request, ctx context.C
 // NewSecurityProviderApiKey will attach a generic apiKey for a given name
 // either to a cookie, header or as a query parameter.
 func NewSecurityProviderApiKey(in, name, apiKey string) (*SecurityProviderApiKey, error) {
-	interceptors := map[string]func(req *http.Request, ctx context.Context) error{
-		"cookie": func(req *http.Request, ctx context.Context) error {
+	interceptors := map[string]func(ctx context.Context, req *http.Request) error{
+		"cookie": func(ctx context.Context, req *http.Request) error {
 			req.AddCookie(&http.Cookie{Name: name, Value: apiKey})
 			return nil
 		},
-		"header": func(req *http.Request, ctx context.Context) error {
+		"header": func(ctx context.Context, req *http.Request) error {
 			req.Header.Add(name, apiKey)
 			return nil
 		},
-		"query": func(req *http.Request, ctx context.Context) error {
+		"query": func(ctx context.Context, req *http.Request) error {
 			query := req.URL.Query()
 			query.Add(name, apiKey)
 			req.URL.RawQuery = query.Encode()
@@ -100,11 +100,11 @@ func NewSecurityProviderApiKey(in, name, apiKey string) (*SecurityProviderApiKey
 // SecurityProviderApiKey will attach an apiKey either to a
 // cookie, header or query.
 type SecurityProviderApiKey struct {
-	interceptor func(req *http.Request, ctx context.Context) error
+	interceptor func(ctx context.Context, req *http.Request) error
 }
 
 // Intercept will attach a cookie, header or query param for the configured
 // name and apiKey.
-func (s *SecurityProviderApiKey) Intercept(req *http.Request, ctx context.Context) error {
-	return s.interceptor(req, ctx)
+func (s *SecurityProviderApiKey) Intercept(ctx context.Context, req *http.Request) error {
+	return s.interceptor(ctx, req)
 }


Test patch:
diff --git a/pkg/securityprovider/securityprovider_test.go b/pkg/securityprovider/securityprovider_test.go
new file mode 100644
index 0000000..efea758
--- /dev/null
+++ b/pkg/securityprovider/securityprovider_test.go
@@ -0,0 +1,42 @@
+package securityprovider
+
+import (
+	"testing"
+
+	"github.com/deepmap/oapi-codegen/internal/test/client"
+	"github.com/stretchr/testify/assert"
+)
+
+var (
+	withTrailingSlash string = "https://my-api.com/some-base-url/v1/"
+)
+
+func TestSecurityProviders(t *testing.T) {
+	bearer, err := NewSecurityProviderBearerToken("mytoken")
+	assert.NoError(t, err)
+	client1, err := client.NewClient(
+		withTrailingSlash,
+		client.WithRequestEditorFn(bearer.Intercept),
+	)
+	assert.NoError(t, err)
+
+	apiKey, err := NewSecurityProviderApiKey("cookie", "apikey", "mykey")
+	assert.NoError(t, err)
+	client2, err := client.NewClient(
+		withTrailingSlash,
+		client.WithRequestEditorFn(apiKey.Intercept),
+	)
+	assert.NoError(t, err)
+
+	basicAuth, err := NewSecurityProviderBasicAuth("username", "password")
+	assert.NoError(t, err)
+	client3, err := client.NewClient(
+		withTrailingSlash,
+		client.WithRequestEditorFn(basicAuth.Intercept),
+	)
+	assert.NoError(t, err)
+
+	assert.Equal(t, withTrailingSlash, client1.Server)
+	assert.Equal(t, withTrailingSlash, client2.Server)
+	assert.Equal(t, withTrailingSlash, client3.Server)
+}