Meteor User Account Settings email validation - meteor

I am using Meteor user accounts api to create user accounts.
https://github.com/meteor-useraccounts/core/blob/master/Guide.md
How to add email restriction to particular domain such as only #mydomain.org so that only those users with the domain will be allowed to log into the system while other users with other domains such as #gmail.com would not be able to log into the system?

There is this (unfortunately) undocumented Accounts.config which is part of accounts-base. It allows you to set a email domain restriction for accounts creation. This your app won't allow any accounts to be created that are not part of this domain:
Put the following in server and client startup code to configure the accounts package:
Accounts.config({
restrictCreationByEmailDomain: 'mydomain.com'
})
The source documentation says on this particular option
#param {String | Function} options.restrictCreationByEmailDomain If set to a string, only allows new users if the domain part of their email address matches the string. If set to a function, only allows new users if the function returns true. The function is passed the full email address of the proposed new user. Works with password-based sign-in and external services that expose email addresses (Google, Facebook, GitHub). All existing users still can log in after enabling this option. Example: Accounts.config({ restrictCreationByEmailDomain: 'school.edu' }).
Source code of the Account.config method: https://github.com/meteor/meteor/blob/devel/packages/accounts-base/accounts_common.js#L170

I would recommend using accounts-password package to manage user creation and authentication.
With Accounts.createUser method you can easily create an user where you can apply any kind of check. In your case add a regex check to make sure the email address comes from your domain before calling the Account.createUser method.

Related

Firebase subaccounts

I'm currently building a POS/Store admin app, when a user gets into my app, the Owner of the store will then be asked to login only once for setup purpose (e.g. a new machine), the app will then display a list of staffsName that has already been added by this owner, and then everytime a staff wants to start a new transaction, he/she will only need to click on his/her name, then enter his/her 4-digit pincode to 'login' and process the transaction.
How do i go about achieving this?
I was thinking of using firebase auth for the 'login' of the staff, but then when i log in using the staff credential, I will lose access to the uid of the owner, which is needed to access the owner's store data such as his/her products.
i'm also thinking of using firestore to store the 4digit pincode, but then i'm also concerned about security
There are multiple ways you can approach this, one where you utilize the email login by simply appending a fake domain to the username to create a valid email domain. This user account could be the designated 'user' in question, or utilize credentials inside custom claims or hidden in a database that allows the client or server (depending on your preference) to then log in as the user.
Moreover if you want the manager to login once you can add Authentication State Persistence to specify whether a signed in user should be indefinitely persisted until explicit sing out, page reload etc.
Another approach requires the user also to have a valid auth that is not an email password and you link your pin auth to that main account with Firebase Auth Linking per the documentation: https://firebase.google.com/docs/auth/web/account-linking.
This does however require that the user be registered from an auth provider such as Google, Twitter, Apple, etc. then the user will have to activate this link by logging in for authentication purposes. This can in theory be automatically generated and processed without the user knowing.
It is a long way around it since this is essentially a custom solution but it does create the flow you are looking for without having to use a custom auth provider.

How do I allow a role insert into a table (for signup), but after that deny further inserts for that user?

That's my question. I am using Hasura, and defining 'user' permissions.
Users are of course allowed to modify their own information, and not allowed to insert new records into my users table.
But when they signup, they should be allowed to insert themselves. So how can I define this permission?
To make my scenario more clear:
I have a React app, that uses an external OpenID provider. So a new user signs up there, and the provider returns a JWT to my app, containing a user I've never seen before.
My app does not know that, it just uses the access token to send to the Hasura backend to retrieve further info about this user, using the 'user' role. But it uses a query which will automatically insert the user if not found.
There's really not a safe way to allow sign-ups without involving a backend service. It is a very bad idea to allow anonymous inserts into your user table, even if you added a unique constraint against a user ID or email address.
If you have the option of using NextJS, see the Hasura example for configuring NextAuth. This works by configuring your app with a protected API route that uses your Hasura app's ADMIN_SECRET to insert new users who have authenticated with a third-party.
If NextJS isn't an option, Hasura's Auth0 example similarly uses a callback method to insert an authenticated user if they don't exist.
In the user table, for the user role, you need to add a permission with custom check. And the check should be user_id equals x-hasura-user-id.
{"id":{"_eq":"x-hasura-user-id"}}
For non-logged-in users, leverage the anonymous role by setting the permissions that make sense for your use case: https://hasura.io/docs/1.0/graphql/manual/auth/authorization/common-roles-auth-examples.html#anonymous-not-logged-in-users
Edit after the comment:
Ah, I see. When the user comes to your app, your app goes and retrieves some data that it expects every user should have (for example perhaps the user info store on the user table). But since it's a new user, this info is not there.
At this point, your React app knows that:
there's someone with a legitimately signed JWT cookie (use a library to verify the signature) and
there's no user info from the backend. Therefore, the React app shows
a "Welcome new user, wait while we're setting up your account".
Then
the React app makes a mutation to a signup Hasura action you'll
prepare. Once that returns, you proceed as usually (redirect the user to their home page).
use hasura action handler instead. Inside your handler, do a check if the user already exists or not. If not then insert a new row.

Login with Email/Password without enabling it

My current registration process looks like this:
App sends a registration request via my REST Api to my backend with information like username, password, email etc.
My backend checks if the username is available. If it is, it creates a new user with the admin api. If this is successful as well it saves the username to the realtime db.
When I want to log in with loginWithEmailAndPassword it says that I can't because PasswordLogin is disabled.
Since I don't want anybody to just register with registerWithEmailAndPassword I want to keep it disabled.
My question now is, how can I log a user in without enabling Email/Password?
Or would there even be a possibility to exploit the system when I enable Email/Password?
EDIT: What I'm not sure about is if registrations with registerWithEmailAndPassword are guaranteed to be from my app?
firebaser here
There is no way to sign the user in to a disabled provider. I'm actually quite surprised that you can register them.
There is no way to prevent users from registering after you enable the provider.
But it's quite easy to only allow users that your administrative back-end created access to certain data. Just make the admin script write the UID of users it creates to a whitelist:
/whitelist
uid1: true
uid2: true
And then in your security rules only allow access on whitelisted users:
".read": "root.child('whitelist').child(auth.uid).exists()"

Limit Meteor.js built-in Google authentication to a domain

I'd like to use the Meteor.loginWithGoogle() tool to authenticate users, but is there any way to limit it to a specific (Google Apps) domain?
I could check after the user is authenticated using the returned email, but is there a way to do this at the login stage with some parameter for Google login?
I dont think its possible right now.
There is a pull resquest to partly add that functionality: https://github.com/meteor/meteor/pull/1332
The issue with that pull request seems to be that it only fixes the client side of thinges (ie. it only shows accounts from the selected domain when the user logs in).
But it does not add any server side checks.
Im using the following workaround:
In a .js file in the sever folder I have the following code:
Accounts.validateNewUser(function (user) {
if(user.services.google.email.match(/example\.org$/)) {
return true;
}
throw new Meteor.Error(403, "You must sign in using a example.org account");
});
This prevents accounts from being made for domains different from example.org.
If you want to only allow certain users from your domain, you could also add a whitelist collection that defines user ids from your Google Apps account. This way you can restrict access to only certain users, get single sign-on functionality, and can pre-set user roles and properties for your app before users even create their accounts.
Use the Accounts.onCreateUser(function(options, user){}) callback for that since it allows you to define additional user properties.

Transparent user registration after external authentication in Drupal

I'm working on a Drupal 6 module to provide OAuth-based user authentication and registration. I'm already using the OAuth module to authenticate as described on http://oauth.net/core/1.0a/#anchor9. The next step is to create the user account using information provided after authentication using an custom API of the Service Provider.
According to http://drupal.org/node/497612#comment-3047302, I should not use user_external_login_register() but see the OpenID module for how to properly login an external user.
After studying the OpenID module, here is what I plan to do:
Try to load an existing user for a authname build from the custom API result using user_external_load().
If a user exists, use user_external_login() to log the user in.
If not, pretend the registration form has been submitted (like openid_authentication() does) to create a new user account. And redirect to a pre-filled form if any additional information is needed in order for the user to register.
Is this the right way to do it ? Is there another module worth looking at for how to this properly in addition to OpenID ?
You could have a look at the former Drupal module. That module did two entirely different things (hooray for the architecture :)).
* It puplished information to a central "who runs Drupal" directory. (and offered a page to show such a directory yourself!)
* It allowed login with credentials from other Drupal-sites.
The latter is what you are looking for. Note that the module was discontinued, not because the method for logging in was done wrong, but because the DrupalID mechanism itself is flawed. It has been replaced with openID and oauth.
http://drupalcode.org/viewvc/drupal/drupal/modules/drupal/drupal.module?hideattic=0&view=markup
The hooks and methods you would be looking for (in that order) are:
drupal_form_alter -- Adds validate-callback to the login forms.
drupal_form_user_login_alter -- Adds information about alternative login on login form.
drupal_distributed_validate -- Validation callback: calls drupal_auth to see if the user is valid. If so, calls user_external_login_register
drupal_auth -- Helper for validation callback: determines if the credentials are valid.
All other functions are either helper functions for these, or provide that directory-feature, or allow remote sites to authenticate against our database. Neither of which you will be using.

Resources