func RedirectHandler(client Client, op *OpenIDProvider, successfulAuthRedirectURL string) gin.HandlerFunc {
	return func(c *gin.Context) {
		session := sessions.Default(c)
		authError := c.Query("error")
		if authError != "" {
			session.Delete("state")
			err := errors.Unauthorizedf("OP was unable to successfully authenticate your request: %s", authError)
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		serverState := c.Query("state")
		localState := session.Get("state")
		if localState == nil {
			err := errors.NotValidf("Couldn't find the local state or nonce to verify the response from the OP")
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		if localState.(string) != serverState {
			c.String(http.StatusForbidden, "Nonce or state did not match")
			c.Abort()
		}
		code := c.Query("code")
		token, err := op.Exchange(code, client)
		if err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		session.Set("OpenIDTokenResponse", token)
		ui, err := op.UserInfo(token.AccessToken)
		if err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		session.Set("UserInfo", ui)
		session.Delete("nonce")
		err = session.Save()
		if err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
		}
		c.Redirect(http.StatusFound, successfulAuthRedirectURL)
	}
}
RedirectHandler provides a gin.HandlerFunc to process the authentication response from an
Open ID Provider.
package heart
import (
	"encoding/gob"
	"net/http"
	"strings"
	"time"
	"github.com/gin-gonic/contrib/sessions"
	"github.com/gin-gonic/gin"
	"github.com/icrowley/fake"
	"github.com/juju/errors"
	"gopkg.in/square/go-jose.v1"
)
func init() {
	gob.Register(OpenIDTokenResponse{})
	gob.Register(UserInfo{})
}
func OAuthIntrospectionHandler(endpoint, iss, aud string, pk jose.JsonWebKey) gin.HandlerFunc {
	return func(c *gin.Context) {
		auth := c.Request.Header.Get("Authorization")
		if auth == "" {
			c.String(http.StatusForbidden, "No Authorization header provided")
			c.Abort()
			return
		}
		token := strings.TrimPrefix(auth, "Bearer ")
		if token == auth {
			c.String(http.StatusForbidden, "Could not find bearer token in Authorization header")
			c.Abort()
			return
		}
		jwt := NewClientJWT(iss, aud)
		clientAssertion, err := SignJWT(jwt, pk)
		if err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		ir, err := IntrospectToken(endpoint, token, iss, clientAssertion)
		if err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		if !ir.Active {
			c.String(http.StatusForbidden, "Provided token is no longer active")
			c.Abort()
			return
		}
		c.Set("scopes", ir.SplitScope())
		c.Set("subject", ir.SUB)
		c.Set("clientID", ir.ClientID)
	}
}
func OIDCAuthenticationHandler(client Client, op *OpenIDProvider) gin.HandlerFunc {
	return func(c *gin.Context) {
		if strings.Contains(c.Request.URL.Path, "/redirect") {
			return
		}
		session := sessions.Default(c)
		ui := session.Get("UserInfo")
		if ui != nil {
			tokenInterface := session.Get("OpenIDTokenResponse")
			if tokenInterface != nil {
				token := tokenInterface.(OpenIDTokenResponse)
				if token.Expiration.After(time.Now()) {
					c.Set("UserInfo", session.Get("UserInfo"))
					return
				}
				valid, err := op.Validate(token.IDToken)
				if err != nil || !valid {
					c.Abort()
					c.String(http.StatusForbidden, "Provided IDToken is not valid or could not be validated")
				}
				session.Delete("UserInfo")
				session.Delete("OpenIDTokenResponse")
			}
		}
		state := fake.CharactersN(20)
		session.Set("state", state)
		err := session.Save()
		if err != nil {
			c.AbortWithError(http.StatusInternalServerError, err)
			return
		}
		authURL := op.AuthURL(client, state)
		c.Redirect(http.StatusFound, authURL)
		c.Abort()
	}
}