OAuth callback URL parameters with Doorkeeper - ruby-on-rails

I'm Using OAuth2 with Doorkeeper to protect my API.
The problem is that one client had several different flows in which he redirects users to my OAuth flow.
He would like to dynamically add some parameters when redirecting the user to my OAuth flow and get these parameters back when I'm calling his callback URL. This way he will be able to tell from which flow this callback originated.
Is this possible with OAuth 2? with Doorkeeper? How?
Edit:
Thanks Zólyomi István for your hint.
I set the state parameter before calling the auth endpoint and got it back in the callback. However, I found that I get back a state parameter with some apparently random string even if I don't set anything. Any idea what it is? I'd like to be sure I'm not messing up anything...

Well, using the state parameter was indeed the solution. Just adding state to the request and then getting it back when the control is returned to my code.
According to the specification:
The state parameter is used to link requests and callbacks to prevent
CSRF attacks where an attacker authorizes access to his own resources
and then tricks a users into following a edirect with the attacker's
token.
Apparently ominauth oauth 2 assigns random value to this parameter unless it's used in order to detect CSRF attacks.

Related

OAuth 2.0 State Parameter

I am working with the eBay API using OAuth on my current Meteor project app.
There is a section of the app where I can create an eBay account profile, and assign custom values to the account (such as nick-naming it, etc.). This is where I initiate the OAuth sign-in redirect process.
My question is about the 'state' parameter in the token requests. I understand that it is for helping prevent CSRF, but do I HAVE to use it that way? 'state' does seem to be optional after all.
Let's say I wanted to pass another value into the request call such as the string 'eBay Seller', and expect that the same exact string be returned in the response. I want to use that value to help my app determine which account to assign the returned tokens to (based on which account profile initiated the redirect link).
Is 'state' a valid place to pass in a variable that I expect to be returned exactly as sent? I considered using Session variables to handle this scenario, but quickly realized that this would not work, since the OAuth process takes me outside of my project's domain.
Does OAuth support passing variables that are expected to be returned as sent? Is sending my variable as 'state' allowed or even recommended (or absolutely not recommended?) Is there a better way to achieve what I want to do that does not involve updating database values?
Thank you!
You can send what you want as state. You should try to make sure it's not guessable though, to mitigate against CSRF attacks.
If you want to return useful information like 'ebay seller' then include something for CSRF (e.g. hash of the session key id) and the text 'ebay seller' and delimit them e.g.
2CF24DBA5FB0A30E26E83B2AC5B9E29E1B161E5C1FA7425E73043362938B9824|ebay seller
Now you have the best of both worlds: useful state info + CSRF protection.
Your redirect endpoint logic can check the hash of the session id matches and also confirm the account type from the initial request.

Returning a refresh token with the resource owner flow

I have created an authentication server that implements OAuth 2 for authorization and it also provides local password authentication using the resource owner flow.
At the moment I always return a refresh token along with the access token which was an acceptable thing to do when I first implemented the feature. However now I need to implement a remember me feature in the client that uses the server. I could always just save the refresh token in the client when the user ticks the remember me checkbox but the token would still exist on the server and be usable even though the user didn't want it to.
What I want to do is simply pass a parameter along with the request that tells me whether I should create a refresh token or not.
So my question is. Is there some standard or recommended way of doing this using the fields provided in the spec or is it acceptable to simply add a parameter to the request to handle this use case?
AFAIK, there is no standardized way to choose whether to issue a refresh token or not.

VK Oauth: Security Error

I'm trying to authorize my standalone application. But after I click "Allow" it always redirects to http://oauth.vk.com/error?err=2 and gives this as response body:
{"error":"invalid_request", "error_description":"Security Error"}
Here's the request URL (I do have correct client_id):
https://oauth.vk.com/authorize?client_id=...&scope=messages,offline&redirect_uri=https://oauth.vk.com/blank.html&display=page&v=5.37&response_type=token
It seems that I've tried everything:
Turning application on and off
Passing scope as bit mask
URI encoding some parameters to have correct URL
and so on
After hour of searches I've found this.
So, it means that user has an old session and must re-login in browser.
Space in state parameter causes this.
OAuth 2 RFC, sections 4.1.1 on authorization request and 4.1.2 on authorization response, recommends using state parameter to maintain state in authorization code flow, particularly to prevent CSRF.
When I set this field to CSRFTOKEN123 http://my.site/next/url, I got this error. Replacing (space) with : to get CSRFTOKEN123:http://my.site/next/url helps.
By the way, I couldn't find any mention of state parameter on VK documentation website but VK OAuth 2 authorization system actually supports it. It couldn't be called OAuth 2 otherwise. So I find it legit to use state parameter.
The topic https://vk.com/topic-17680044_30635058 mentioned by author is closed now, current discussion is https://vk.com/topic-1_24428376. There are number of questions on this. All in Russian.

Get around CSFR token for iOS app

I am developing an iOS app for a RoR api (my co-worker made it). I am trying to develop the login portion, but while testing the api in POSTMan, I noticed it requires a CSRF token. Is there a way to get around doing an api call to get the CSRF?
Side note: I am using AFNetworking 2.0
There are a couple things you can do:
You can launch a GET request before you do the post, and retrieve the sessions CSRF token. Then submit the POST form with an authenticity_token parameter as the proper CSRF token. You can embed the original token anywhere in the view with the rails helper form_authenticity_token, or just get it from the sign up form's hidden tag. (This is my favorite option)
You can make a secondary loggin-in action on your site that is actually a GET request in and of itself. It's not too dangerous to bypass the CRSF token here because anyone should have access to log in. This has the advantage of keeping CRSF for any other action you may need, but it wouldn't work for actions that need more security.
You can make your iOS page consist of a UIWebView. I'm not sure if this will suit your needs, but it would have the proper CSRF token and you can remove the UIWebView after submitting. It's kind of like option 1, but bulkier.
Good luck!
Easiest fix is to change the server side to not authenticate the CSRF token. Here's an example of using a different controller for your API.
class Api::BaseController < ApplicationController
skip_before_filter :verify_authenticity_token
end
In general, your API is either going to require authentication for API calls (in which case you should have your own authentication, or OAuth, or any number of authentication mechanisms) or isn't (in which case it's a publicly accessible API and CSRF doesn't matter). There a few other threads here and here that discuss it.
From another answer on SO (go upvote it!):
CSRF attacks rely on cookies being implicitly sent with all requests to a particular domain. If your API endpoints do not allow cookie-based authentication, you should be good.

AngularJS and authentication to an Oauth2 Provider?

We have an API, Oauth2 Provider.
From AngularJS client Side app, how can I implement the flow of authentication to this api to get the access token for future requests?
What I am searching for is a Implicit Grant flow for this.
I'll provide a
{
client-id: "abcdefghijklmnopqrstuvqxyz0123456789",
redirect_url: "http:localhost:8080/provider_cb",
response_type: "token"
}
I have a Rails REST API in the backend and doorkeeper/devise for Oauth2 provision.
I came across angular-oauth, which seems to solve the problem to certain extent.
but,
I do not wish to provide a token verification function (Is this mandatory)
I do not wish to open a new window popup for the login (Wish to do redirections in same window)
Now,
Q1. What I do not understand is how is the whole process started, I can't make any $http request, this returns with a SignIn HTML page. Should I use $location service to redirect to it to login page? Or should I have a link to the whole GET request to /oauth/authorize?...
Q2, How will I capture the redirect after SignIn to extract out the access_token?
Q3. Do know any Service which takes care of Oauth2 authentication or a standard Angular way of doing this?
Lets try an answer to your three questions:
Q1) You should basically understand the general OAuth2 process. It is not an AngularJS-specific implementation you're looking at. If you don't want to work with a popup window for the authorization, you'll have to trick around a bit to have the redirect_url / state working correctly after coming back (if you want to have #state - saving - otherwise just specify your entry - url in the redirect_uri). You should not use $http for the redirection as this is just for XHR and similar calls useful. To get your user to the login page, just do a
$window.location.href = 'http://yourlogin.com/oauthloginpage';
Your app will then redirect to the login page - don't forget your parameters for redirect_url. Also specify other parameters within the request like "scope" / "state" if required.
Q2) The redirect AFTER Login will redirect to the uri you specified within your redirect_url. Then it will come up with something like http://myapp.com/#access_token=foobar&refresh_token=foobar2&state=loremipsem
Just grab the parts from angular with a bit of code like this:
var currentURL = $location.absUrl();
var paramPartOfURL = currentURL.slice(currentURL.indexOf('#') + 1);
Then parse the paramPart into an array with split('&') and iterate through it by looking for the "key" access_token and - voila - there is your access_token ready for being taken into your local storage / service / cookie.
There are other implementations you might use to split URLs into parts - maybe there is a better one, but this here would be the "fast shot".
After parsing, you can redirect the user again to the correct state with a normal $location.path(....) call and eliminate the # parameters of OAuth2.
Q3) If you want to have a way of mapping the source state / route of your AngularJS-app - try misusing the state parameter if your OAuth2-Server implements it. This will survive the request <-> response.
For a non-popup-implementation, I don't know any further module currently.
Another way to play with the OAuth2 stuff is to implement the loginpage on your own and then just interact with a oauth2 provider reacting on rest calls with Basic Auth or other methods. Then you can use $http calls probably.

Resources