How to restrict user action from email link without login? - ruby-on-rails

As part of my app, users get to approve certain "requests" via email. Requests have their own model and therefore each has a unique id.
Users get an email with a named route in a link: 'approve/:id' where :id is the id of the request. The approve method then handles the approval logic, etc.
How can I prevent a user from approving requests made to other users without having the user login beforehand? Since the ids are freely displayed in the URL, I guess a GUID would be needed or?

If you really want to do that, then yes, you'd need a GUID of some sort. Perhaps a cryptographic hash of the user_id or email address(?). so you end up using /approve/:id/:GUID.
I'm surprised you don't want the user to login though, remember that if they login you can redirect them on to the approval automatically. Also if the cookie is still valid a user may already be logged in.

Related

Rails app Query params and Cookie based login

I am trying to find a way to distribute a Ruby on Rails app selectively by sending them an email with the link that logs them in. This should be the only way to get to the page hosted at a unique subdomain. Additionally, we don't plan on having a login wall so the access would need to be guarded by using Cookies or the Query URL params.
A couple of questions regarding this:
Is it possible to leverage cookies exclusively to achieve this? I.e Any way to embed cookies within the URL sent in the email itself?
An approach I felt that might work is to embed the user ID (encrypted) in the URL in the email. In order for the users to not need to bookmark this URL or go back to the email to access this link, I was planning to store their session ID via a browser cookie. Any issues with this approach?
How to avoid wandering users(i.e users who haven't received this email) to access this page (i.e a nice way to raise a 404 error)?
Any other cleaner ways to accomplish this task?
Is it possible to leverage cookies exclusively to achieve this? I.e
Any way to embed cookies within the URL sent in the email itself?
No. You cannot "embed cookes in a URL". Cookies are set via the SET-COOKIE header in a response or through JavaScript.
An approach I felt that might work is to embed the user ID (encrypted)
in the URL in the email. In order for the users to not need to
bookmark this URL or go back to the email to access this link, I was
planning to store their session ID via a browser cookie. Any issues
with this approach?
Yes. You should generate a random token thats not tied the users id.
How to avoid wandering users(i.e users who haven't received this
email) to access this page (i.e a nice way to raise a 404 error)?
Create time limited access tokens that can only be used once by the user. There really is no other way for you to actually know that the person requesting the URL is the recipient of the email.
What you are describing can be accomplished with Devise Invitable which is a pretty good community tested point of reference if you want to reinvent the wheel.
When you invite a user Invitable creates invitation tokens which are stored in the users table. This is just a random string. There are also timestamp columns that expire invitations automatically.
The token is included in the URL in the invitation email as a query parameters.
When the user clicks the link the controller looks up the user based on the token and nulls users.invitation_token so that it cannot be used again. This stores the user id in the session and takes the user to a screen where they edit and finalize their account by setting a password.

OAuth combined with custom users

I have a website where users can create an account and log in. This is stored in a database on the server. I also want users to be able to log in with Facebook etc, and thus skip the account creation. I don't know how to combine this and keep it persistent in the database. Any good examples on this use case?
Let's first see how logins work in general. When a user is logging in for the first time, a session id is generated for the user and is stored in the browser of the user as a cookie (note that there are mechanisms to store session id without a cookie, but let's assume you require a cookie for simplicity).
For subsequent requests to other pages in the same website, the cookie is also sent along. With this cookie (which has the session id), the unique user can be identified.
So, all that you require to know to identify a user in the server side (upon a web request) is the session id.
Having said that, if you want to include facebook etc into the login mechanisms, you need to do two things:
Connect your website with facebook (you will require a facebook developer account and some keys. Look here). When you do this successfully, if the user selects facebook login, your website should redirect to facebook login page and once the user logs in into facebook account, facebook will redirect back to your website with a token. This token is an indication that the user is a 'real' user. If required, you can use the token to get more details (such as facebook id, email address, name, etc.) from APIs facebook.
The second step is the same for any authentication flow. You need to generate a session id for use by your server and then save the session id in cookie.
What I have specified is the general flow on how your requirement could be achieved. The mechanics of how to do this will depend on the server side technology that you are adopting (such as ASP.NET, Ruby, etc.)
Additionally, if your website requires storing information about the user behavior / user activity, you may need to additionally check if the user logged in via FB already exists in your database. If not present, you can store the user's facebook id or something to uniquely identify the user later. With this as the primary key / user id, you can store user activity (such as inserting a record in orders table if the user purchases a product).

Using OAuth but store extra information in my own DB

I've been looking into OAuth for a while, but haven't implemented it in any of my applications yet. I'm having trouble really understanding the full concept, so I still have a few questions that I haven't found an answer to, so I hope that anyone can help me.
I want a user to be able to start my application (WP8), login to facebook / twitter / microsoft / ... .
When he gets authenticated, I want to actually save this user to my own DB so I can add some user specific stuff like preferences, posts, ... .
What do I need to save in my own DB to specify a user?
Do I need to save the token itself or is this something that will be invalidated after a while? Or do I need to specify the user's name? With other words: What can I use as a unique identifier?
And what happens when a user would authenticate with for example facebook and he deletes his account?
And one more question, would you ever allow a user to connect to an application with 2 different service providers? If so, how would you make the coupling of these 2 providers to 1 user in your own DB?
I hope my questions are clear enough!
If not, don't hesitate to ask for more information!
Kind regards,
Gert
I assume that you have your own back-end where you authenticate your own users and your WP8 application is just a client.
First, let me distinguish between a user credential and a user profile. User credential is something that validates who the user is, e.g. username/password, facebook user id supplied with a valid auth token. User profile, is what you store in your own database about the user.
You also need to distinguish between a token you use to authenticate the user and the AccessToken Facebook needs to grant you access to user's data.
So... to answer your questions:
What do I need to save in my own DB to specify a user?
Create a record with user data (like preferences, and your unique user ID), and user's login method (e.g. Facebook) and credential (e.g. Facebook's user ID). This is your user's profile.
Do I need to save the token itself or is this something that will be invalidated after a while?
You can also store the Facebook AccessToken here if you've been granted "offline access" privileges by Facebook, but that is used for Facebook's access by you... not by the user's access to your app/back-end. For user's access you could just use a mechanism similar to cookie-based authentication - it's up to you. You could use the AccessToken as a kind of a "cookie", but you would need to always check against Facebook that it's valid.
With other words: What can I use as a unique identifier?
You could treat Facebook's ID as unique (so long as you never allow another account in your user profile DB to link with the same Facebook account)
And what happens when a user would authenticate with for example facebook and he deletes his account?
It's a good idea to have users still create a username/password combination that works with you site and only rely on Facebook login for convenience. In any case, Facebook provides a "Deauthorize Callback URL" when you create an app profile on Facebook. This is called when a user deactivates your app or deletes an account with Facebook. When you receive this call, you could send your user an email when an auth link to setup a different credential so as to not lose access.
would you ever allow a user to connect to an application with 2 different service providers? If so, how would you make the coupling of these 2 providers to 1 user in your own DB?
Sure, you could do that. Say you'd want to allow a Twitter account as well. You'd need to add a Twitter user ID field to your user profile database.
Here's another tip: create an ASP.NET MVC4 project in Visual Studio - the template includes an example of how to set up a user profile database with OAuth login.
Hope it gives you the high-level overview to investigate further.

Email based interaction with rails app

I need some gem that will allow users to interact with rails app through email, without need to register. For example: I publish something for sale, accompanied with email, and all of controls (CRUD, and submitting) I get on my email as links (delete, update, and so on). I'll like to, somehow connect it to devise, with opportunity of further registration using the same email with shopping history.
To publish something(services or products) for sale User has to fill:
name, email (validates unique), phone. That may or may not be used for future registration using devise.
in the same form may be: pictures, description, and other fields of product.........
the idea is to store: id, name, email, phone in user db without password, or be somehow pending for registration
Just create your own CRUD controller with authorization based on some hash that you will add to the URL. Store those hashes in the database and verify if user is legitimate to perform action.
Warning: anyone with the valid URL will be able to perform these actions.
Well, in comment you wrote that you want it to integrate with Devise. Devise supports login tokens but for existing users. You should then somehow virtually register them. Easiest approach would be to:
Include user email in the URL with some tolen
Check if we already have such user - add token verification here
user = User.find_by_email(params[:email])
if user.nil?
user = User.create(field_1: value1, field_2: value2)
end
sign_in(user)
redirect_to after_sign_in_path(user)
Done. User is authenticated based on the email and token included in the URL.

Authlogic: how to log in a user behind the scenes without knowing their password

I use Authlogic to handle login/authentication/sessions etc and I'm using paypal to handle my payment for subscription to my site. For users whose trial has expired, i'd like to log them in automatically after they go through the paypal payment process, but i can't work out how to do this without a password. My flow is thus:
expired user logs in
their trial has expired, so i push them to the subscribe page, keeping track of who they are via their unique persistence_token field, which i put in a param which gets sent on to paypal.
when i get the payment notification from paypal, i get their token as well, so i know which user has paid, and i amend their account accordingly.
when they have paid in paypal, the button to send them back to my site has the unique token of their order, so i can tell that it is the person who has just paid that is going to that 'subscription complete' page rather than anyone just typing in the url to their browser.
when they return from paypal to the site, they are still logged out, and they have to go through the login/registration process.
In the above situation, because i get the order token in the params to my 'subscription_complete' page, i know that the user is the same one who has just paid, and so i have enough information to trust them, as if they had logged in. So, i would like to log them in automatically, ie create a UserSession record for them. But, the problem is that i don't know their password (because passwords are 1-way encrypted), and i need the passsword to create the user_session.
So, my question is: if i trust the current user, but don't know their password, can i still log them in anyway? If so, how?
I've used UserSession.create(#user) before. Doesn't this work for you?

Resources