Skip to content

Commit de5c18b

Browse files
Feat: add screen_hint param in /authorize api for explicit signup redirection (#420)
* Feat: - Introduce screen_hint param in /authorize for explicit signup redirection * Feat: - Declare variable for base path and signup path - Add social login on signup page * Refactor: - Update variable name for screen hint param
1 parent fe4c693 commit de5c18b

File tree

3 files changed

+36
-23
lines changed

3 files changed

+36
-23
lines changed

app/src/pages/signup.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Fragment } from 'react';
2-
import { AuthorizerSignup } from '@authorizerdev/authorizer-react';
2+
import { AuthorizerSignup, AuthorizerSocialLogin } from '@authorizerdev/authorizer-react';
33
import styled from 'styled-components';
44
import { Link } from 'react-router-dom';
55

@@ -19,6 +19,7 @@ export default function SignUp({
1919
<Fragment>
2020
<h1 style={{ textAlign: 'center' }}>Sign Up</h1>
2121
<br />
22+
<AuthorizerSocialLogin urlProps={urlProps} />
2223
<AuthorizerSignup urlProps={urlProps} />
2324
<FooterContent>
2425
Already have an account? <Link to="/app"> Login</Link>

server/constants/oauth2.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ const (
1616
ResponseTypeToken = "token"
1717
// For the Implicit grant of id_token, use response_type=id_token to include an identifier token.
1818
ResponseTypeIDToken = "id_token"
19+
20+
// Constant indicating the "signup" screen hint for customizing authentication process and redirect to a signup page.
21+
ScreenHintSignUp = "signup"
1922
)

server/handlers/authorize.go

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ import (
5555
const (
5656
authorizeWebMessageTemplate = "authorize_web_message.tmpl"
5757
authorizeFormPostTemplate = "authorize_form_post.tmpl"
58+
baseAppPath = "/app"
59+
signupPath = "/app/signup"
5860
)
5961

6062
// AuthorizeHandler is the handler for the /authorize route
@@ -74,6 +76,7 @@ func AuthorizeHandler() gin.HandlerFunc {
7476
clientID := strings.TrimSpace(gc.Query("client_id"))
7577
responseMode := strings.TrimSpace(gc.Query("response_mode"))
7678
nonce := strings.TrimSpace(gc.Query("nonce"))
79+
screenHint := strings.TrimSpace(gc.Query("screen_hint"))
7780

7881
var scope []string
7982
if scopeString == "" {
@@ -120,27 +123,33 @@ func AuthorizeHandler() gin.HandlerFunc {
120123

121124
// TODO add state with timeout
122125
// used for response mode query or fragment
123-
loginState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI
126+
authState := "state=" + state + "&scope=" + strings.Join(scope, " ") + "&redirect_uri=" + redirectURI
124127
if responseType == constants.ResponseTypeCode {
125-
loginState += "&code=" + code
128+
authState += "&code=" + code
126129
if err := memorystore.Provider.SetState(state, code+"@@"+codeChallenge); err != nil {
127130
log.Debug("Error setting temp code", err)
128131
}
129132
} else {
130-
loginState += "&nonce=" + nonce
133+
authState += "&nonce=" + nonce
131134
if err := memorystore.Provider.SetState(state, nonce); err != nil {
132135
log.Debug("Error setting temp code", err)
133136
}
134137
}
135138

136-
loginURL := "/app?" + loginState
139+
authURL := baseAppPath + "?" + authState
137140

138-
if responseMode == constants.ResponseModeFragment {
139-
loginURL = "/app#" + loginState
141+
if screenHint == constants.ScreenHintSignUp {
142+
authURL = signupPath + "?" + authState
143+
}
144+
145+
if responseMode == constants.ResponseModeFragment && screenHint == constants.ScreenHintSignUp {
146+
authURL = signupPath + "#" + authState
147+
} else if responseMode == constants.ResponseModeFragment {
148+
authURL = baseAppPath + "#" + authState
140149
}
141150

142151
if responseType == constants.ResponseTypeCode && codeChallenge == "" {
143-
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
152+
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
144153
"type": "authorization_response",
145154
"response": map[string]interface{}{
146155
"error": "code_challenge_required",
@@ -160,23 +169,23 @@ func AuthorizeHandler() gin.HandlerFunc {
160169
sessionToken, err := cookie.GetSession(gc)
161170
if err != nil {
162171
log.Debug("GetSession failed: ", err)
163-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
172+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
164173
return
165174
}
166175

167176
// get session from cookie
168177
claims, err := token.ValidateBrowserSession(gc, sessionToken)
169178
if err != nil {
170179
log.Debug("ValidateBrowserSession failed: ", err)
171-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
180+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
172181
return
173182
}
174183

175184
userID := claims.Subject
176185
user, err := db.Provider.GetUserByID(gc, userID)
177186
if err != nil {
178187
log.Debug("GetUserByID failed: ", err)
179-
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
188+
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
180189
"type": "authorization_response",
181190
"response": map[string]interface{}{
182191
"error": "signup_required",
@@ -197,27 +206,27 @@ func AuthorizeHandler() gin.HandlerFunc {
197206
newSessionTokenData, newSessionToken, newSessionExpiresAt, err := token.CreateSessionToken(user, nonce, claims.Roles, scope, claims.LoginMethod)
198207
if err != nil {
199208
log.Debug("CreateSessionToken failed: ", err)
200-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
209+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
201210
return
202211
}
203212

204213
// TODO: add state with timeout
205214
// if err := memorystore.Provider.SetState(codeChallenge, code+"@"+newSessionToken); err != nil {
206215
// log.Debug("SetState failed: ", err)
207-
// handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
216+
// handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
208217
// return
209218
// }
210219

211220
// TODO: add state with timeout
212221
if err := memorystore.Provider.SetState(code, codeChallenge+"@@"+newSessionToken); err != nil {
213222
log.Debug("SetState failed: ", err)
214-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
223+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
215224
return
216225
}
217226

218227
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+newSessionTokenData.Nonce, newSessionToken, newSessionExpiresAt); err != nil {
219228
log.Debug("SetUserSession failed: ", err)
220-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
229+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
221230
return
222231
}
223232

@@ -251,7 +260,7 @@ func AuthorizeHandler() gin.HandlerFunc {
251260
}
252261
}
253262

254-
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
263+
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
255264
"type": "authorization_response",
256265
"response": map[string]interface{}{
257266
"code": code,
@@ -267,19 +276,19 @@ func AuthorizeHandler() gin.HandlerFunc {
267276
authToken, err := token.CreateAuthToken(gc, user, claims.Roles, scope, claims.LoginMethod, nonce, "")
268277
if err != nil {
269278
log.Debug("CreateAuthToken failed: ", err)
270-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
279+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
271280
return
272281
}
273282

274283
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeSessionToken+"_"+nonce, authToken.FingerPrintHash, authToken.SessionTokenExpiresAt); err != nil {
275284
log.Debug("SetUserSession failed: ", err)
276-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
285+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
277286
return
278287
}
279288

280289
if err := memorystore.Provider.SetUserSession(sessionKey, constants.TokenTypeAccessToken+"_"+nonce, authToken.AccessToken.Token, authToken.AccessToken.ExpiresAt); err != nil {
281290
log.Debug("SetUserSession failed: ", err)
282-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
291+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
283292
return
284293
}
285294

@@ -322,14 +331,14 @@ func AuthorizeHandler() gin.HandlerFunc {
322331
}
323332
}
324333

325-
handleResponse(gc, responseMode, loginURL, redirectURI, map[string]interface{}{
334+
handleResponse(gc, responseMode, authURL, redirectURI, map[string]interface{}{
326335
"type": "authorization_response",
327336
"response": res,
328337
}, http.StatusOK)
329338
return
330339
}
331340

332-
handleResponse(gc, responseMode, loginURL, redirectURI, loginError, http.StatusOK)
341+
handleResponse(gc, responseMode, authURL, redirectURI, loginError, http.StatusOK)
333342
}
334343
}
335344

@@ -352,14 +361,14 @@ func validateAuthorizeRequest(responseType, responseMode, clientID, state, codeC
352361
return nil
353362
}
354363

355-
func handleResponse(gc *gin.Context, responseMode, loginURI, redirectURI string, data map[string]interface{}, httpStatusCode int) {
364+
func handleResponse(gc *gin.Context, responseMode, authURI, redirectURI string, data map[string]interface{}, httpStatusCode int) {
356365
isAuthenticationRequired := false
357366
if _, ok := data["response"].(map[string]interface{})["error"]; ok {
358367
isAuthenticationRequired = true
359368
}
360369

361370
if isAuthenticationRequired && responseMode != constants.ResponseModeWebMessage {
362-
gc.Redirect(http.StatusFound, loginURI)
371+
gc.Redirect(http.StatusFound, authURI)
363372
return
364373
}
365374

0 commit comments

Comments
 (0)