I am building an iPhone client with a Rails backend. The client communicates with the server through an Oauth2 API. I've set this up using the oauth2 and doorkeeper gems.
Every API request must be sent with a token. I currently support two token "types":
Client: Using the Client Credentials grant type. This is for non-user-specific requests, like accessing app-wide assets, keys, etc.
User: Using the Password Credentials grant type. To get this token, the client must request it by passing a valid username/password combination. All user requests use this token.
This is all working fine but I'm hitting an issue now that I'm allowing a user to also log into the app using Facebook.
Upon the user logging into FB, my client responds by passing the Facebook UID to my server (using a Client token). I then do some checks on my server to match this UID to an existing user in my database.
Here's the issue: I want to respond to this request with a User Token. This token is needed as the user will now be logged into the app, and any subsequent requests will need this token. However, currently I feel like the only way for me to do this is:
Respond with the username and password. Then have the client make a request for a User Token following the Password Credentials flow. I don't like this because I'm passing a password, and it requires multiple trips.
I feel like I may be missing something basic. Is there another way I should be handling this flow?
I think I have a solution but it's definitely a hack.
Basically I'm hijacking the Password Credentials flow to also handle this Facebook scenario.
The client makes the call like so (formatting may be off as I tested in ruby):
curl -i http://www.example.com/oauth/token -F grant_type=password -F client_id=(client id)-F client_secret=(client secret) -F username=(email address) -F password=(password) -F provider="facebook" -F uid=(fb uid) -F token=(fb token)
On my server I check for the "provider" parameter. If found, instead of password authentication it uses the facebook uid to find a match in the user table. I also pass the FB token as a security measure (I verify that this token belongs to the uid before looking for a match). If a match is found, the user is set as the resource owner of the token, meaning I end up with a User Token.
This is the code block from my doorkeeper.rb:
resource_owner_from_credentials do |routes|
if params[:provider]
// FB uid authentication path code here
else
// password authentication
user = User.find_by_email(params[:username])
user if user && user.authenticate(params[:password])
end
end
The resource owner password credentials type defined by OAuth 2.0 doesn't really fit to external logins, e.g., Facebook, since the authentication is done through the external site and not from the username and password on your own authorization server.
One solution is to switch to the implicit grant type of OAuth 2.0 (https://www.rfc-editor.org/rfc/rfc6749#section-4.2). This type is supported by Doorkeeper too.
From your app you have to open a web view and redirect the user to the authorization endpoint of Doorkeeper (default: /oauth/authorize) with the parameters: client_id=..., redirect_uri=... and response_type=token. Additionally you have to tell Doorkeeper to redirect the user to FB login.
Therefore add this to doorkeeper.rb:
resource_owner_authenticator do
user_from_session || begin
session[:return_to] = request.fullpath
fb_login_url = "..." # add here your facebook login url
redirect_to(fb_login_url)
end
end
After the user logged in via FB and you authenticated the user on your server, you have to redirect the user back to session[:return_to] what points to /oauth/authorize and that redirects to the initially given redirect_uri including the access_token in the url.
Related
I have successfully migrated to devise_token_auth (from simple_token_authentication), however for UX reasons I'd like to allow a user to sign up for their account, use their account immediately (previously done by returning a token in the signup response), and then confirm their email to unlock certain functionality. How can one achieve this flow via this gem?
The user is by default signed in after registering.
You can grab the access-token and other information from the query string of the url that you set as the confirm_success_url i.e the url to which the user gets redirected to after signup. Use that authentication token to make a request to the server for protected resources.
The implicit grant is a simplified authorization code flow optimized
for clients implemented in a browser using a scripting language such
as JavaScript.
The resource owner password credentials (i.e., username and password)
can be used directly as an authorization grant to obtain an access
token.
(https://www.rfc-editor.org/rfc/rfc6749#section-1.2)
My question is about understanding how these two grant types are different?
Important to understand here is the way and place you enter your credentials.
Implicit
Your app is https://example.com and for authentication, you are going to https://auth.some-domain.com (or even https://auth.example.com). After successful authentication, user is redirected to https://example.com/some-callbackurl?#token=token-value.
Points to be noted: Redirection and token in URL
Resource Owner Password flow
Your app is https://example.com and for authentication, you are going to https://example.com (or https://example.com/login). After successful authentication, user is redirected to https://example.com/home.
Points to be noted: No redirection and no token exchange in URL
Basically if you are owning the app (client app, server app, auth app) then this is something you would do. Basically you are the one who is in charge of authentication - not a third party app. You trust your client app.
https://example.com/login gets credentials from user and does a HTTP REST POST (for example) call and get a response as token (and refresh token - optionally). It saves it in localStorage or cookie and then redirects to home page or whatever page it has to redirect to.
No redirection happens in exchange.
As you quoted, the "Resource Owner Password Credentials Grant" is suitable in cases where the resource owner has a trust relationship with the client, such as the device operating system. An example is Facebook application - Facebook trusts their app that is installed on the device.
Thus, client-app does not have to be registered in the auth-server. As you can see in the request the client_id is not transferred as a param. In addition, the flow is simpler - the access token is retrieved within a single request.
I am trying to use account linking in my skill. The problem is that the documentation is not clear enough. I have the login screen, it redirects to the amazon redirect uri provided in the URL parameters, I also include the code (btw I'm using Auth Code Grant) and here comes the problem. My script gets the code and the client credentials and generates the two tokens, but what should it do with them? Does their system wait a json response or something containing the two tokens using their names as keys or should I redirect again? What do they mean in the documentation when they say the server should return the access token and the refresh token?
The token response should look like this. I believe the exires_in and refresh_token properties are optional.
{
"access_token": "...",
"refresh_token": "...",
"expires_in": 3600
"token_type": "bearer"
}
https://developer.amazon.com/docs/alexa-voice-service/authorize-companion-site.html#auth-code-grant.
There are multiple threads on this topic from the Amazon Developer Forum I tried the tutorial referenced on a home brew AVS device (RPi3) and it works with no issue (I can get the user name etc. from my Amazon account), although I still can't figure out how to access activity api json within AVS SDK.
Steps in Account Linking(Auth code grand flow):
• User will be redirect to form based login page, used to get the user credentials
• After validating the user credentials and user authorities by your backend security script, it will be redirect the request to authorize endpoint to generate the authorization code.
• Once the request reached the authorize end point, it will validate the client details.
• Once it is validated, user will be redirected to the approval page.
• Once we get the confirmation from the user, your backend security server script need to create the autorization code and need to give it back to the AWS alexa client.
• AWS client will call our access token end point to get the access token and refresh token.
• Once AWS client gets the access token and refresh token, the skill will be linked to the user.
• AWS Alexa client send the access token in every request once the user have linked the skill
Your Problem: AWS client will call your access token end point url along with Authorization code and client credentials, Your back-end script need to validate those inputs and need to create access token, refresh token and send it back to AWS client.Its a POST request from AWS client, you have to return back response to same POST request.
I'm struggling with OAuth2 authorization, authentication and user linking.
What I've done so far:
I've created a client and it's secret.
All redirects and so on are working. Grant type password works for own native app (e.g. Android and iOS)
But for access token, user_id is NULL if grant type is Authorization code.
How can I assign a user to access token or authorization code?
Is there a module for Apigility to provide login screen? I only get asked for "allow" or "disallow" application but I'm never asked for a username and password.
Update:
Question is related to provide OAuth2 access third party pages, e.g. IFTTT. They open /oauth/authorize page and somewhere I have guide user to a login?! to determine related user? Is there an existing module for this?
Third party sites, e.g. IFTTT do not use password grant type for security reasons. And compared to other pages the workflow is: Is user authenticated? Yes: Show Accept/Decline button. No: User has to login and will be redirected afterwards to /oauth/authorize page. So is there a common way in apigility to check if user is logged in and if not, redirect to a login mask?
To authenticate with username and password using OAuth2 you should use the grant_type=password.
I'm not sure if there is a login screen in Apigility. But I don't think it should have it, because Apigility already allow this by one or more endpoints through OAuth2, more specifically by OAuth2 Server Library for PHP.
How to do
Add the grant type to client:
On your client table (oauth_clients.grant_types column) set "password".
Create a new authentication adapter type=oauth2.
Create a post to the authetication url like below.
url=localhost:8080/oauth, where localhost:8080 is where the apigility is running and /oauth is the configured auth adapter url.
payload:
{
"username": "USERNAME",
"password": "PASSWORD",
"grant_type": "password",
"client_id": "CLIENT_ID"
}
When login successfully it will return the access token.
I am currently trying to implement a web service (API) with OAuth2 authentication using Spring Security OAuth. As far as I understood, given a user, a client app and a server, the authentication process is as follows:
User requests resource from server via client
Client retrieves request token from server
Server responds with a temporary request token and a redirect URL
Client loads web page (redirect URL) and lets user enter credentials in order to authenticate the request token. The form inputs are sent to the server, input is unknown to client.
Server replies with an authorization code, which is handed to the client
Client uses authorization code to retrieve an access token (and, optionally, a refresh token if one was requested)
User hands access token to client
Client uses access token to retrieve requested resource
In Spring OAuth, there are three grant types to request an access token:
Authorization Code, which is the method I described above, refresh token, and user credentials. I don't know how retrieval by user credentials works, is it similar to retrieval via refresh token?
A couple of statements you are making above are incorrect. Probably it's a good idea if you have another look into the OAuth2 spec: https://www.rfc-editor.org/rfc/rfc6749
To concentrate on your question I just refer to the last paragraph of your question here after.
OAuth2 supports 4 grant types, namely 'Authorization Code', 'Implicit', 'Resource Owner Password Credentials' and 'Client Credentials'. The one you are refering to as 'user credentials' would be 'Resource Owner Password Credentials'. In this grant type you loose OAuth's benefit of not having to hand over resource owner (aka user) credentials to the client. However it still has the benefit of not having to store the password on the client and sending it for each resource request, since a token is used instead. The process flow is as following:
resource owner sends credentials to client
client sends credentials to authorization server
server returns access token (and optinally a
refresh token)
client uses access token in subsequent request to
ressource server
So yes, you could say that the flow of the Resource Owner Password Credentials grant is similiar to the flow when a client already has a valid refresh token (from which ever grant).