Files
hanko/backend/flow_api/flow/shared/action_thirdparty_oauth.go
bjoern-m 601ffaae92 Introduce Flowpilot - integration (#1532)
This pull request introduces the new Flowpilot system along with several new features and various improvements. The key enhancements include configurable authorization, registration, and profile flows, as well as the ability to enable and disable user identifiers (e.g., email addresses and usernames) and login methods.

---------

Co-authored-by: Frederic Jahn <frederic.jahn@hanko.io>
Co-authored-by: Lennart Fleischmann <lennart.fleischmann@hanko.io>
Co-authored-by: lfleischmann <67686424+lfleischmann@users.noreply.github.com>
Co-authored-by: merlindru <hello@merlindru.com>
2024-08-06 16:07:29 +02:00

88 lines
2.4 KiB
Go

package shared
import (
"fmt"
"github.com/teamhanko/hanko/backend/flowpilot"
"github.com/teamhanko/hanko/backend/thirdparty"
"github.com/teamhanko/hanko/backend/utils"
"golang.org/x/oauth2"
"net/http"
"strings"
)
type ThirdPartyOAuth struct {
Action
}
func (a ThirdPartyOAuth) GetName() flowpilot.ActionName {
return ActionThirdPartyOAuth
}
func (a ThirdPartyOAuth) GetDescription() string {
return "Sign up/sign in with a third party provider via OAuth."
}
func (a ThirdPartyOAuth) Initialize(c flowpilot.InitializationContext) {
deps := a.GetDeps(c)
enabledProviders := deps.Cfg.ThirdParty.Providers.GetEnabled()
if len(enabledProviders) == 0 {
c.SuspendAction()
return
}
providerInput := flowpilot.StringInput("provider").
Hidden(true).
Required(true)
for _, provider := range enabledProviders {
providerInput.AllowedValue(provider.DisplayName, strings.ToLower(provider.DisplayName))
}
c.AddInputs(flowpilot.StringInput("redirect_to").Hidden(true).Required(true), providerInput)
}
func (a ThirdPartyOAuth) Execute(c flowpilot.ExecutionContext) error {
deps := a.GetDeps(c)
errorRedirectTo := deps.HttpContext.Request().Header.Get("Referer")
if errorRedirectTo == "" {
errorRedirectTo = deps.Cfg.ThirdParty.ErrorRedirectURL
}
if valid := c.ValidateInputData(); !valid {
return c.Error(flowpilot.ErrorFormDataInvalid)
}
redirectTo := c.Input().Get("redirect_to").String()
if ok := thirdparty.IsAllowedRedirect(deps.Cfg.ThirdParty, redirectTo); !ok {
return c.Error(flowpilot.ErrorFormDataInvalid)
}
provider, err := thirdparty.GetProvider(deps.Cfg.ThirdParty, c.Input().Get("provider").String())
if err != nil {
return c.Error(flowpilot.ErrorFormDataInvalid.Wrap(err))
}
state, err := thirdparty.GenerateState(&deps.Cfg, provider.Name(), redirectTo, thirdparty.GenerateStateForFlowAPI(true))
if err != nil {
return c.Error(flowpilot.ErrorTechnical.Wrap(err))
}
authCodeUrl := provider.AuthCodeURL(string(state), oauth2.SetAuthURLParam("prompt", "consent"))
cookie := utils.GenerateStateCookie(&deps.Cfg, utils.HankoThirdpartyStateCookie, string(state), utils.CookieOptions{
MaxAge: 300,
Path: "/",
SameSite: http.SameSiteLaxMode,
})
deps.HttpContext.SetCookie(cookie)
if err = c.Payload().Set("redirect_url", authCodeUrl); err != nil {
return fmt.Errorf("failed to set redirect_url to payload: %w", err)
}
return c.Continue(StateThirdParty)
}