How to authenticate client on multiple OAuth2 providers? - authentication

My REST API (api.example.com) is currently an OAuth2 provider and has been the support of a mobile app.
Recently we have created a new web-site(www.example.com) which will be treated like any other client. The web can authenticate on the API by using a password grant_type where a user types in her credentials. From there the client(browser) gets an access token and can than consume the API.
The problem comes that we want to authenticate clients on the web-page using Facebook.
So basically, the web should in the end be able to get an user access token to access the API by logging in via Facebook.
I've looked around and I've seen two legged and three legged OAuth2 authentication scenarios but:
How does that applies on the scenario I just described?
What is the right way of doing this?
What are the security issues I should take into account?

Here is one way to go about this:
When a client authenticates with facebook, on mobile using their SDK or for instance on the web using the authorise method, it will get a facebook access token.
If your API is also an OAuth2 provider and you want to then login the client(issue an access token) using the facebook token you just got you can do this by using extension grants(https://www.rfc-editor.org/rfc/rfc6749#section-4.5).
Here, the same way OAuth2 has a password_grant type, you could create an extension grant called, for instance facebook_access_token_grant, and send that facebook token to the API. If the token is valid than the API issues an app access token that can be used by the client on subsequent requests.
The steps are:
1 - Client gets an access token from facebook. On mobile devices will be using the Facebook SDK, on web apps can be with the javascript login thing or using the authorise method where the browser is redirected to facebook and so on.
2 - After getting the facebook access token, the client requests a access token from the API by posting:
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
client_id={{ client_id }}&client_secret={{ client_secret }}&grant_type=facebook_access_token&facebook_access_token={{ TOKEN }}
3 - API debugs the facebook_access_token with a https://graph.facebook.com/me?access_token=TOKEN.
If everything validates the API issues a bearer token to the client by responding something like:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"API_ACCESS_TOKEN",
"username":"theuser",
"expires_in":3600,
"refresh_token":"API_REFRESH_TOKEN",
}
4 - Client uses that token on subsequent calls to the API.
GET /some_endpoint HTTP/1.1
Host: server.example.com
Authorization: Bearer API_ACCESS_TOKEN
Make sure you do all this over a secure connection(TLS) so that you don't violate https://www.rfc-editor.org/rfc/rfc6749#section-1.6 and all this should be according OAuth2 protocol.

You have to have user login both and then connect them using email

Related

ID token usage when using "Log in with Google" in a mobile app

Suppose that I have a mobile app with a frontend and a backend server.
My understanding is that -- when a user logs in the app with "Login with google", the frontend sends a request to the google auth server, and gets back an ID token. The documentation says that the frontend can then send the token to the backend server to establish a session. I imagine that means the token can be used in session-based authentication?
If I were to use token-based authentication (as opposed to session-based), do I just attach the ID token in every server request, and have the backend verifies it each time when processing a request? this page suggests the ID token should not be sent to the backend API. Which leaves me wonder what the correct procedure is for token-based authentication when using log in with Google.
So my question is: Does my server need to create an access token from the ID token from Google, and send it to the frontend, so the frontend can attach that access token in the API requests for authentication?
Thanks
Login with Google is an identity provider (IDP) operation. A full OAuth solution, including an authorization server (AS) looks like this:
Mobile app uses system browser to redirect to AS
AS returns a redirect response to the system browser, which routes to the IDP
User signs in at the IDP
IDP returns an authorization code to AS
AS swaps it for IDP tokens and carries out validations
AS issues a set of tokens to the app. This includes an access token (AT) with whatever scopes and claims are needed for business authorization to work.
Mobile app sends AT in API requests
API authorizes using scopes and claims from the access token
So ideally plug in an authorization server, to get this out-of-the-box behaviour. Another option is to implement your own token service, and issue your own tokens. That is less recommended though, since it requires more detailed understanding of the underlying security.

Google OAuth2 on Mac Catalyst App: "invalid_grant" when exchanging authorization_code with refresh_token

We've an app that successfully performs Google sign-in from different clients: web, iOS app, Android app.
We're now trying to integrate Google Sign-in on a Mac Catalyst version of our iOS app.
We use the hybrid flow, we generate the authorization code on the client and exchange it on the server to obtain access and refresh token.
I found this library https://github.com/elsesiy/GAppAuth and I'm using the same credentials used for the iOS app.
The redirect to the app after the sign in through custom scheme works fine and I'm able to obtain the authorization code.
But when I share the authorization code with my server, I get an error on the request to exchange the authentication code to obtain access_token and refresh_token:
POST https://accounts.google.com/o/oauth2/token
Content-Type: application/x-www-form-urlencoded
Params:
code (sent by client)
client_id (server client id)
client_secret (server secret)
grant_type="authorization_code"
redirect_uri is not added for native client request.
Response:
400 {'error': 'invalid_grant', 'error_description': 'Bad Request'}
Please note that that the exactly same flow works on iOS.
I checked also a different type of credentials (Native clients, type: Other)
Any ideas on what's wrong and how can I fix this?
I suspect there's something that Google libraries for login do that is not implemented in GAppAuth (see https://github.com/openid/AppAuth-Android/issues/293).

Simultaneous use of an api key and an access token in the OAuth2 authorization flow

I'm auditing an API whose client is a mobile application using the OAuth2 workflow but I'm missing something. I have a first endpoint of the /token.oauth2 API which allows me with credentials to get an access token needed to call other endpoints of the API. So far OK but on top of that I have an "x-api-key" which is transmitted along with the access token and if both the API key and the access token are not present, the server sends me a HTTP 401 response.
I can't find any mention of a connection flow using both an "x-api-key" and an access token in the OAuth2 standard. When do you think?

Update a Socrata dataset using app token and private in HTTP basic

I'm trying to write a script to update metadata on various datasets, using an authorized app. Using OAuth seems like the wrong approach (it's not a web-facing application for other users to use as themselves), and passing my own user name and password seems...icky.
The SODA API authentication documentation is pretty confusing:
All HTTP-basic-authenticated requests must be performed over a secure (https) connection, and should include an application token, which is obtained when you register your application. However, authentication [sic, should be "application"?] tokens are not strictly required when a request is authenticated. Authenticated requests made over an insecure connection will be denied.
Here is a sample HTTP session that uses HTTP Basic Authentication:
POST /resource/4tka-6guv.json HTTP/1.1
Host: soda.demo.socrata.com
Accept: */*
Authorization: Basic [REDACTED]
Content-Length: 253
Content-Type: application/json
X-App-Token: [REDACTED]
So:
Can you even use app token + secret token to authenticate with HTTP basic?
Which of the two "[REDACTED]" is the app token, and which is the secret token?
My guess (based on some testing) is that the answers are:
No
The first "[REDACTED]" is the Base64 version of username+password, the second one is the application token, which is not relevant to authentication.
Application tokens and secret tokens aren't actually tied to any sort of pre-baked user authentication. They're tied to your application, and are then used in OAuth to ensure that your app is what it claims to be when the user is passed through the OAuth workflow. Once the user authenticates, the app can retrieve an authentication token that is used to actually authenticate their requests.
What you're really looking for is a way to retrieve a "bearer token", which some API providers allow you to generate. This would allow you to basically "pre-OAuth" and get an authentication token without going through the full workflow. Unfortunately we're not one of them (yet) so you'll need to authenticate with plain old HTTP Basic and your username and password.
If you want a slightly-less-icky way to do that, I recommend registering a "bot" account that you grant only the necessary permissions on the necessary datasets. Then at least you're not baking your regular user credentials into your config. But keep in mind that even if we had bearer tokens, you'd be putting those into your config somewhere.
To answer your more specific questions:
No, because then one of them would have to be a bearer token, which they are not.
The Authorization header is the Base64 encoded username:password, while the X-App-Token is your application token. In this case the latter is just an extra header that would identify that request as having come from your app.
Thanks for your feedback on the docs - I'll clean them up and try to be more straightforward, and I'll definitely fix that typo.

Correct HTTP Status Code to be returned with OAuth Authorization Code grant type

A new website I'm working has the following components:
AngularJS/HTML5 Front-End
Web API Back-End that supports Front-End
OAuth Server - Authenticates user and provides tokens
The workflow for an unauthenticated user:
Views Front-End, which calls Web API to determine if authenticated
If not authenticated the user is redirected to OAuth Server
After successful authentication, the browser is redirected back to website with Auth Code
Auth Code is sent to Web API
Web API logic requests Access Token from OAuth server
A cookie is used to associate the token to the user
Additional requests send the cookie, which is used to authorize the user.
My question is what should I send for the HTTP Status Code for Step 1? Normally you send 401 for not unauthorized, but that is if you are using HTTP Authentication. Since the authentication is handled by a different server, that wouldn't make sense. 403 doesn't seem correct either because it implies a that the status will not change.
Should I just use a generic 400 or a custom 400.X code?
Although there is nothing wrong with sending HTTP 401 Unauthorized as a response in your case, a much better alternative would be to send HTTP 302 Found, which would imply that when the user was trying to access the front-end view, the applicable resource in this case (OAuth Server Url) was found somewhere else.
You can mention the OAuth Server Url in the Location header of the response, so the client would redirect the unauthenticated user to the intended location.
HTTP 302 Found
Location: https://oath-server-url.com