Creating user with no password in Meteor - authentication

I have a unique user creation flow which is as follows:
User comes to my site for the first time and they click a button.
I create a User in the DB for them and set a localStorage key with the UID.
Use goes about creating data and I save the data in the DB and associate it with the UID.
User comes back, and if they have UID set in localStorage, I show them the data they previously created.
User can click Register to create a "real" account from which point they will have to login with username and password or another service (e.g. Facebook).
So, how would I accomplish this with Meteor Accounts and the User model?
In a nutshell:
I need to create User mongo document with no information (about the user).
I need to authenticate a user by just having a UID (acting as a "password").

Register onCreateUser to add an "anonymous" field ({anonymous:1})
when a random password is used, maybe generated with Meteor.uuid().
Add a timestamp field
({created:new Date()}) to clean out old, anonymous accounts.
Perform old anonymous user maintenance, like deleting anonymous users more
than one hour old:
Meteor.autorun(function()
{Meteor.users.find({anonymous:1,$where:"new Date() - this.created >
360000"}).forEach(function (user) {
Meteor.users.remove({_id:user._id})}});
On the client:
Always prompt
for a "nickname." This will become the official username, or will
sit in the system forever used.
Check if client is logged in. If
not, create a user with nickname and a "magic number" password,
which logs you in. When they click register, write "Register" at the
top, but actually just change their password and $set:{anonymous:0}
Don't use localStorage, and don't use UIDs. The session cookie IS your UID.

I don't know how to help with the authentication, but as for creating a blank User object, I've successfully done the following on the server-side (with a different name...):
Meteor.users.insert({profile: {name: 'Oompa Loompa'}, foo: 'bar'});

Related

Authentication using oauth2

I am trying to create web-forum with user authentication, using Github and Google. I've already managed to get user information with access token, like login, email and etc. But I don't get the workflow for authenticating this user in my database.
In order for user to register, he need to provide email, login and password. All the examples and tutorials I saw, was stopping at the sessions and that's it.
My website has database with posts and comments, and to fetch, for example, user's created posts, I need to get the user id, then I will lookup in the database. I thought, maybe, I can use access token as a password, since it's unique, but it always changes and has an expiration date. Then I thought, to left the password input empty and register user without it, but I think, that's not very secure. How should I do it?

How do you store user information in firestore if they don't have an account?

I am trying to create an app using firebase auth and firestore where new users can be invited via email to work on a project. The problem is, I do not know the best way to store the temporary user project permissions before they have a uid. I want the user that got invited via email to get access to the project upon opening the link sent to them.
I had tried two different ways
Having a sub collection doc for every user in the project
/project/{projectId}/users/{userId}
When a new user is invited, the userId was set to their email, having a cloud function that triggered when a new user was created to send the invite email to the user. Once the user opened the link, it deleted their user document and a cloud function ran that created a new doc with the users id now that they had once since they were authenticated.
This worked, but left a 10 second period where the user can't interact with the project because the cloud function for making the new user doc is running. Also it just seemed like a bad way to do it.
Having a single document with all of the user information
/project/{projectId}/users/users
users:{
roles: {
users_id: 'admin',
new_user_email: 'admin',
}
}
This one I was not able to get to work as firestore does not let you create a key with a period in it, but if there was a way around this, it would work as well. I had also set up firestore security rules which made it so they could only edit fields where the key was there uid or their email if they were not an editor/admin.
Consider creating an anonymous account in Firebase Authentication first, which requires no input from the user. It will receive a UID that you can use to store data for that account. Then, you can convert that account to a normal account after the signup or login succeeds.
Since you didn't say which mobile platform you're using, I linked you to the web docs, but the procedure is generally the same for each one.

How to handle logged in state of user authenticated via 3rd party OAuth1.0a?

I am building a website using Node.JS/Express.JS that will allow a user to log in using a 3rd party provider (Discogs via OAuth1.0a).
I have successfully implemented the authentication process so that a user grants access to their Discogs account and I am returned an Access Token for future API calls. The Access Token does not expire. The user is classed by Discogs as an "authenticated application".
At the moment I am storing the Access Token in a session, which persists even when the user restarts the browser, or my server is restarted, so the user stays logged in. Great.
However, when I log the user out by destroying their session and they repeat the authentication process, the 3rd party provider treats the user as a newly authorised application, leaving the old authorised app behind. How can I get around this? Is it better to not destroy the user's session on log out and instead store the logged in state of the user? Discogs do not provide a method for de-authentication.
Also, there is some config to be set against a user once they are logged in. Should I created a dedicated DB table or equivalent for this, or would storing this in the session suffice? It seems like a dedicated user table may be superfluous as I am relying on the user's session id to identify them.
Generally, you will probably want to save some info about your users permanently on your own servers, so probably in a database.
In your specific case, that database should probably save some kind of unique user ID that you get from Discogs (do not save the access token itself for security reasons), which you can use on subsequent logins to identify which access tokens belong to the same user.
Your flow would probably be something like this:
User logs in via Discogs for the first time, you get an access token, put that in session
You figure out a unique user id somehow, you save that to your DB along with any other user info you might need
You put that ID in the session as well
User logs out, you destroy the session, but keep the info in your DB
User logs in via Discogs again, you get a different access token, put that in session
You figure out the unique user id, which matches the ID in your DB, so you write that ID into your session - now you can treat the user as the same user, just with a different access token
The unique user ID can be anything that is, you guessed it, unique. Might be an actual ID, a username or email address - I'm not familiar with Discogs but I'm sure you can figure something out and how to obtain it.

How to implement "remember me" using ServiceStack authentication

I am trying to implement a Remember me feature in a ServiceStack-based project. I don't want to use Basic Authentication because it requires storing password in clear text in a browser cookie, so I need to come up with an alternative approach that will be easy to maintain and customized to my existing database.
I understand that ServiceStack's own support for Remember me is based on caching the IAuthSession instance in the server-side cache, which by default is an in-memory data structure that is wiped out when the website restarts (not good). Alternatively, the cache can also be based on Redis or Memcached, which is better (cached data survives website restarts) but adds more moving parts to the picture than I care to add to it.
Instead, I would like to implement the this functionality using my own database:
Table Users:
UserID (auto-incremented identity)
Username
Password
Email
Name
etc...
Table Sessions:
SessionID (auto-incremented identity)
UserID (FK to Users)
StartDateTime
EndDateTime
SessionKey (GUID)
The way I see things working is this:
On login request, AuthService creates an empty instance of my UserAuthSession class (implements IAuthSession) and calls my custom credentials provider's TryAuthenticate method, which authenticates the user against the Users table, populates UserAuthSession with relevant user data and inserts a new record into the Session table.
Then the auth session is cached in the in-memory cache and ServiceStack session cookies (ss-id and ss-pid) are created and sent to the browser.
If the user checks Remember me then additionally my custom credential provider's OnAuthenticate method creates a permanent login cookie that contains the user's username and the auto-generated Sessions.SessionKey. This cookie will help us track the user on subsequent visits even if the auth session is no longer in the cache.
Now, suppose the site has been restarted, the cache is gone, so when our user returns to the site his auth session is nowhere to be found. The current logic in AuthenticateAttribute redirects the user back to the login screen, but instead I want to change the flow so as to to try to identify the user based on my custom login cookie, i.e.:
look up the latest Sessions record for the username extracted from the login cookie
check if its SessionKey matches the key in the login cookie
if they match, then:
read the user's data from the Users table
create my custom auth session instance, fill it with user data and cache it (just like at initial login)
insert a new Sessions record with a new SessionKey value
send back to the browser a new login cookie to be used next time
if the keys don't match then send the user back to the login screen.
Does the above logic make sense?
Has anyone already implemented anything similar using ServiceStack?
If I were to proceed with this approach, what is the best course of action that doesn't involve creating my own custom version of AuthenticateAttribute? I.e. which hooks can I use to build this using the existing ServiceStack code?
This is already built for you! Just use the OrmLiteCacheClient.
In your AppHost.Configure() method, add this:
var dbCacheClient = new OrmLiteCacheClient {
DbFactory = container.Resolve<IDbConnectionFactory>()
};
dbCacheClient.InitSchema();
container.Register<ICacheClient>(dbCacheClient);
I am not sure when this particular feature was added, perhaps it wasn't available when you originally asked. It's available in v4.0.31 at least.

External Login Account vs. Native Login Account

I am brand new to Visual Studio 2012 and MVC 4, and I've been working with the SimpleMembershipProvider via the WebMatrix.WebData library.
I'd like to integrate Facebook as an external login source down the road, but it's not a requirement as of right now. However, to get a decent feel for what it would take, I've been following the tutorial and guide found here - http://www.asp.net/mvc/tutorials/mvc-4/using-oauth-providers-with-mvc.
My question :
If a user has already been created using :
WebSecurity.CreateUserAndAccount(model.Email, model.Password);
WebSecurity.Login(model.Email, model.Password);
Can they be "upgraded" to an oAuthMemebership account in the future, if they choose to use their Facebook credentials instead of the email and password they created when first signing up?
I couldn't find a clear answer to this question in the guide, or elsewhere, so I'm hoping someone can clarify how that process may work.
The SimpleMembership setup allows for a local and multiple OAuth logins all sharing the same UserProfile - so a single user can login with either a local password, or FacebOogLiveWitter.
(I should state, that I'm assuming in this answer that the OAuth provider does not send back a matching piece of information for a local account. If they do then the principles of actually performing the merge are the same, but the complexity and steps are vastly reduced.)
The OAuth registration process will refuse the user if they use an existing user name, rather than try and merge two accounts. Therefore this isn't simple, you'll have to build the functionality yourself. The process is complex as there are many directions the user can approach this from (so you could simplify by only supporting one or two), and you need to enforce security as well in case someone tries to merge into an account they don't own.
I will assume you are comfortable with the link you've posted, and you've followed the Facebook help at (for example) Facebook Login and The Login Flow for Web (without JavaScript SDK) so you have a working test application.
Your general process has to have multiple user journey approaches to make sense to a user:
for a logged in user (with a local account)
let them login to facebook and associate the accounts
let them merge an existing account on your site which uses a facebook login
for a logged-in user (with a facebook account)
let them create a local account
let them merge an existing local account on your site
for a non logged in user who tries to register a local account
let them merge this new account with a facebook login that is already registered, and do that as part of the registration process
for a non logged in user who tries to register (or log in for the first time with) a facebook account
let them link this with an existing local account as part of the registration process
etc.
ASK PERMISSION
(You can skip this if the OAuth provider has sent back a matching identifying piece of information, such as an email address).
You should enforce confirmation security, usually through email confirmation sent to the target account of the merge. Otherwise:
someone can login to your site with facebook for the first time
during that process say they "own" the email address or username of a local account (remember, facebook won't necessarily confirm what their email is for you)
and therefore gain access to the existing local account
So, once the merge "request" is made, you need to ask for permission to proceed from the target account of the merge.
The MVC 4 AccountController
I will use Facebook as our OAuth example. To compare what happens when you register a user on your local authentication framework vs. OAuth:
Local: creates an entry in webpages_Membership and an entry with the same UserId in UserProfile (assuming you are using the default tables for the MVC 4 application template)
OAuth: creates an entry in webpages_OAuthMembership and an entry with the same UserId in UserProfile
Now let's look at what happens when a user signs in using Facebook for the first time:
They click on Login using Facebook (or whatever your button says)
they get taken to facebook to login
they succeed (let's assume that, and ignore the failure case)
they then get sent, invisibly to them, to /Account/ExternalLoginCallback
OAuthWebSecurity.SerializeProviderUserId is called, passing the OAuth details to that Action
They get redirected to /Account/ExternalLoginConfirmation and asked to provide a username for their new presence on your site
If that user name is available then UserProfile and webpages_OAuthMembership entries are created
This process is your chance to "join" the accounts by matching some unique piece of information. As long as you end up with the same UserId in UserProfile, webpages_Membership and webpages_OAuthMembership you should be ok. So we have to intercept the process at the point of /Account/ExternalLoginConfirmation.
If the OAuth provider has sent back a matching identifying piece of information, such as an email address, this becomes simple, test for this in the ExternalLoginConfirmation action, and auto-merge using a similar process to the one outlined below.
However, I think you can't/shouldn't assume that the user uses the same email address for your site and OAuth, (nor should you for many reasons). Also, probably in the T&Cs for something like FacebOogLiveWitter it stops you asking for the email of their account anyway, and if they don't currently they might in future.
So instead, you could link the accounts based on alternatives, like username or email address, or phone number. Either way you are going to need them to input some identifying piece of information that is unique against an account, and will pull back the target account.
Wrapping up
So to put this all together: In the first part of this answer I outlined how you will need to consider multiple user journeys to merge accounts. I will use the example 4.1.
Your process will need to:
(Assumption - when a user first registers with a local account, you ask them for an email address and validate it or assume it is valid)
Let the user login with facebook for the first time
at Account/ExternalLoginConfirmation ask them if they want to
Create a new account with you
Use their facebook login to access an existing account
Assuming the latter, then you log a request in a new table (maybe "MergeAccountRequests") with:
The facebook account UserId
The target merge local account UserId
An authorisation code to use in the email you need to send
(From this point on, if they login without confirming that merge, they will have to get sent to a page to ask them to confirm, rather than create objects in other db tables which you have to worry about later)
You then send an email to the address of the target merge (local) account asking for permission to complete the merge (a standard confirmation email, with a link)
When they click on that link, or enter the code you sent them (you could use SMS as well as email) then you need to merge the two accounts
Choose the "new" and "target accounts (in this case "new" is the facebook account as you don't have data associated with it yet)
Delete the UserProfile of the "new" account
Change the UserId of the "new" account webpages_OAuthMembership table to the same as the "target" account
Log the user out (so there are no complications depending on which account they are currently logged in with)
Display a message to the user telling them the merge is almost complete and that they can now log in with either account to confirm and complete the merge
Rather than send them to a login page, i would give them the login options alongside the confirmation message.