Sign Up with google account to Firebase-based Web App - reactjs

It seems that Firebase only provides the way to sign IN an app with Firebase as BaaS. I'm not sure if I missed something; if so, let me know what I can use to sign UP a new account with Google but it should be different the manner we sign IN to it.
If there isn't a solution, please let me know how I can customize a Sign-up function.
This is what I am using now:
const provider = new firebase.auth.GoogleAuthProvider();
const signInWithGoogle = () => {
auth.signInWithPopup(provider);
};

Firebase Authentication is only focussed on authenticating a user, so for them to prove who they are by providing their credentials. For OAuth providers (such as Google) the user already provided those credentials elsewhere, so there is no need for them to sign up with Firebase Authentication. All that is needed is the credentials from the OAuth provider, as in the code you've shown.
If you want the users to register with your app, that is definitely possible but is separate from their signing in with Firebase Authentication. You'll want to put up a form where you gather the registration information about the user, and then store that in a database of your choice for later look up.

Related

MSAL React not showing roles, but they are in the token

I'm trying to implement App Roles in a single-tenant React + .NET Core app of ours. This app has successfully been authenticating users via MSAL, so this is just an incremental addition.
I have the app roles set up in Azure AD, and I have the Authorize attribute with role restrictions working in the .NET back-end, but for some reason I'm unable to get the roles via the react MSAL library, even though when I manually decode the token I see them in there.
I was referring to this MS sample for my code. In my index.js, I have the following:
export const msalInstance = new PublicClientApplication(msalConfig);
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
msalInstance.setActiveAccount(accounts[0]);
}
Then, in the test page I have, I'm trying to access the roles array in this way (just as a test to print them out):
const TestComponent = () => {
const { instance } = useMsal();
useEffect(() => {
const activeAccount = instance.getActiveAccount();
setTokenRoles(activeAccount?.idTokenClaims?.roles);
// I've also tried:
// setTokenRoles(activeAccount?.idTokenClaims['roles']);
}, [instance]);
return (
<div>
ROLES: {JSON.stringify(tokenRoles)}
</div>
);
};
Unfortunately, tokenRoles is null. When I inspect entire idTokenClaims object, I see all the other claims, but no roles. However, I do see them in the token itself:
{
...
"roles": [
"Packages.Manage"
],
...
}
I'm really hoping to avoid manually decoding the token. There has to be a way to get it out of MSAL.
Jason Nutter's comments provided the answer, and in case this helps others I figured I'd give it a write-up.
Per the MS docs, I put the app roles on the back-end app registration. This is why I am able to have the Authorize(Roles = "Role") attribute work on the back-end. The reason I can see the roles in the access token is that the token is retrieved with the scope for that back-end API. But because I don't have those roles mirrored on the front-end app registration, I don't see anything in the id token.
There would be two options if you wanted to use the Azure app roles:
Mirror the app roles in the front-end app registration. In this way you'd have access to the roles in the id token. This sounds not good because I could foresee a typo or mismatch causing weird issues. I'm sure there might be a way using the Azure API to have a process that would sync the roles, but that's not worth it in my opinion.
Manually decode the access token on the front-end. The cleanest way I could think of to do this would be to create a roles context that would pull an access token, decode it, and store the roles for child components to refer to.
Another alternative would be to manage roles in the app itself. For us, the application in question is single-tenant, so there's not much need to do that. However, we do have a multitenant app we are moving to MSAL, and in that case we will already need to do things like validate that the tenant is authorized, and we will need more granular permissions than what this internal app needs, so we will likely have role system and have the front-end retrieve role and profile data from the back-end upon authentication through MSAL.
EDIT: What I ultimately did...
I did indeed keep the roles in the back-end only, then created a user context object that the front-end would retrieve. This user context includes the app roles, as well as other convenience data points like nickname, and is used by a React context and provider that I wrap my app in.

How to distinguish admin and customer role when create user with createUserWithEmailAndPassword firebase auth in ReactJS

I have two reactjs websites, one for client user and one for admin. I have graphql api for data access. Currently, admin is using JWT and we will change to firebase authentication.
I already implement both login and registration using firebase package.
here is the create user function. So it worked and can login successfully. But my question is that how can I distinguish admin user and customer user. I saw that setCustomUserClaims is only for firebase-admin. May I know how to set the role in firebase and what is the correct way to set?
function register(name, email, password) {
return createUserWithEmailAndPassword(auth, email, password).then((res) => {
const auth = getAuth();
updateProfile(auth.currentUser, {
displayName: name
}).then(() => {
// Profile updated!
// ...
}).catch((error) => {
// An error occurred
// ...
console.log(error.message);
});
});
}
Custom claims are definitely the easiest way to add roles in Firebase Auth but you'll need to use Admin SDK in a Cloud function or any secure server environment.
I saw that setCustomUserClaims is only for firebase-admin
setCustomUserClaims() is used to set the custom claims but you can always read them using getIdTokenResult() function in client SDK.
const { claims } = await getIdTokenResult(auth.currentUser)
So if your GraphQL API runs on your own server you can install Firebase Admin there and add custom claims to Firebase auth users.
Alternatively, you can store user role in a database like Firestore or your own database and read user's role from there. One catch of store roles in a database is that you cannot access them from security rules of other services like Firebase storage if required but custom claims can be.

Msal logout displaying multiple account

I am using Azure AD with React JS. When I am signed in using multiple accounts and call msal logout, then it is showing me an option to select an account that needs to be signed out. I just want to show the logout option for the currently active account, rather than all signed-in users.
I have tried to pass an active account using the below snippet but still, I am getting an option to logout all signed-in accounts. Can you please let me know how can I get an option to logout only active account, rather than all signed-in accounts?
const myMsal = new PublicClientApplication(config);
// you can select which account application should sign out
const logoutRequest = {
account: myMsal.getAccountByHomeId(homeAccountId)
}
myMsal.logoutRedirect(logoutRequest);
https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-spa-sign-in?tabs=javascript2#sign-out-with-a-redirect
You can use Prompt-less Logout:
const currentAccount = msalInstance.getAccountByHomeId(homeAccountId);
// The account's ID Token must contain the login_hint optional claim to avoid the account picker
await msalInstance.logoutRedirect({ account: currentAccount});
You will need to add login_hint claim to token optional claims in your application's Token configuration on Azure Portal:
msal logout it is shows an option to select an account that
needs to be signed out
The logout prompt you're seeing comes from the AAD service, because it needs to know which user to terminate the session for on the authentication server side
Unfortunately, this is a known issue with the AAD service. At this time, there is no way to bypass the logout account selection screen on logout
According to this document : https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/logout.md and code descriptions, MSAL is clear the cache and session data on the client side (browser)
There is github issue you can refer it for more details :
https://github.com/AzureAD/microsoft-authentication-library-for-js/issues/2922

Custom React GUI for oidc-client-js

is there a way to user your custom React GUI with oidc-client-js? I know that if you trigger authentication endpoint using:
// PopUps might be blocked by the user, fallback to redirect
try {
await this.userManager.signinRedirect(this.createArguments(state)); //Shows midleware login form
return this.redirect();
} catch (redirectError) {
console.log("Redirect authentication error: ", redirectError);
return this.error(redirectError);
}
Middleware will try to render its predefined login form:
However I have my own React form and I only need to pass to OICDClient params (email,password) and get back User instance to display UserName etc. Something like:
var loggedUser = await this.userManager.signinCustom(state.loginEmail, state.LoginPassword); //Login using credentials
I don't want to write all the logic by myself I really want to use all functionality from OIDCClient - only with my GUI (loginForm, registerForm, updateUserForm etc).
I'm using scaffolded library from MSDN using command:
dotnet new react -o <output_directory_name> -au Individual
Is there any method/implementation to initialise oidc-client-js from React components and not user default GUI forms?
Thanks a lot!
I might be missing some thing but the whole idea of using a 3rd partly federated auth provider be it your own/your company's SSO (say developed using Identity Server 4) or say Google sign in(say using their Firebase JS kit) or Microsoft sign in, Facebook sign in etc. is that you will be redirected to their authentication endpoint where you then use say your google credentials (if you are using google sign in for example) to sign on to google auth servers. Once you do that then a payload (consisting of an identity token and access token) is returned back to your redirect URL which you must configure for your specific app.
By saying you'd like to provide your own sign-in form you are missing the entire point of using a 3rd party authentication provider. Besides, you/your app shouldn't know about user names and passwords and you don't want to have access to all that information. All that you should be interested in knowing whether the user, who are using one of the federated authentication providers, that you would have configured for your app, are who they claim to be and you then delegate all that heavy lifting to your 3rd party authentication provider.
Besides, say your company has a SSO system of their own then all your company's app will use that SSO system and from a UI perspective you want to show the same login screen so as to give a consistent user experience.
In addition, if you show me a google authentication button and then on clicking that button you show me some weird form that doesn't look like the typical google picklist sign-in form then I'll shut down your app before you can say hello, and, I suspect most user would (and should) do the same. The reason being that when you show me a google sign-in page then I know that you/your app will only get back what you need and I wouldn't ever entrust my google user name and password to any other application.
If you really want to have your own authentication form then you'll have to manage user names and passwords yourself, the way we used to do things probably over 10+ years back.
If you decide to go the route of setting up your own authentication system and then say use identity server 4 then yes you can certainly change the UI and customize it to your heart's content, but that will happen at the server level, not at the level of your react app. Point being that in any SSO system the user will be redirected to the that auth provider's endpoint where they then authenticate (and, optionally, provider permission for your app to use certain claims) and once they do that they they are redirected back to your redirect endpoint with a payload (JWT token).
Lastly, even if you could some how wire up a client side sign in form, I'm not sure you would want to use it. Passing passwords & user names over the wire isn't a good idea. You'll always want to use a server rendered sign in form.

redirection after signin with the use of cognito user groups

I have setup a cognito user pool with amplify and react. I now want to configure the authentication in such a way that after signin the users are redirected to pages depending on which group they are in meaning if someone from the group "admin" signsin he will be directed to a different page than someone from the group "user". Help would be very much appreciated.
Thanks alot.
Once you get the user accessToken after logging in via Amplify Auth, you will be able to get the groups user is assigned to via accessToken.payload["cognito:groups"].
You can also get the user session via const session = await Auth.currentSession();, inside you will find the accessToken.
Based on that you will be able to redirect wherever you need.

Resources