Skip to content

Commit

Permalink
Redirect on oauth session expired authgear#3813
Browse files Browse the repository at this point in the history
Return to user app if user visits expired oauth pages e.g. oauth consent.

It mostly likely happens when users refresh on expired oauth page or go back after oauth flow has completed e.g. settings action.
  • Loading branch information
IniZio authored and louischan-oursky committed Mar 6, 2024
1 parent 19edf45 commit 637993c
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 13 deletions.
38 changes: 36 additions & 2 deletions pkg/lib/oauth/handler/handler_authz.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ func (h *AuthorizationHandler) HandleConsentWithUserCancel(req *http.Request) ht
RedirectURI: nil,
}
if errors.As(err, &oauthError) {
resultErr.Response = oauthError.Response
resultErr := h.prepareErrInvalidOAuthResponse(req, *oauthError)
return resultErr
} else {
h.Logger.WithError(err).Error("authz handler failed")
resultErr.Response = protocol.NewErrorResponse("server_error", "internal server error")
Expand Down Expand Up @@ -241,7 +242,8 @@ func (h *AuthorizationHandler) doHandleConsent(req *http.Request, withUserConsen
RedirectURI: nil,
}
if errors.As(err, &oauthError) {
resultErr.Response = oauthError.Response
resultErr := h.prepareErrInvalidOAuthResponse(req, *oauthError)
return resultErr, nil
} else {
h.Logger.WithError(err).Error("authz handler failed")
resultErr.Response = protocol.NewErrorResponse("server_error", "internal server error")
Expand Down Expand Up @@ -668,3 +670,35 @@ func (h *AuthorizationHandler) generateSettingsActionResponse(
resp.Code(code)
return nil
}

func (h *AuthorizationHandler) prepareErrInvalidOAuthResponse(req *http.Request, oauthError protocol.OAuthProtocolError) httputil.Result {
resultErr := authorizationResultError{
Response: oauthError.Response,
RedirectURI: nil,
}

// Only redirect if oauth session is expired / not found
// It mostly happens when user refresh the page or go back to the page after authenication
if oauthError.Type() != "invalid_request" {
return resultErr
}

redirectURI, err := url.Parse(req.URL.Query().Get("redirect_uri"))
if err != nil {
return resultErr
}

client := h.ClientResolver.ResolveClient(req.URL.Query().Get("client_id"))
if client == nil {
return resultErr
}

err = validateRedirectURI(client, h.HTTPProto, h.HTTPOrigin, h.AppDomains, redirectURI)
if err != nil {
return resultErr
}

resultErr.RedirectURI = redirectURI

return resultErr
}
34 changes: 23 additions & 11 deletions pkg/lib/oauth/oidc/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,27 @@ type UIInfoResolver struct {
}

func (r *UIInfoResolver) SetAuthenticationInfoInQuery(redirectURI string, e *authenticationinfo.Entry) string {
consentURI := r.EndpointsProvider.ConsentEndpointURL().String()
consentURL := r.EndpointsProvider.ConsentEndpointURL()

url, err := url.Parse(redirectURI)
if err != nil {
panic(err)
}

// Not redirecting to the consent endpoint.
// Do not set anything.
if redirectURI != consentURI {
if SameEndpoint(url, consentURL) {
return redirectURI
}
u, err := url.Parse(redirectURI)
if err != nil {
panic(err)
}

q := u.Query()
q := url.Query()
q.Set("code", e.ID)
u.RawQuery = q.Encode()
return u.String()
url.RawQuery = q.Encode()
return url.String()
}

func SameEndpoint(urlA *url.URL, urlB *url.URL) bool {
return urlA.Scheme == urlB.Scheme && urlA.Host == urlB.Host && urlA.Path == urlB.Path
}

func (r *UIInfoResolver) GetAuthenticationInfoID(req *http.Request) (string, bool) {
Expand Down Expand Up @@ -186,7 +192,13 @@ func (r *UIInfoResolver) ResolveForAuthorizationEndpoint(
client *config.OAuthClientConfig,
req protocol.AuthorizationRequest,
) (*UIInfo, *UIInfoByProduct, error) {
redirectURI := r.EndpointsProvider.ConsentEndpointURL().String()
redirectURI := r.EndpointsProvider.ConsentEndpointURL()

// Add client_id and redirect_uri to URL as hint when oauth session expires / not found
q := redirectURI.Query()
q.Add("client_id", req.ClientID())
q.Add("redirect_uri", req.RedirectURI())
redirectURI.RawQuery = q.Encode()

idToken, sidSession, err := r.IDTokenHintResolver.ResolveIDTokenHint(client, req)
if err != nil {
Expand Down Expand Up @@ -228,7 +240,7 @@ func (r *UIInfoResolver) ResolveForAuthorizationEndpoint(

info := &UIInfo{
ClientID: req.ClientID(),
RedirectURI: redirectURI,
RedirectURI: redirectURI.String(),
Prompt: prompt,
UserIDHint: userIDHint,
CanUseIntentReauthenticate: canUseIntentReauthenticate,
Expand Down
1 change: 1 addition & 0 deletions pkg/lib/oauth/protocol/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ func NewErrorWithErrorResponse(resp ErrorResponse) error {
}

func (e *OAuthProtocolError) Error() string { return e.Response["error_description"] }
func (e *OAuthProtocolError) Type() string { return e.Response["error"] }

0 comments on commit 637993c

Please sign in to comment.