Related to Accessing Third Party Apps After Creating A Session Via API Token and to AWS API credentials with OneLogin SAML and MFA
Since AWS assumeRoleWithSAML temporary security credentials are only valid for one hour and we have a few different roles to assume it would be very annoying for the user to enter the username/password everytime he needs to switch the role or get new credentials because of the short validity. It's totally odd to the web base OneLogin usage, where he is logged in once for the whole day or even week (depending on the policy).
I know how to get a session via API. At least this would reduce the times the user needs to enters username/password to two times. One time in the web, one time on the CLI.
But is there any way to use this session token to generate a SAML assertion via API with this session token instead of submitting username/password to the API endpoint?
I don't want so store the users credentials locally for this. And with MFA enabled this wouldn't work in a seamless way.
While being able to generate a SAML assertion for any user (without the need for MFA and a user/pass) seems like a good workaround, this is unfortunately fraught with security perils.
An API that bypasses the usual authentication effectively gives that endpoint the ability to assume any user in AWS. The "assume user" privilege is locked down pretty tightly in OneLogin, and is not the sort of thing that's given out lightly.
Basically, an API to do this seems dangerous from a security perspective. This might be something we'd consider as part of an oAuth flow (or OpenID Connect resource endpoint) but that'll take some more thinking on our part before we'd implement it.
The only compromise solution I can think of that could be implemented today would be to temporarily cache the users' credentials for a longer period of time in your code. This way they could be reused to generate new SAML assertions for a longer period of time, but would effectively be thrown away after (say) eight hours.
This wouldn't allow for MFA on an app policy, but we are building out the ability to request and verify MFA via API (coming soon) so you could implement MFA in your app (independent of any app policy) once this becomes available.
Obviously the ideal solution would be for AWS to let users' configure the session length, but so far they've been unwilling to allow this.
Related
I'm developing an ASP.NET Core API, and I'm trying to do the authentication and authorization part as best as I can. I'm studying OAuth 2 and OpenIDConnect (very preliminary studies at this point). But from an API developer standpoint, what can I gain from inserting an Identity Provider like Auth0 or Azure AD B2C in the process instead of just storing the user credentials using some form of cryptography?
Also, Oauth 2 seems to allow many flows, is the job of the API to be concerned with the flow of the application consuming that API? Seems a bit unreasonable. What I want is just to have a safe way to store the user credentials, and allowing the users of my API to perform authentication and authorization before consuming and manipulating resources within the other services within the API.
I understand that authentication and authorization is a sensitive topic within an application, as they deal with security concerns, and I'm planning on building an application that will deal with sensitive financial operations. That's the reason I wend after Auth0 and Azure AD B2C. But to be honest I'm having a little trouble trying to understand what Identity Providers like these will bring to the table, I know they'll bring something of importance, I just need some help to see what and why should I use them.
what can I gain from inserting an Identity Provider like Auth0 or Azure AD B2C in the process instead of just storing the user credentials using some form of cryptography?
Well, you get the freedom of not storing credentials in your database.
Most likely these service providers are taking better care of their security than you would.
Another thing that you gain is Single Sign On.
Many apps can use the same identity provider for the users, so the users only need to sign in once to use all of the apps.
Of course it is not zero cost, there is complexity involved in OAuth/OIDC.
But neither is building your own user store.
Also, Oauth 2 seems to allow many flows, is the job of the API to be concerned with the flow of the application consuming that API? Seems a bit unreasonable.
No, the API usually does not care what flow the caller uses.
What it cares about is that it receives a valid access token that contains the necessary permissions to access a particular resource.
It is a concern of the client app to choose the flow to use.
But to be honest I'm having a little trouble trying to understand what Identity Providers like these will bring to the table, I know they'll bring something of importance, I just need some help to see what and why should I use them.
Well, here are the things that come to my mind:
Better security (most likely, it isn't only about the password hashing algorithm etc.)
Better SLA (building a 99.95% SLA service like Auth0 is not cheap)
Proven track record
Single Sign-On
Single identity for users to all your apps, can easily disable their account as well to prevent access to all apps at once
Can easily add support for federated authentication with other identity providers
No need to store password hashes etc. in your app
Ready-made administration tools (which you need to build otherwise)
To add to #juunas:
AI to proactively monitor user access and disable dodgy logins e.g. logging in from USA and Russia a minute apart
Reporting and stats.
Password protection e.g. not allowing password that has appeared in a breach
Portal and API for user CRUD
MFA
Self-service password reset
Passwordless support
Fido 2 support
TL;DR When using google oauth on desktop app, what to save on disk to avoid repeated sign in? Save the google user id? or the token? or an session id?
I'm creating an little desktop app, whitch must authenticate to my REST API server. I'm using google oauth2 for that.
The idea is, that when the desktop app will be authentivated, it generates some data that will be send to my server. The server will store the data with the google user id received from https://www.googleapis.com/userinfo/v2/me.
On the first run of the desktop app, it will open the default browser, with and url for my server and start an local http server. then:
my server will redirect the browser to google (with the clientid, secret, etc.)
user logs in and it will be redirected back to the server with the oauth code
server uses the code to get the token, and then the user profile and stores the token and the profile in db, then redirects the browser to localhost with an paramerer
the desktop app catches the parameter and stores it in an file on the disk
next time the desktop app will start it only reads the file for the parameter to send the generated data with it to my server
my question is: what the parameter should be? the google user id? the oauth token? an generated session id for this desktop app? or something else?
when it will be the google user id, it can conveniently sent the data with the user id and the rest server will just store it in db as is. but I don't think it's safe
when it will be the token, the rest server has to with every request also get the user profile from google with the token. and imho sending the token with every request isn't safe either
generating an session id means to store it with the user and the token on the server and the desktop app will just store it and send it with every request. but I don't know if it's safe to do that
As it's normally the case in software development you have a couple of options depending on requirements.
The mandatory requirement is that your client (desktop) application needs to send something to your REST API so that the API can perform up to two decisions:
Decide who the user is.
Decide if the user is authorized to perform the currently requested action.
The second step may not be applicable if all authenticated users have access to exactly the same set of actions so I'll cover both scenarios.
Also note that, for the first step, sending the Google user ID is not a valid option as that information can be obtained by other parties and does not ensure that the user did authenticate to use your application.
Option 1 - Authentication without fine-grained authorization
Either always sending the id_token or exchanging that token with your custom session identifier both meet the previous requirement, because the id_token contains an audience that clearly indicates the user authenticated to use your application and the session identifier is generated by your application so it can also ensure that. The requests to your API need to use HTTPS, otherwise it will be too easy for the token or session ID to be captured by an attacker.
If you go with the id_token alternative you need to take in consideration that the token will expire; for this, a few options again:
repeat the authentication process another time; if the user still has a session it will indeed be quicker, but you still have to open a browser, local server and repeat the whole steps.
request offline_access when doing the first authentication.
With the last option you should get a refresh token that would allow for your application to have a way to identify the user even after the first id_token expires. I say should, because Google seems to do things a bit different than the specification, for example, the way to obtain the refresh token is by providing access_type=offline instead of the offline_access from OpenID Connect.
Personally, I would go with the session identifier as you'll have more control over lifetime and it may also be simpler.
Option 2 - Authentication + fine-grained authorization
If you need a fine-grained authorization system for your REST API then the best approach would be to authenticate your users with Google, but then have an OAuth 2.0 compliant authorization server that would issue access tokens specific for your API.
For the authorization server implementation, you could either:
Implement it yourself or leverage open source components
⤷ may be time consuming, complex and mitigation of security risks would all fall on you
Use a third-party OAuth 2.0 as a servive authorization provider like Auth0
⤷ easy to get started, depending on amount of usage (the free plan on Auth0 goes up to 7000 users) it will cost you money instead of time
Disclosure: I work at Auth0.
There should be no problem sending the access_token with every request since they are created for that purpose and are thus short lived. You can use the Google Authorization Server endpoint to verify a token instead of using it to do a request for a users profile.
If you're only relying on Google for authentication, here's how your workflow can look:
the client (desktop application, in your case) retrieves the
Google id_token following the user's log in, and then sends it to
the server
the server validates the integrity of said token and extracts the user's profile data; this could mean a simple GET on Google's endpoint to verify this token: https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
On subsequent requests, nothing should change really, except that the user's login process will be automated (since he's given permissions & all), and thus much faster. #danielx is right, there's no problem with sending the token each and every time.
Since LinkedIn discontinued their network updates RSS feeds, I haven't been able to find any "simple" mechanism to gain access to update feeds w/o going through the oauth process requiring the user to authenticate first. The few examples I've seen posted here all assume you've obtained the auth token first. Is that even possible?
In case anyone else inquires: https://developer.linkedin.com/support/faq
If your application requires you to make API calls in an automated way
- without user interaction, you need to bootstrap the first access token request by manually signing in, and then ensure that your
application refreshes the token automatically prior to expiry to avoid
the need for additional human authentication.
Preface
I'm developing several web services and a handful of clients (web app, mobile, etc.) which will interface with said services over HTTP(s). My current work item is to design an authentication and authorization solution for the product. I have decided to leverage external identity providers, such as Facebook, Google, Microsoft, Twitter, and the like for authentication.
I'm trying to solve the problem of, "when a request comes to my server, how do I know who the user is and how can I be sure?". More questions below as well...
Requirements
Rely on external identities to indicate who I'm dealing with ('userId' essentially is all I care about).
The system should use token-based authentication (as opposed to cookies for example or basic auth).
I believe this is the right choice for scaling across multiple clients and servers while providing loose coupling.
Workflow
Based on my reading and understanding of token-based authentication, the following is how I imagine the workflow to be. Let's focus for now on Facebook in a web browser. My assumption is that other external identity providers should have similar capabilities, though I have not confirmed just yet.
Note, as of writing, I'm basing the following off of Facebook login version 2.2
Client: Initiates login to Facebook using the JavaScript SDK
Facebook: User authenticates and approves app permissions (to access user's public profile for example)
Facebook: Sends response to client which contains user’s access token, ID, and signed request
Client: Stores user access token in browser session (handled by SDK conveniently)
Client: Makes a request to my web service for a secure resource by sending along the user’s access token in the authorization header + the user’s ID (in custom header potentially)
Server: Reads user access token from request header and initiates verification by sending a request to the debug_token graph API provided by Facebook
Facebook: Responds back to the server with the user access token info (contains appId and userId)
Server: Completes verification of the token by comparing the appId to what is expected (known to itself) and the userId to what was sent on the client request
Server: Responds to the client with the requested resource (assuming the happy authorization path)
I’m imagining steps 5-9 would be repeated for subsequent requests to the server (while the user’s access token is valid – not expired, revoked from FB side, app permissions changed, etc.)
Here's a diagram to help go along with the steps. Please understand this system is not a single page application (SPA). The web services mentioned are API endpoints serving JSON data back to clients essentially; they are not serving HTML/JS/CSS (with the exception of the web client servers).
Questions
First and foremost, are there any glaring gaps / pit falls with the described approach based on my preface and requirements?
Is performing an outbound request to Facebook for verifying the access token (steps 6-8 above) per client request required / recommended?
I know at the very least, I must verify the access token coming from the client request. However, the recommended approach for subsequent verifications after the first is unknown to me. If there are typical patterns, I’m interested in hearing about them. I understand they may be application dependent based on my requirements; however, I just don’t know what to look for yet. I’ll put in the due diligence once I have a basic idea.
For instance, possible thoughts:
Hash the access token + userId pair after first verification is complete and store it in a distributed cache (accessible by all web servers) with expiry equal to access tokens. Upon subsequent requests from the clients, hash the access token + userId pair and check its existence in the cache. If present, then request is authorized. Otherwise, reach out to Facebook graph API to confirm the access token. I’m assuming this strategy might be feasible if I’m using HTTPS (which I will be). However, how does performance compare?
The accepted answer in this StackOverflow question recommends creating a custom access token after the first verification of the Facebook user token is complete. The custom token would then be sent to the client for subsequent requests. I’m wondering if this is more complex than the above solution, however. This would require implementing my own Identity Provider (something I want to avoid because I want to use external identity providers in the first place…). Is there any merit to this suggestion?
Is the signedRequest field present on the response in step #3 above (mentioned here), equivalent to the signed request parameter here in the ‘games canvas login’ flow?
They seem to be hinted as equivalent since the former links to the latter in the documentation. However, I’m surprised the verification strategy mentioned on the games page isn’t mentioned in the ‘manually building a login flow’ page of the web documentation.
If the answer to #3 is ‘Yes’, can the same identity confirmation strategy of decoding the signature and comparing to what is expected to be used on the server-side?
I’m wondering if this can be leveraged instead of making an outbound call to the debug_token graph API (step #6 above) to confirm the access token as recommended here:
Of course, in order to make the comparison on the server-side, the signed request portion would need to be sent along with the request to the server (step #5 above). In addition to feasibility without sacrificing security, I’m wondering how the performance would compare to making the outbound call.
While I’m at it, in what scenario / for what purpose, would you persist a user's access token to a database for example?
I don’t see a scenario where I would need to do this, however, I may be overlooking something. I’m curious was some common scenarios might be to spark some thoughts.
Thanks!
From what you describe I'd suggest to use a server-side login flow as described in
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2
so that the token is already on your server, and doesn't need to be passed from the client. If you're using non-encrypted connections, this could be a security risk (e.g. for man-in-the-middle attacks).
The steps would be:
(1) Logging people in
You need to specify the permission you want to gather from the users in the scope parameter. The request can be triggered just via a normal link:
GET https://www.facebook.com/dialog/oauth?
client_id={app-id}
&redirect_uri={redirect-uri}
&response_type=code
&scope={permission_list}
See
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#login
(2) Confirm the identitity
GET https://graph.facebook.com/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#confirm
(3) Inspect the access token
You can inspect the token as you already said in your question via
GET /debug_token?input_token={token-to-inspect}
&access_token={app-token-or-admin-token}
This should only be done server-side, because otherwise you'd make you app access token visible to end users (not a good idea!).
See
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#checktoken
(4) Extending the access token
Once you got the (short-lived) token, you can do a call to extend the token as described in
https://developers.facebook.com/docs/facebook-login/access-tokens#extending
like the following:
GET /oauth/access_token?grant_type=fb_exchange_token
&client_id={app-id}
&client_secret={app-secret}
&fb_exchange_token={short-lived-token}
(5) Storing of access tokens
Concerning the storing of the tokens on the server, FB suggests to do so:
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.2#token
(6) Handling expired access tokens
As FB doesn't notify you if a token has expired (and if you don't save the expiry date and compare this to the current timestamp before making a call), it's possible that you receive error messages from FB if the token got invalid (after max. 60 days). The error code will be 190:
{
"error": {
"message": "Error validating access token: Session has expired at unix
time SOME_TIME. The current unix time is SOME_TIME.",
"type": "OAuthException",
"code": 190
}
}
See
https://developers.facebook.com/docs/facebook-login/access-tokens#expiredtokens
If the access token becomes invalid, the solution is to have the person log in again, at which point you will be able to make API calls on their behalf once more. The login flow your app uses for new people should determine which method you need to adopt.
I dont' see any glaring gaps / pit falls, but I'm not a security expert.
Once your server has verified the given token (step 8), as you said:
The accepted answer in this StackOverflow question recommends creating a custom access token after the first verification of the Facebook user token is complete. The custom token would then be sent to the client for subsequent requests. I’m wondering if this is more complex than the above solution, however. This would require implementing my own Identity Provider (something I want to avoid because I want to use external identity providers in the first place…). Is there any merit to this suggestion?
IMHO is the way to go. I would use https://jwt.io/ which allows you to encode values (the userId for example) using a secret key.
Then your client attach this token to every request. So you can verify the request without need to a third party (you don't need database queries neither). The nice thing here is there is no need to store the token on your DB.
You can define an expiration date on the token, to force the client authenticate with the third party again when you want.
Let's say you want your server be able to do some action without the client interaction. For example: Open graph stories. In this scenario because you need to publish something in the name of the user you would need the access token stored on your DB.
(I can not help with the 3 and 4 questions, sorry).
Problem with Facebook is that they do not use OpenId connect on top of Oauth (https://blog.runscope.com/posts/understanding-oauth-2-and-openid-connect).
Thus resulting in their custom ways of providing Oauth authentification.
Oauth2 with OpenId connect identity services usually provide issuer endpoint where you can find URL (by appending ".well-known/openid-configuration") for jwk's which can be used to verify that JWT token and its contents were signed by the same identity service. (i.e access token originated from the same service that provided you jwk's)
For example some known openid connect identity providers:
https://accounts.google.com/.well-known/openid-configuration
https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
(btw it is not a coincidence that Attlasian provides only these two services to perform external login)
Now as you mentioned, you need to support multiple oauth providers and since like Facebook not all providers use same configuration of oauth (they use different JWT attribute names, toke verification methods, etc. (Openid connect tries to unify this process)) i would suggest you to use some middleware identity provider like Oauth0 (service not protocol) or Keycloak. These can be used with external identity providers (Social pages as you mentioned) and also provides you with custom user store.
Advantage is that they unify authentication process under one type (e.g both support openid connect). Whereas when using multiple oauth providers with not unified authentication workflow you will end up with redudant implementations and need for merging different information's under one type (this is basically what mentioned middle-ware identity providers solve for you).
So if you will use only Facebook as identity provider in your app then go for it and make implementation directly for Facebook Oauth workflow. But with multiple identity providers (which is almost always case when creating public services) you should stick with mentioned workaround or find another one (or maybe wait till all social services will support Openid connect, which they probably wont).
There may be hope.. This year, Facebook have announced a "limited login" feature, which, if they were to add to their javascript sdks would certainly make my life easier:
https://developers.facebook.com/blog/post/2021/04/12/announcing-expanded-functionality-limited-login/
At the time of writing, I can only find reference to iOS and Unity SDKs, but it does seem to return a normal JWT, which is all I want!
I am building a messaging application using BackboneJS which naturally persists using a REST interface.
The issue I'm having is that I don't know how to restrict what data a user can pull back from the API. For instance a call to /messages would, at the moment, return messages for ALL users. I would like that resource to only return messages belonging to the current user.
Searching online seems to indicate that oAuth2 is the best way to solve this issue but all the tutorials talk about been redirected to another place to confirm access and retrieve an access token.
Given that my users will have already logged into the message application and that the REST API is actually part of the same application I don't like the idea of asking the users to confirm that my own app can access my own API.
Is there a better way?
oAuth2 is probably your best bet -- you definitely don't want to roll your own security. However, the flavor of oAuth2 you are thinking of is probably not what you want.
oAuth2 has four different flavors, known as authorization grant types:
Authorization code: This is the type you are thinking about. It is often called three-legged oAuth, because there are three actors in the token granting process (app, resource owner, and user). The app asks the user whether it is ok for the resource owner to give specific type(s) of access to the resource. It is a rather complex process that allows the validation of user credentials without allowing the app access to them. This is not necessary in your case, since you are both the app and resource owner.
Client credentials: This is a method for authorizing a client application with the server. It does not use user credentials at all. If you completely trust your client application (all client applications) to correctly protect user data and not expose other user's data to the user using the app, or you are providing only non-user data via the API (for example, map data or catalog data), you might be able to use this fairly simple type of oAuth2. However, if you want to be vigilant in protecting user data (and not allow apps to get to the data without the user providing credentials), you might not use this one.
Resource owner password credentials: The username and password of the user is passed via https to your backend server, which authenticates and authorizes access by providing an access token. The access token can then be passed with each call, and it remains valid for accessing the backend until a configurable time period has elapsed. This means that someone intercepting the token could only use it successfully for a limited amount of time (some number of minutes, generally). The interceptor would not know the username and password of the user. In addition, you can supply the app with a refresh token, which can be used to get a new access token once it has expired (until the refresh token expires -- usually with a significantly longer expiration date). Since the credentials are not passed across the wire often (and must only be passed encrypted), this is often the best solution for protecting user credentials and not requiring the user to pass them in often (good user experience). Implementation is much simpler than for the authorization code grant type.
Implicit: This is the least secure method -- no credentials are validated server side at all. This is usually used for client side scripting languages where credentials cannot be stored safely. If you are worried about security at all, avoid this type if possible.
So, check out OAuth 2.0, and look for the resource owner password credentials grant type.