How poorly have I implemented OAuth/OpenId? - oauth-2.0

I can't help but think I've implemented Open ID slightly incorrectly, but I also cannot find why I've done the implementation the way I have is bad or not.
Scenario:
Website - Used forms authentication before being updated to use OWIN. Forms auth has been stripped out.
Website now supports OpenId to Okta. This is being implemented for a large company of our users to facilitate their logins. This is functional.
The method I use for the site models how Microsoft does logins. On email domain detection, we redirect the user to the login page for their domain. In this case, Okta. We receive the callback, and look up the user in our existing data, and generate a cookie based on our existing data (or create a new user account if they don't have one).
Essentially, just using Okta to confirm they are a valid user, and then we log them in with our user data. We foresee doing this for other companies as well.
Problem:
I have a desktop (WPF) client that requires a login to our website. This talks to API's that already exist using an auth key/token system we built many years ago. Ideally, we do something similar. Use Okta to verify the user is a user of that system, then generate a token that can be used for these API's.
Here is where I'm not sure I've done this appropriately.
The desktop client calls an API endpoint on our site with the email domain the user entered. We verify the user's domain is allowed to use SSO, and if so, we issue back a challenge endpoint for the client to call. This challenge endpoint is then called by the desktop client to launch the users default browser.
This challenge endpoint is an endpoint on OUR website, that essentially triggers the challenge to the IdP. After login, a callback is called on OUR website, to process the auth response. We verify the user's account is valid, and get the refresh token from the response. With the refresh token, and an identifier of the user, this data is then sent back to the desktop client using localhost:randomPort so the client can consume the refresh token and identitifer. (Note that I do encrypt the refresh token and identifier's before returning them to the client)
This refresh token is then POSTed to OUR website, along with their identifier (so we can identify the IdP we should call), then use an OIDC client to verify the refresh token is still valid. If the refresh token is still valid, we generate an app token and return it.
Is there a glaring issue with how this is implemented that I'm not seeing? How can I do this differently?

You seem to be missing the role of an Authorization Server (AS) that you own, to manage connections to other systems and to issue tokens to your apps.
You seem to have some good separation and to be doing quite a few things well - eg you are using your own tokens rather than foreign Okta tokens. The main issue is likely to be growing the system.
PREFERRED BEHAVIOUR
An AS should result in simpler code and a system that is easier to extend:
You can add new authentication methods quickly
This should involve just adding a connection (eg Okta) to your AS
Doing so requires zero code changes in your UIs and APIs
Your UIs just use standard OpenID Connect flows and call AS endpoints, regardless of the authentication method used
Your APIs just verify tokens issued by the AS, then authorize requests, regardless of the authentication method used
Some scripting is needed in the AS, but typically this is small.
FEATURES
In terms of what an AS should do for you, have a browse of the Curity Concepts Pages. I work there, and we try to write about the science of OAuth and the common extensibility features software companies need.
CHOOSING YOUR MOMENTS
Integrating an AS and getting past all the blocking issues is a gradual journey though, and involves learning. So it requires choosing your moments, spikes and getting buy in from your stakeholders.
The main objective should always be simple and standard code in your apps, that is easy to scale. OAuth and the Authorization Server give you design patterns that help with this.

Related

What is a good microservice-friendly technique for refresh token security?

I've got an OAuth2-driven authorization system for the applications in my ecosystem using the Auth Code flow. At the moment, it is working extremely well following what I feel are best practices. My current flow can be summed up as this:
User clicks a Login button in application frontend.
Backend for application redirects user to Auth Server login page with redirect URI, client ID, etc, in params.
User logs in, Auth Server redirects to Backend /authcode endpoint with Authorization Code.
Backend authenticates with Authorization Code, receives Access (JWT) & Refresh tokens. It stores Refresh token in its own database, and returns Access token as an HTTP-Only cookie.
When Access token expires, Backend sends Refresh token to Auth Server to refresh.
The problem with this approach is it is heavily dependent on a single-backend/monolith/etc architecture. When the access token expires, the backend app in question needs to be able to get the refresh token and then do the refresh against the Auth Server.
My goals for the future state of this architecture are driven by two main concerns:
Allowing backends to be split into multiple micro-services that are all capable of authenticating the same JWT.
Supporting SSO. Currently, even though all users are managed through the same Auth Server and use the same credentials, they need to enter those credentials separately for each app they log into.
My initial thought was to move the refresh handling to the client-side part of the architecture. Since all the apps are owned by me, I could setup a new flow where a user would login directly with the Auth Server, and then the Access (JWT) and Refresh tokens are set as HTTP Only cookies. This is further supported by the fact that all of my apps are hosted via a single domain name (with different root URI paths for different apps). The new token structure would determine which apps a given user has access to.
My concern there is how to secure the Refresh Token client-side. Most likely I would need to use the Path attribute and depend on the fact that all my apps are on the same hostname, which as I said they are and that will not be changing.
I guess the point of this post is I'm looking for guidance on best practices for handling this kind of scenario.
A few thoughts based on design patterns we recommend at Curity:
BACKENDS AND JWTs
Related APIs should be able to forward JWT access tokens to each other, as detailed in the scopes article. Validating the JWT in each API results in a recommended zero trust setup.
BACK END FOR FRONT END
We recommend a particular way of doing this, focused on separation of web and API concerns - see this code example on the token handler pattern.
Token refresh is handled via HTTP Only cookies and client side retries. This provides a stateless solution that is easy to manage, and where the web back end is static content only, eg a content delivery network. It requires a couple utility API components to be deployed though.
An alternative option, as you say, is to write code within your back end to store tokens, so that cookies only contain a Session ID.
COOKIES AND MULTIPLE WEB APPS
In our resources we use reverse proxies / API gateways as the entry point to APIs, rather than a web back end. Common plumbing such as translating cookies to tokens can then be managed via gateway plugins - as covered in this tutorial.
However, when you have multiple web apps you need to keep cookies isolated during API requests. Each app therefore needs its own API routes. This is awkward but is a consequence of needing to use secure cookies for best browser security. It is best managed in the gateway, and separate domains or subdomains is usually cleanest:
https://api.brand1.com
https://api.brand2.com
Each web team is then responsible for their own API routes and the cookie / CORS / CSRF stuff, rather than the API developers.
SSO
This should be determined solely by the Identity Provider session cookie, which will remain valid as you navigate across apps. If you are presenting a login button when the app does not have a secure cookie yet, then it will not feel like SSO though. One technique for making SSO look seamless is for each app to automatically redirect when it does not have application cookies yet, rather than presenting a login button.
SUMMARY
A long answer, but the best solutions require separation of concerns that is not always obvious. Done well, the end result should be simple code in apps, correct security and an architecture that can be scaled.

iOS authentication to web server

OK. So i need some guidance as I am a total iOS authentication noob.
I have a simple app. Users can login to the app, and send messages to friends. There is a web server and a MySql Database that holds the users and login information.
Question: How do I authenticate a user when he logs in safely and securely?
I have spent the last several hours hurting my brain on the following authentication stuff i found from google:
OAuth 1.0 - is said to be good. But it is a protocol and not a library. Do i have to implement this from scratch? Is this even needed in my case for authentication?
OAuth 2.0 - it seems that some sites are using this. I have the same questions for this as version 1.0. I also saw this this message from the library's lead creator literally saying f*** version 2.0 because it was bad for security. But yet so many still use it. Is it dangerous?
The creator of 2.0 has now gone on to make a completely other library because of how bad 2.0 was and because of how unscalable 1.0 was. His library is called OZ. Should I be using this for my server?
I see AlamoFire/ AFNetworking have basic authentication shown in their documentation. Should i just screw the oAuth stuff and just use theirs?
Being new to the authentication thing, all this is very confusing to me. Can anyone knowledgeable in this provide some guidance?
I am currently in the process of creating a cross-platform application and have spent quite some time researching this!
My approach to the project is using a ASP.NET Web API using OWIN middleware.
This uses bearer tokens to authenticate the user.
Using Microsoft.Identity you can limit endpoints down to roles or even individual users (Autherization)
Currently I create a user on the REST API, They log-in at the /token endpoint and then receive a token. This token is then saved to the Apple key chain and can be used to authenticate the user for further requests to the API.
As long as you use SSL this is a secure method and is used widely in many applications.
This approach uses OAuth2 also, so you'll be albe to easily integrate Facebook/Google/etc integration.
Here is a link to the Microsoft Documentation for some further reading on how I did it:
http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api
Currently this is working perfectly for me for an angular front-end but would work exactly the same in iOS except you may want to save the token to the KeyChain Storage.
We mostly use OAuth 2 creating custom system on iOS to handle the authentication.
Nothing is ever bullet-proof but the 2 token system decreases the chance for stealing credential quite nicely.
The AlamoFire, AFNetworking or any other libraries you amy find have nothing to do with this though. What type of credentials you use depends on your choice or rather the choice of the API. You may use these tools to ease your communication with the API though.
So what the idea behind this is you will try to send your user name and password only once when logging in and then you will receive the two tokens which are further used to communicate. This will decrease a chance for someone to intercept the request with the user name and password which are the ultimate key to get the access to the user data.
Next is "refresh token" which is used to receive a new "access token". This call should be made every few hours or so (controlled by the API). If someone was to steal this token he would be able to use it to get further access for an infinite duration or until the owner chooses to invalidate the refresh tokens (this is what happens when you click "log out from all devices"). So this is still quite bad if someone gets it.
Then there is the "access token" which is used for each and every further request to the server. These tokens have a limited time till they are invalidated so if someone was to intercept it somehow he would have the access to the data for the duration of the token.
So assuming this is the procedure that is done on the backend this is what you need to do:
If you have the access token and is valid simply use the service
If you receive the error that the access token is invalid you need to refresh the access token using your refresh token
If refresh token reports an error you need to navigate back to the login screen
If the app has no refresh token then simply go to the login screen
There are some other things that are nice to cover such as if the request reports an invalid token you should pend the request, refresh the token and then repeat the call to the pending request. A system around this may be quite large.
This is pretty much it about the tokens and authentication but there are other parts of the communication which increase the security such as using a https secure connection. When talking about security you must take a look into every part of the communication.

Use password credential flow and some 3rd party authorization server

This is more of a general question but I hope it is still valid for SO.
So far I have learned, that in general, a mobile app (such as official Pinterest app) use the Password credential flow to let their users login and access the API directly. (let's just assume they use OAuth for this)
So they collect username and password, send it to their server and get a token in return which is used for subsequent requests.
Now a user did not want to register and created an account using e.g. Facebook as the authorization server. So my question is:
How is this flow implemented?
My educated guess:
User chooses "Login with Facebook" in mobile app
Facebook Login Page opens with return_uri = mobile app
Mobile app receives auth token
Mobile app uses client credentials and says the API: Use this token for user X
Is this correct?
First of all, apps should not use the Password Credentials Grant. The specification is rather clear about it:
In the traditional client-server authentication model, the client
requests an access-restricted resource (protected resource) on the
server by authenticating with the server using the resource owner's
credentials. In order to provide third-party applications access to
restricted resources, the resource owner shares its credentials with
the third party. This creates several problems and limitations
The specification then goes on describing those problems.
And about the Resource Owner Password Credentials Grant:
The authorization server should take special care when enabling this grant type and only allow it when other flows are not viable.
The entire purpose of OAuth 2.0, I to not have to use something like the Password Credentials Grant, where the user hands over their password to the application.
About your second question: what happens when a user does not want to register and create an account with your app, but wants to use e.g. Facebook for authentication?
Remember that both the Implicit Grant, as well as the Authorization Code Grant, work by using a browser control to authenticate the user. In that browser session with the Authorization Server, you are free to authenticate your user in any which way you want. Certainly, you can use your own user/password database, but you could also use other mechanisms, such as WS-Federation. In your case, it sounds like the user want to authenticate using Facebook.
Authenticating using Facebook is then not done by your client app, but by your Authorization Server. It typically does that by using the Facebook Authorization Code Grant, followed by a call to read the user's profile to obtain their Facebook user id, name, and so on.
If you do not want to build such an Authorization server yourself, you can use an existing one. Several companies offer login-as-a-service solutions, including the one I work for.
UPDATE: You asked several follow up questions in a comment below. I'll answer them briefly here:
First of all, the fact that some companies that use OAuth to secure their services allow for a Password Credentials Grant, does not imply that you should. In fact, there are probably more examples of companies that don't offer this possibility, than companies that do.
There are real trust issues, and real security risks with sharing your password with a device app. To start with, the app on the device is easier to hack than a server. Furthermore, if you give the app your password, presumably that app also needs to store it somewhere for future use. As a user, I just have to hope that that storage is safe form possible malware running on my machine. For more issues, see the introduction in the OAuth 2.0 specification mentioned above.
Secondly, all good Authorization Servers differentiate between First Party Clients and Third Party Clients. A First Party Client such as yours is controlled by the same company that controls the Authorization Server, and for such an app the Authorization Server does not ask for user permission to share data, since it makes no sense to talk about sharing data with yourself. That is why the web sites of these companies don't ask you whether you allow to share the data they hold on your behalf with them. They already have it, and there is no "sharing" going on.
Of course, you might argue that you have never seen any of these companies talking about this distinction between First Party Clients and Third Party Clients. But the reason they don't should be obvious: when you deal with them, you are always a Third Party App. They don't need to tell you that they treat themselves differently.
The mechanism I would choose in your scenario depends on the nature of the client app, and the nature of the services it accesses. What are your requirements?
Anyway, if the device the application is running on has a secure storage facility, such as Windows Phone 8.1, I would probably consider using the Authorization Code Grant without client credentials. That way, the user never has to log in again. If we're talking about a web site or a SPA, I would consider the Implicit Grant (where the "remember me" feature, if any, is offered by the Authorization Server). Again, the specification gives advantages and disadvantages of each grant type for several scenario's.

restful api (rails), mvc javascript app (ember or backbone) and token based authentication

I read about token based authentication and get the general id. What I don't understand is why on the frontend (ember in my case) I would need such a token if all communication is with your own restful api backend (rails in my case). If you communicate strictly with your own backend, and you leave the authentication in that backend then why do you need the token in your ember app?
Your backend would serve as a proxy sometimes but is that bad? Is it better to do it directly from the ember app if possible?
I would (mainly) go to twitter for queries.
Thanks for sharing your ideas.
I'm a bit new to this topic myself, but your question is also a bit unclear. If you mean the consumer key tokens that are used in oAuth systems, these are required to ensure that the third-party using your API has actually been granted access to use it - anyone without a consumer key cannot use your API.
Alternatively, if you are referring to users being authenticated using an authentication token...
When you create a rails app that has authentication (for example using the devise gem) a sessions controller is also created/used. Sessions(/cookies) are basically a way of 'remembering' that the user has logged in. This avoids having to resend username/password with every action the user performs in order to authenticate him/her for that action.
This approach works perfectly fine when it comes to web apps because all browsers support cookies. However, this is not true when it comes to mobile apps. It is not possible to keep a session/cookies when using a native app (well it is technically possible, but from what I've read it seems to require quite a bit of manual labor and a bit of code wizardry to get it working correctly).
Now, when you create an API for your app, you need to bear in mind that your API may be used for creating a mobile app (either by you in the future or if you open it to the public). This means that using sessions probably isn't a good idea. For each request that requires authorization the username/password will need to be sent to ensure the user has access to perform the requested action. But sending username/password with each request is definitely a bad idea. That's where token authentication comes in. If you've ever used devise, you will notice there is an option to enable token authentication. This basically allows the 3rd party to send a token rather than the username/password and works just the same. The good thing about this approach is that even if a token gets stolen they can expire and a new one can be generated without the user even realising and without the users password being stolen.
(I'm fairly new to the topic myself, from what I've gathered so far that seems to be how things work. Now if I have made any mistakes in my explanation/understanding I hope people will jump in an correct me.)

Use OAuth 2.0 Tokens to login to Salesforce.com

Currently we are not using OAuth with our apps but we are working on making the shift, we have direct login and capture the user/pass that was entered and store those. We then turn around and use the stored credentials for a feature that allows the user to open a record within Salesforce.com, we pass the user/pass in to the login endpoint along with a starting URL to the specific record, this works great and is a well liked feature as it is a simple SSO from the App to Salesforce.com where the user can see all data that may not be visible within the app.
Moving to OAuth 2.0 and using the standard webflow, we no longer can capture the user/pass, which is actually a good thing as far as security is concerned. We would however like to keep this functionality, is there anyway of SSO'ing into Salesforce.com by passing along one of the OAuth tokens or some kind of sesson id?
After reading more and thinking about what OAuth accomplishes I feel like this probably isn't possible being that the tokens obtained are meant to be used only with the API and not with the front end system. I hope that I am wrong though and there is a way to login to the front end using these tokens.
EDIT
Ok I am editing to hopefully make this more clear. Currently user's authenticate using the login() API method with their user/pass, we store this user/pass locally (not ideal). We then sync a subset of data that the users can access anytime within the app, being that it is a subset, we have a feature to "SSO" to the Salesforce.com front-end. This simply opens Salesforce.com in a web-view (UIWebView) using the URL https://ns8.salesforce.com/?pw=PASSWORD&un=username#example.com&startURL=/recordId. This will log us in to Salesforce.com and open the specified record.
Moving forward we want to use OAuth 2.0 with the web flow so that we aren't handling the user/pass and so that we do not have to deal with Security Tokens or opening specific IP ranges to allow login without a Security Token.
With that said, is there anyway to use the tokens/credentials received from the OAuth authentication to open Salesforce.com, automatically log the user in, and goto a specific record?
I may have mis-used "single sign on" before, but in a sense, this simulates an SSO from our App to Salesforce.com, in that our users can touch a single button within the app and be logged in to the Salesforce.com web interface.
When you request an OAuth token, you can specify what scope it has, options include api only (the original type of tokens), or other options which include the ability to use the token with the UI pages. (see the scope parameter detail in the help). One of the still missing peices is a way to bootstrap the UI with that token when all you can do is tell a browser/webview to goto a URL, but a widely used (but unsupported) way is via frontdoor.jsp, e.g. you'd open https://{instance}/secur/frontdoor.jsp?sid={the_Access_token}&retURL={optional_relative_url_to_open} remember to URLEncode the 2 values.
So I think you are saying your application uses the SFDC username and password to just authenticate to retrieve a record from SFDC to display in your app?
IF this is correct - which I think it is - then you could just use the standard Salesforce Single Sign On system to authenticate. There is a guide here which outlines the process of setting up a SAML SSO system with Pat Patterson writing an interesting feature on how the security system works here. He has also written a great blog post on DeveloperForce here about the nitty details of OAuth in general for Force.com and not just the SAML setup. I have used the OAuth system in an iPad app against SFDC and it works quickly and easily. I can't see why your system should be unable to use the protocol as you desire.
Direct access into Salesforce is a key benefit of SSO and definitely provided. I'm not sure where you read that SSO in Salesforce is API only. From the SSO PDF pbattisson linked for you:
With single sign-on, users only need to memorize a single password to
access both network resources or external applications and Salesforce.
When accessing Salesforce from inside the corporate network, users are
logged in seamlessly, without being prompted to enter a username or
password. When accessing Salesforce from outside the corporate
network, users' corporate network login works to log them in. With
fewer passwords to manage, system administrators receive fewer
requests to reset forgotten passwords.
OAuth 1 & 2 are both supported, though I'm a fan of OAuth 2 since 1 has really finicky additional steps involving the order of parameters and their encoding sequences. I recently wrote an Apex-Twitter integration and quickly realized it wasn't going to be as easy as Facebook, which uses OAuth 2.0.
But in your case it sounds like you just want to provide users with the ability to actually login to Salesforce and go to a specific landing page once authenticated. This is definitely doable.
Good luck!

Resources