I'm developing a REST API with a tightly coupled SPA as the only client of the mentioned REST API.
Let's say the SPA is available at myservice.com and api is under myservice.com/api. They're basically one service, just split at code level, and deployed at different root paths.
What I'm using for security right now is OAuth2 with ROPC (username/password) grant type.
Here comes the problem. I keep reading everywhere that ROPC is not secure and should not be used. What should I use then?
My REST API acts as an authorization server but it doesn't have any web interface itself. So any flow involving redirect doesn't really make sense. The SPA and API are so tightly coupled that for an end user they're basically one application. There's no 3rd party.
I could add simple login form to the API available at let's say myservice.com/login. But I'm struggling to see the difference that would make.
Security in this application is very important.
Here are my questions:
Is using ROPC really dangerous in this scenario?
What would be the perfect way for authentication and authorization?
Or maybe OAuth2 is completely redundant without a third party?
Technologies used:
Server: Spring Boot
Is using ROPC really dangerous in this scenario?
No, not really providing:
a) You don't store a user's password - maybe only use it to get the initial access and refresh token - although that could be tricky with an SPA.
b) Your SPA client and the resource API are owned by you, so you don't need the user to consent to specific scoped access for the SPA.
What would be the perfect way for authentication and authorization?
It depends on lots of things. Not enough info to try to answer that. OAuth2.0 (with a probably implemented Authorisation server) is a pretty good way for the example you have here.
Or maybe OAuth2 is completely redundant without a third party?
If other applications will use your API in time then OAuth2.0 is probably a good call. Otherwise you could probably use a more simple solution e.g. session cookies as all sits on same domain.
Answer to this can be taken out from OAuth 2.0 specification (RFC6749) itself. It define when ROPC grant is suitable for,
4.3. Resource Owner Password Credentials Grant
The resource owner password credentials grant type is suitable in
cases where the resource owner has a trust relationship with the
client, such as the device operating system or a highly privileged
application. The authorization server should take special care when
enabling this grant type and only allow it when other flows are not
viabl.
According to your explanation, you have tight coupling with SPA and backend. Also you have both authorization server and resource server built as one. This is completely acceptable implementation.
The authorization server
may be the same server as the resource server or a separate entity.
So what matter now is to clear out why you use OAuth 2.0 in your scenario.
If you are using OAuth 2.0 to obtain tokens, maintain them as defined through OAuth 2.0 specification, then this is completely oaky. But if you are doing this to follow a trend, think twice.
OAuth 2.0 implementation comes with it's own complexity. You have to maintain user identities, maintain tokens and renew them. You are building a complete authorization server by yourself. But this also have some advantages as well.
For example, same authorization server can be used to issue token for future integrations/secondary app. IMO, usage of OAuth 2.0 make integrations easy as it define a protocol for issuing tokens, renew and revoke them.! But in such integration scenario, may be you will require to use a different grant. Still, your API being authorized on token, you only need to worry about how new integration/application obtain tokens. This is better than using authenticated sessions
Going back to your questions,
Q : Is using ROPC really dangerous in this scenario?
As explained, if there is a correct trust relationship between client and authorization server, then it is fine. But be mindful about complexity comes with having a authorization server.
Q : What would be the perfect way for authentication and authorization?
OAuth 2.0 is for authorization. You obtain access token and use them to authorize against your protected APIs. From APIs you do a token validation to detect correct access levels/permissions.
If you want authenticaiton, then you must use OpenID Connect. It is a protocol extended from OAuth 2.0. And allows your application to authenticate the end user based on ID Token. You can use ROPC grant to obtain an ID token.!
Q : Or maybe OAuth2 is completely redundant without a third party?
Not necessarily. It allows you to design your APIs in a modern, standard way. Who know what future hold (again the integration scenario). Following a protocol allows that easy.
Only advice, follow specifications closely. Do not invent your own protocol/adaptation. It makes things harder to maintain.
Related
Background information: The REST API will be used by a web application and server
We are thinking to have the code flow for the web application and client credential flow for the server part (machine to machine authentication). As tool, we will be using keycloak
But the problem is now that we are not sure if it is possible to have two oauth flow on one REST API.
Is it possible to have two oauth flow for one REST API?
And if it's possible, how can you do it?
This is fine. In both cases the clients will perform OAuth flows using Keycloak, and these can be completely different. Your API needs to knows nothing about how clients authenticated, and in both cases receives a JWT access token.
The two different clients will not always call the same API endpoints. They are likely to use different scopes and claims, and your API authorization design needs to deal with this. The server client will not provide a user identity via a subject claim, whereas the web app will.
The way to cope with these differences is usually to design a ClaimsPrincipal during JWT processing, then apply authorization rules based on the data received within the API's business logic.
In some cases, operations designed for the server client should not be callable from the web app, and vice versa. Scopes and claims will enable you to achieve this.
EXAMPLE API
Maybe have a look at this code sample of mine and the blog post. The key point is that the API performs these steps. If you do the same steps you will be in good shape:
Validates JWT access tokens
Builds a claims principal
Enforces scopes for each operation
Uses the claims principal to apply business authorization rules
My API does some slightly advanced stuff like look up extra claims, which you can ignore. Note that the API doesn't know or care which flow clients used - there could be 5 different flows. The API's job is just to work with scopes and claims.
I have a Django backend which will be served as my API endpoints. Users are identified by username and password and have some extra information and should be able to consume my same API, so I want to grant tokens for them.
How to create API keys for them to use? (Would a uuid serve a good purpose here?)
How to generate tokens for them? (I could imagine that some way like sha256(api_key + password + some_salt), where salt is some timestamp object would do the trick and also help in expiration)
How to generate a refresh token to be used for refreshing an expired token? (I have no idea here)
I took a look at Oauth 2.0 but TBH I could not figure it out completely and it is overly complicated as my API server will also be my authentication server.
I would not recommend to build your own authentication scheme, nor deploy your own cryptographic functions. Nowadays the industry standard for API authentication and authorization is OAuth 2.0, it provides all the requirements you've described in a robust but rather simple to implement solution.
If the mentioned application does not require any of the OAuth 2.0 authorization concepts, using OpenID Connect is certainly a great approach. OpenID Connect is a protocol built on top of OAuth 2.0:
It allows Clients to verify the identity of the End-User based on the
authentication performed by an Authorization Server, as well as to
obtain basic profile information about the End-User in an
interoperable and REST-like manner.
API authentication technologies are widely available in different forms, even SAML 2.0 can be implemented for such scenarios (more infrastructure is required), anyhow for what you have described, OpenID Connect certainly cover all requirements.
The easiest way to solve this is a classical Session-Cookie, Django directly offers this functionality.
If you do not want to hold state on the server side you may look into JSON Web Tokens.
I'm trying to build a proof of concept using Angular 5 and Symfony 4. I need the backend to be decoupled from the frontend so that I can focus on using JS entirely for the frontend and to be able to escalate to apps and other types of clients.
For this reason I'm building a RESTful API on Symfony. I've managed to send credentials from the front to the back... and that's pretty much what I've managed to do because I don't know how to proceed next.
Symfony should take the login data, somehow call a service to validate, and respond properly to the frontend. What is the most secure way of doing this? I've read a lot about JWT and how it's unfitting for this use case, and apparently OAuth2 is good only for authorization and not authentication unless you use OpenId Connect. I've read that the simplest approach is to create a session ID + a CSRF token and store it in a cookie (I don't care if this breaks statelessness, being certain that the system is secure is more important). I think the latter can be done with a bundle transparently but I don't know how to do the former.
In fact I'm entirely lost. I don't know where to begin, I've been stuck for days and the task seems just too overwhelming. I was even suggested to use Laravel instead, but I don't even know where to get started and this is legit the first time I try to implement a REST API, so it's quite daunting.
What am I supposed to do here?
EDIT: Here are some of the reasons why I'm schewing JWT for authentication.
Wanting to use JWT instead of OpenID Connect is like wanting to use a SAML assertion without the SAML protocol.1
(This one could lead me to use OpenID Connect as my solution)
Stateless JWT tokens cannot be invalidated or updated, and will introduce either size issues or security issues depending on where you store them. Stateful JWT tokens are functionally the same as session cookies, but without the battle-tested and well-reviewed implementations or client support.2
Unfortunately, an attacker can abuse this. If a server is expecting a token signed with RSA, but actually receives a token signed with HMAC, it will think the public key is actually an HMAC secret key.3
This isn't just an implementation bug, this is the result of a failed standard that shouldn't be relied on for security. If you adhere to the standard, you must process and "understand" the header. You are explicitly forbidden, by the standard, to just disregard the header that an attacker provides.4
The linked websites have more information as of why JWT is not secure.
Now I am implementing a similar task, only on the frontend Vue.js. On the backend I use Symphony 4 + API Platform. At the moment, I implement secure access to the API through JWT Authentication, this method is recommended.
Links for your topic:
https://github.com/lexik/LexikJWTAuthenticationBundle
https://gist.github.com/lologhi/7b6e475a2c03df48bcdd
https://github.com/knpuniversity/oauth2-client-bundle
If you want fast setup, then use FOSUserBundle Integration, but API Platform not recomendated his method.
Or use this method at Symfony4: -
https://symfony.com/doc/current/security/api_key_authentication.html
https://symfony.com/doc/current/security/guard_authentication.html
What is the best way to authenticate clients that uses my private REST API? I will not be opening this to outside public. Is there a easy and secure way to do this?
Note: I'm running SSL already. I've looked at HTTP Basic Auth over SSL, but I don't want to ask the user to send the password every time, and it seems not good practice to store the user/pass in the client to be send automatically.
Any ideas or best practices?
You can use the most adopted authentication approach which is OAuth
You select the best suited one between OAuth 1.0a and OAuth 2.0
Here is a comparison between the above two ways : How is OAuth 2 different from OAuth 1?
There are several levels to implement security / authentication in RESTful services:
Basic authentication. Username and password are sent for each call within the Authentication header encoded with based 64.
Token-based authentication. This implies a dedicated authentication resource that will provide temporary token based on credentials. Once received there is no need to use again credentials since this resource also gives a refresh token to a new authentication token when the previous expired.
OAuth2. It provides different flows according to the use cases. It allows to let the end user to authenticate through a third-part provider (google, facebook, ...). The application doesn't manage username / password (and even know the password). The drawback of this technology is that it provides high-level hints and it's not so simple to implement.
Here are some links that could provide you some additional hints:
Implementing authentication with tokens for RESTful applications - https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/
OAuth2 flows - http://www.bubblecode.net/en/2013/03/10/understanding-oauth2/
Hope it helps you,
Thierry
We are in the process of planning an iOS application in which users will need to be authenticated and authorized before they can interact with data provided by a Symfony2 web service.
Authorization will be implemented with ACLs, it's the authentication I'm not sure about.
From what I found in my research, there are a few ways to achieve the authentication part, but since there won't be any third parties accessing the data it sounds like basic HTTP authentication paired with a SSL certificate is the way to go. Is this correct?
Additionally, is a simple username and password secure enough, or is it better to add some sort of API key for identification?
If a key is needed and considering our users will be part of a group, should a key be bound to every user individually or to the group as a whole?
Finally, and slightly off topic, Symfony2 has FOSRestBundle, is there a defacto REST library for iOS?
For securing REST applications in symfony the FOSOAuthServerBundle is very useful. With it you can implement easy OAuth authentication for your app. OAuth is de facto standard for securing REST web services.
As https/ssl is pretty secure you can go for basic http authentication and/or the api key solution.
Wether to use a key and/or username/password is your personal choice.
If somehow requests can be catched in cleartext either one is compromised.
Keys in addition to username/password auth can have the advantage of seperating i.e. user contingents.
Basic http authentication is mostly used, therefore the chance of your client having already available methods to integrate it from his side are high.
You should always give out unique keys or username/passwords to every user in order to be able to log who did exactly what.
I'm not that much into iOS, sorry.