How to Pass Additional Parameters in SSO Login

Hi Team, I'm currently working on a custom Sign In/Sign Up authentication flow using Google authentication. During sign-up, users need to check two checkboxes(refer to the screenshots), but this requirement doesn't apply during sign-in. I've implemented the logic and basic client side error handling in React, but I'm unsure about the following: I need to ensure that new users have accepted both checkboxes before granting access to our application. Is there a way to pass the checkbox click status as additional query parameters (nonces) to the /auth/google/login route in Wasp 0.13.0? Additionally, can I retrieve this status in defineUserSignupFields (inside the data param) to validate that new users have indeed checked the checkboxes during sign-up? Alternatively, do you have any suggestions for a better approach to handle this situation? Thank you for your assistance.
No description
No description
14 Replies
kapa.ai
kapa.ai8mo ago
Hi @Harish. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the provided knowledge sources, Wasp allows you to customize the signup process by defining extra fields and customizing the SignupForm component. However, there is no direct mention of passing additional query parameters to the /auth/google/login route or retrieving this status in defineUserSignupFields. For customizing the signup process, you can define extra fields that you want to be saved in the database. This can be done using the defineUserSignupFields function as shown in the API Reference (https://wasp-lang.dev/docs/auth/social-auth/google#api-reference). Here is an example:
import { defineUserSignupFields } from 'wasp/server/auth'

export const userSignupFields = defineUserSignupFields({
address: (data) => {
if (!data.address) {
throw new Error('Address is required')
}
return data.address
}
phone: (data) => data.phone,
})
import { defineUserSignupFields } from 'wasp/server/auth'

export const userSignupFields = defineUserSignupFields({
address: (data) => {
if (!data.address) {
throw new Error('Address is required')
}
return data.address
}
phone: (data) => data.phone,
})
You can also customize the SignupForm component by passing the additionalFields prop to it. This can be either a list of extra fields or a render function. Here is an example:
import { SignupForm, FormItemGroup } from 'wasp/client/auth'

export const SignupPage = () => {
return (
<SignupForm
additionalFields={(form, state) => {
const username = form.watch('username')
return (
username && (
<FormItemGroup>
Hello there <strong>{username}</strong> 👋
</FormItemGroup>
)
)
}}
/>
)
}
import { SignupForm, FormItemGroup } from 'wasp/client/auth'

export const SignupPage = () => {
return (
<SignupForm
additionalFields={(form, state) => {
const username = form.watch('username')
return (
username && (
<FormItemGroup>
Hello there <strong>{username}</strong> 👋
</FormItemGroup>
)
)
}}
/>
)
}
However, these methods seem to be more related to adding extra fields to the signup form and saving them in the database, rather than passing additional query parameters to the /auth/google/login route. For your specific requirement of ensuring that new users have accepted both checkboxes before granting access to the application, you might need to handle this on the client side, possibly by disabling the signup button until both checkboxes are checked. This is not directly covered in the provided knowledge sources. I would recommend checking the Wasp documentation or reaching out to the Wasp community for more specific guidance on this topic. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ---------------------- Sorry @Harish, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
Filip
Filip8mo ago
@Vinny (@Wasp) can we do something about how our bot formats the code? Or are we left at the mercy of the resources it uses and its "brain"? @martinsos @miho You're more in the loop with the auth stuff than I am... Is this something Wasp can currently do? If Wasp can't do this, is it something that the login/signup hooks we're working on this sprint would enable? If login hooks won't be able to do this, do we have an issue that talks about this behavior? @Harish Thanks for the question! I've tagged all the relevant people, someone will come up with something useful 🙂
martinsos
martinsos8mo ago
We are left at the mercy of it, if I am correct. While @miho will know the best, I will try to start the conversation a bit. @Harish , why would you want to pass data as query to /login route? You said you want those checkmarks to be checked in order for sign-up to pass -> how is that connected to query params in login? Regarding your issue, I think that additionalFields prop of SignupForm might be exactly what you need: https://wasp-lang.dev/docs/auth/overview#2-customizing-the-signup-component . You should be able to define these two additional fields there, and then also add logic there that confirms they are checked.
Harish
HarishOP8mo ago
Hi @martinsos: Thank you for your response and for pointing me to the additionalFields property of SignupForm in Wasp. From what I've gathered in the documentation, it seems that we can only add additional fields in Email or Username & Password authentication methods (please correct me if I'm mistaken). However, since we use only Google Single Sign-On (SSO) as auth method, I am wondering if there is a way to achieve the same functionality of adding additional fields specifically within the Google Authentication flow. I noticed a section in the documentation about overriding and using data from Google (https://wasp-lang.dev/docs/auth/social-auth/google#overrides), but I'm not sure if this extends to adding extra fields.
Google | Wasp
Wasp supports Google Authentication out of the box.
martinsos
martinsos8mo ago
I will let @miho give the final word here, but I thought additionalFIelds work regardless of the type of the auth methods used! Notice this is not userSignupFields, this is additionalFields, which is a prop on SignupForm React component that Wasp gives you. I might be wrong, I haven't tried it out at this very moment, but this is what I get from reading the docs (they are a bit confusing though I admit).
miho
miho8mo ago
The additional fields in the UI get passed along only for the Email and Username methods. Not Google or any other method. The trouble is that the flow starts by visiting a link which redirects to Google. This is quite similar to a problem someone else had when they wanted to passthrough params on the link all the way to the home page after login. We should really figure how you can set things in the session which you can access on some postLogin hook (future work)! Okay, something a bit basic but it might work: on check box change, save some state in the local storage. On successful login, check local storage and trigger an action to update the DB if something is found in local storage. Let me know if this works for you @Harish? If you need more info than this let me know, I can prepare a gist for you.
martinsos
martinsos8mo ago
Thanks @miho and @Harish sorry for the wrong info! @miho is it clear from the docs somewhere that this works only for email and username? I was trying to find this details but couldn't felt like it works for anything. Maybe we coudl add an issue to explain this better? Also, should we create an issue (if we don't have it yet) for adding this support also for other methods?
miho
miho8mo ago
Maybe a diagram could be useful in the docs for people to better understand the data flow 🫡 We can't add support for social methods to receive the form data because of the reasons I explained above 😐
martinsos
martinsos8mo ago
@miho got it! Hm. I wonder how other auth libraries do it. I think the move with storing that info into session data is reasonable. What I can't find in the docs is the info on what happens with those additional fields, defined via additionalFields hm. I guess they get passed along the other fields, like email, so if somebody is going to use them, ok. But we never explain how ot use them, because the only thing that can use them is our default signup action that is being used by Auth UI? So how I could imagine it working for Google sign up, is that you can still define additionalFields, and then we store them for you in the session data/storage. Or, you can maybe access the in the pre-signup hook and store them yourself. Btw to make it work for these checkboxes we wouldn't even need that -> we would just need to run validation for those fields, nobody even has to look at themor store them anywhere or use them. Which is why I thought this maybe already works.
miho
miho8mo ago
userSignupFields is used for: saving additional fields on the User entity which you can base on the data you receive from an auth method. The fields you receive depend on the auth method. For the password based method, that data is the form that's submited. For the OAuth methods, that data is the data we receive from for example Google. Getting the form data when using OAuth method To receive the data from the form is not really possible since it's never submitted. The OAuth flow starts by visiting a link and ends with a redirect to our frontend. This means that we need to somehow take the form state, save it and then load it when we resolve the callback. If we want to do it in the signup flow: 1. Save the data somehow on change (save it in localStorage; or save it in the DB but give it some random ID which you also save in the localstorage) 2. After a successful redirect, get the data and send it to the callback endpoint (no currently possible, but if we enable callback page customization, it would be) Or if we want to do it after the successful login: 1. Same as above 2. Have some custom logic on the homepage (custom code that checks the localstorage and passes the data via an action, or if you stored the extra info in the DB and just saved some ID in the localstorage, just send the ID and then update the User entity on the backend Additional option Have a two step signup process, you have a property on User called hasFinishedOnboarding and then you redirect to /finish-onboarding if the value is false where you can have an additional form to fill out the extra data you need. This is super simple and it gives a way to offer a completely custom from to fill out. How others do it - Supabase doesn't offer putting extra fields in their Auth UI https://supabase.com/docs/guides/auth/auth-helpers/auth-ui - Clerk offers some unsafeMetadata you can set during the signup process
Supabase
Auth UI | Supabase Docs
A prebuilt, customizable React component for authenticating users.
Harish
HarishOP8mo ago
Hi @miho : Yup, I was also thinking about options like this as an alternative. Let me try it and get back to you incase i have any further questions. Thanks for your timely reply 🙂
miho
miho8mo ago
No problem 🙂 I'll try playing around with this myself and see if I can produce a working example for future reference First, we setup our signup page like this:
import { useEffect, useState } from "react";
import { FormItemGroup, FormLabel, SignupForm } from "wasp/client/auth";

export function LoginPage() {
const [acceptedTerms, setAcceptedTerms] = useState(false);
useEffect(() => {
saveExtraUserInfo({ acceptedTerms });
}, [acceptedTerms]);
return (
<div>
<SignupForm />
<FormItemGroup>
<FormLabel>
I accept the terms of service
<input
type="checkbox"
checked={acceptedTerms}
onChange={(e) => setAcceptedTerms(e.target.checked)}
/>
</FormLabel>
</FormItemGroup>
</div>
);
}

const extraDataKey = "user:extraInfo";

function saveExtraUserInfo(data: Record<string, unknown>) {
localStorage.setItem(extraDataKey, JSON.stringify(data));
}

export function loadExtraUserInfo(): Record<string, unknown> | null {
const data = localStorage.getItem(extraDataKey);
try {
const parsedData = data ? JSON.parse(data) : null;
localStorage.removeItem("user:extraInfo");
return parsedData;
} catch (e) {
console.error("Failed to parse extra info:", data);
return null;
}
}
import { useEffect, useState } from "react";
import { FormItemGroup, FormLabel, SignupForm } from "wasp/client/auth";

export function LoginPage() {
const [acceptedTerms, setAcceptedTerms] = useState(false);
useEffect(() => {
saveExtraUserInfo({ acceptedTerms });
}, [acceptedTerms]);
return (
<div>
<SignupForm />
<FormItemGroup>
<FormLabel>
I accept the terms of service
<input
type="checkbox"
checked={acceptedTerms}
onChange={(e) => setAcceptedTerms(e.target.checked)}
/>
</FormLabel>
</FormItemGroup>
</div>
);
}

const extraDataKey = "user:extraInfo";

function saveExtraUserInfo(data: Record<string, unknown>) {
localStorage.setItem(extraDataKey, JSON.stringify(data));
}

export function loadExtraUserInfo(): Record<string, unknown> | null {
const data = localStorage.getItem(extraDataKey);
try {
const parsedData = data ? JSON.parse(data) : null;
localStorage.removeItem("user:extraInfo");
return parsedData;
} catch (e) {
console.error("Failed to parse extra info:", data);
return null;
}
}
and then we get the value on our Main page:
import { useEffect } from "react";
import "./Main.css";
import { loadExtraUserInfo } from "./auth";

export const MainPage = ({ user }) => {
useEffect(() => {
const data = loadExtraUserInfo();
if (data && data.acceptedTerms === true) {
alert("You have accepted the terms and conditions");
}
}, []);
return (
<div className="container">
<main>
You are logged in. The user data we have is:
<pre>{JSON.stringify(user, null, 2)}</pre>
</main>
</div>
);
};
import { useEffect } from "react";
import "./Main.css";
import { loadExtraUserInfo } from "./auth";

export const MainPage = ({ user }) => {
useEffect(() => {
const data = loadExtraUserInfo();
if (data && data.acceptedTerms === true) {
alert("You have accepted the terms and conditions");
}
}, []);
return (
<div className="container">
<main>
You are logged in. The user data we have is:
<pre>{JSON.stringify(user, null, 2)}</pre>
</main>
</div>
);
};
Additional example we have in our docs, "allowing users to set their username" might be useful to illustrate the two step signup process: https://wasp-lang.dev/docs/auth/social-auth/overview#example-allowing-user-to-set-their-username
Harish
HarishOP8mo ago
Thanks a lot for the code reference 👍
martinsos
martinsos8mo ago
Thanks @miho ! I also created an issue based on some questions asked here and my feeling that docs are not clear enough: https://github.com/wasp-lang/wasp/issues/1945 .
Want results from more Discord servers?
Add your server