func setQueryPairs(v url.Values, pairs ...string) {
	for i := 0; i < len(pairs); i += 2 {
		if pairs[i+1] != "" {
			v.Set(pairs[i], pairs[i+1])
		}
	}
}
----------------------------------------------------------------------------
setQueryPairs sets non-empty values in a url.Values.

This is just a convenience to avoid checking for emptiness for each value.
package server
import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)
type Store interface {
	GetClient(clientID string) (Client, error)
	CreateAuthCode(r AuthCodeRequest) (string, error)
}
type Client interface {
	ID() string
	Type() string
	RedirectURI() string
	ValidateRedirectURI(string) string
}
type AuthCodeRequest struct {
	ClientID     string
	ResponseType string
	RedirectURI  string
	Scope        string
	State        string
}
type AccessTokenRequest struct {
	GrantType   string
	Code        string
	RedirectURI string
}
func NewServer() *Server {
	return &Server{
		errorURIs: make(map[errorCode]string),
	}
}
type Server struct {
	Store     Store
	errorURIs map[errorCode]string
}
func (s *Server) RegisterErrorURI(code errorCode, uri string) {
	s.errorURIs[code] = uri
}
func (s *Server) NewError(code errorCode, description string) ServerError {
	return NewServerError(code, description, s.errorURIs[code])
}
func (s *Server) NewAuthCodeRequest(r *http.Request) AuthCodeRequest {
	v := r.URL.Query()
	return AuthCodeRequest{
		ClientID:     v.Get("client_id"),
		ResponseType: v.Get("response_type"),
		RedirectURI:  v.Get("redirect_uri"),
		Scope:        v.Get("scope"),
		State:        v.Get("state"),
	}
}
func (s *Server) HandleAuthCodeRequest(w http.ResponseWriter, r *http.Request) error {
	req := s.NewAuthCodeRequest(r)
	var err error
	if req.ClientID == "" {
		err = s.NewError(ErrorCodeInvalidRequest,
			"The \"client_id\" parameter is missing.")
	} else if req.ResponseType == "" {
		err = s.NewError(ErrorCodeInvalidRequest,
			"The \"response_type\" parameter is missing.")
	} else if req.ResponseType != "code" {
		err = s.NewError(ErrorCodeUnsupportedResponseType,
			fmt.Sprintf("The response type %q is not supported.",
			req.ResponseType))
	}
	var redirectURI *url.URL
	if req.ClientID != "" {
		client, clientErr := s.Store.GetClient(req.ClientID)
		if client == nil {
			if err == nil {
				err = s.NewError(ErrorCodeInvalidRequest,
					"The \"client_id\" parameter is invalid.")
			}
		} else {
			if u, uErr := validateRedirectURI(
				client.ValidateRedirectURI(req.RedirectURI)); uErr == nil {
				redirectURI = u
			} else {
				if err == nil {
					if req.RedirectURI == "" {
						err = s.NewError(ErrorCodeInvalidRequest,
							"Missing redirection URI.")
					} else {
						err = s.NewError(ErrorCodeInvalidRequest, uErr.Error())
					}
				}
			}
			if clientErr != nil && err == nil {
				err = clientErr
			}
		}
	}
	if redirectURI == nil {
		return err
	}
	query := redirectURI.Query()
	setQueryPairs(query, "state", req.State)
	var code string
	if err == nil {
		code, err = s.Store.CreateAuthCode(req)
	}
	if err == nil {
		query.Set("code", code)
	} else {
		e, ok := err.(ServerError)
		if !ok {
			e = s.NewError(ErrorCodeServerError, e.Error())
		}
		setQueryPairs(query,
			"error", string(e.Code()),
			"error_description", e.Description(),
			"error_uri", e.URI(),
		)
	}
	redirectURI.RawQuery = query.Encode()
	http.Redirect(w, r, redirectURI.String(), 302)
	return nil
}