1
votes

I am considerably new to OAuth authentication scheme. What pose a problem for me at the moment is getting access_token from server in Rails app.

So far I read few articles covering methods related to Resource Owner Password Credentials in OAuth 2.0, but still it got me nowhere. To name a few Official documentation regarding ROPC / Introduction to OAuth2 / Description of OAuth2 gem from Intridea

Server that I want to connect with allows password grant. It's deployed by 3rd party, so I assume everything is ok with it. On manual page they defined example of authorization as follows:

curl -X POST -d
'grant_type=password&username=USER_EMAIL&password=YOUR_PASSWORD&client_id=CLIENT_ID&client_secret=CLIENT_SECRET'
'https://auth.example.com/oauth2/token'

I posses all data which is mentioned above. BTW, client_id and client_secret are generic values enclosed in documentation. Server uses Doorkeeper gem to implement OAuth2.

To retrieve access_token from server, I simply put advised by Doorkeeper's wiki code into one of my controllers. Testing ROPC for Doorkeeper

My code in Rails API app utilizing OAuth2 gem from Intridea:

 def test
    client = OAuth2::Client.new(CLIENT_ID, CLIENT_SECRET,
     site: 'https://auth.example.com/oauth2/token')

    access_token = client.password.get_token(username, password)
    Rails.logger.info access_token.token
  end

What I get after visiting localhost/test is Completed 500 Internal Server Error with OAuth2::Error saying that page that I look for doesn't exist.

When trying just use curl from command line with respective data, I recieve:

WWW-Authenticate: Bearer realm="Doorkeeper", error="invalid_grant", error_description="The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."

Please kindly advise what may cause problem in these set-up.

1
So CLIENT_ID and CLIENT_SECRET are your environment variables? Where did you set your environment variables? The site is wrong. If you want to test this in development the site should be site: 'https://127.0.0.1:3000' 3000 If your server is using port 3000. Also you need to have client.auth_code.authorize_url(:redirect_uri => 'http://127.0.0.1:8080/oauth2/callback' If you use port 8080. So did you follow the instructions at page or I am just totally wrong? I never used this but I configured Devise and Omniauth-Facebook and they are very similar github.com/intridea/oauth2 - Fabrizio Bertoglio
CLIENT_ID and CLIENT_SECRET in my code are replaced with actual data, I just didn't want to reveal it on SO. Server to which I want to connect is not developed by me, I only have data which should allow to authenticate and then use their api. As far as I know, setting up callback doesn't apply here as it is authenticated by password grant. - w1t3k
You are right ! - Fabrizio Bertoglio
I have read many discussion, some people suggest that you should not pass client_id and client_secret, the required parameters for the refresh token are grant_type and refresh_token. stackoverflow.com/questions/24548977/… stackoverflow.com/questions/39689168/… - Fabrizio Bertoglio
Thanks for your comment. Please, take under consideration that I want to get access_token not refresh_token. Your first link says that we should not use client_id / client_secret on web browser apps, mine is on server-side. You're right that client_id / client_secret may be unnecessary overhead nowadays. I also saw this kind of suggestions, in my implementation above I use Intridea oauth2 gem which enforces using this data in constructor. #initialize - w1t3k

1 Answers

2
votes

As it seems I overlooked one important thing, we should declare explicitly token_url in relation to site address and not treat site parameter as entire path.

So in order to request access_token my method should look like this:

def test
  client = OAuth2::Client.new(client_id,
                                client_secret,
                                token_url: "/oauth2/token",
                                site: "https://www.example.com/" )

  access_token = client.password.get_token(username, password)
  Rails.logger.info access_token.token
end

Here you can find similar issue to mine.

If someone wants to get access token with password credentials using simple http method, here is example how to approach this thing:

def test
  param = {
          :client_id => client_id,
          :client_secret => client_secret,
          :grant_type => 'password',
          :username => username,
          :password => password
        }

  uri = URI.parse(service_url)
  http = Net::HTTP.new(uri.host, uri.port)
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  http.use_ssl = true
  request = Net::HTTP::Post.new(uri.request_uri)
  request.body = param.to_query
  response = http.request(request)

  Rails.logger.info response.body()
end