Authentication for REST web services
Asked Answered
O

8

43

I'm starting to design a REST web service, and am unclear on the best approach to authentication. The service will allow individual users to access/manage their own data, so some type of user authentication is required. I've been looking at these options:

  • OAuth

OAuth seems to be more about authorisation instead of authentication. I plan to handle authorisation natively within the services, so am not looking for a solution to this. But, is OAuth also appropriate for authentication?

  • OpenID

OpenID certainly provides a solution for authentication, but this is geared more to allowing users to use their 3rd party credentials (Google, Yahoo, etc.) Though I would like to support this, this is not a primary concern for me, and I will definitely allow users to sign up with native credentials (email/password).

  • HTTP Basic authentication

This is simple to implement, but it's my understanding that this may not be a very secure method. Also, it would seem to require the exchange of credentials for each access, but I'd prefer that the user authenticate once and then continue access via a session token.

  • Custom authentication

Basically, roll my own login/token generation service, and require a valid token for access to all other resources (obviously, everything would be over SSL).


As well as creating the web services, I'll also be building a client (web) application which uses these services on behalf of a user, but I don't want the application to have to store user information/credentials/etc. So, something like this:

User (authenticates with email/password or 3rd party credentials) --> Web application (authenticates with application ID) --> Web services

And again, I want to allow others to build clients as well, so the middle tier can be any 3rd party application:

User (authenticates with email/password or 3rd party credentials) --> 3rd party application (authenticates with application ID) --> Web services

My very top-level requirements are:

  • Secure (obviously)
  • Native credentials
  • Support for 3rd party credentials (Google, Yahoo, LinkedIn, etc.)
  • Support multiple clients (web app, mobile app, 3rd party apps, etc.)
  • Client credentials (just an app ID?)
  • Login sessions that expire
  • Authorisation is NOT required

So, my question is, based on the above (please let me know if this is too vague), is there a "best" approach? Are OAuth or OpenID appropriate, or am I making this too complicated, and instead should just roll my own authentication?

EDIT:

I think I will need to implement the following:

1) Native credentials/tokens (HTTP basic auth over SSL?)

2) An OpenID "Relying Party" to allow my api to use OpenIDs hosted elsewhere (i.e., "support for 3rd party credentials")

3) An OAuth "Consumer" to allow my api to access 3rd party services (like accessing a user's LinkedIn profile).

4) An OpenID "Provider" to allow people to use the api's native IDs elsewhere (optional)

5) An OAuth "Provider" to allow 3rd party apps to access my api on users' behalf (optional)

Does this seem right, or am I making this more complicated than it needs to be?

Outherod answered 1/11, 2013 at 5:38 Comment(2)
recommand the article best practices for a pragmatic restful api , and also you could check how others implement it like githubStoker
"just roll my own authentication", never do this. Rolling your own authentication is the antithesis of software engineering best practices. People spend their lives working on solving the "How do we securely authenticate a user?" question.Preserve
U
13

You could consider JWT (JSON Web Token) see JWT draft rfc. It would certainly meet your security and session expiration requirements. However being a draft standard it's unlikely to be widely used right now, this could change soon since JWT are part of OAuth 2.0. JWT are easy to implement in most languages and there are plenty of libraries already. As a simple explanation, a JWT token consist of 3 parts , the header , body and signature. The header and body are json objects being basee64url encoded (alphabets differ from base64 by the 2 last characters) and then signed with HMAC256 (or another algorithm specified in the header) the RFC explain how to exactly generate this signature. You might want to check this online token generator.

JWT are http headers and query parameters friendly.

Upsweep answered 8/9, 2014 at 15:16 Comment(2)
This, and a number of the other answers here, each touch upon a piece of the puzzle. No single answer contains the whole answer though.Benbow
This is the best answer I have found so far. It advocates for using a standard (JWT) which has (as of 2016) existing libraries that implement it. Meaning, that someone wishing to leverage JWTs doesn't have to "roll their own" implementation.Preserve
P
11

One of the good option to consider is 'Shared key Authentication'. This is the type of authentication that Amazon web service and Windows Azure Storage service uses. We have used Shared Key Authentication in the REST service we developed. You can do a quick search in Google for 'Shared Key authentication' you will get lot of details.

I wrote one blog post here about this.

High level steps are:

  1. Client combines a set of unique data (elements) defined by the REST service.
  2. Sign this combined data using a key only known to client and REST service
  3. Send this signature to REST service as value for HTTP Header
  4. REST service compute the signature exactly the same way client did
  5. Compare signature sent by client with the one computed, if same assume its a valid request else deny the request
Pearle answered 21/2, 2014 at 2:1 Comment(1)
For reference: AWS Authenticating RequestsAstrophotography
O
7

My suggestion is to authenticate the first request and then set up a session token.

The front-end application would store the token and provide it with each subsequent request.

The token would have an expiration time. Token would expire if not used for certain period.

The token can be associated with the originating IP address for added security.

The token can be transmitted as cookie, or as one of query parameters in URL.

If the bother of SSL client authentication is acceptable, you could use mutual SSL authentication. Each client would have to be provisioned with a certificate which the server trusts. It can be the same certificate, or different certificates if you have to treat clients differently.

Oneirocritic answered 8/9, 2014 at 22:16 Comment(5)
@arunasr but what's the different of session token and username/pwd? they're all a unique id for a userHamal
@Hamal username/pwd is authentication credentials for a user. Session token is one-time expirable random data. Why you need a token when you can send user name/pwd every time? So that you don't have to store and transmit user credentials many times. User name and password are sensitive and should be protected by expensive hashing algorithms. You want to store and transmit them as little as possible, in case a third party gets hold of them. A session token is temporary and does not compromise security permanently even if intercepted.Oneirocritic
Upvoted since it explains a simple way for this to work without utilizing some huge and impenetrable 3rd party solution. As such, it allows people to understand what's going on behind the scenes. But I also have a question: isn't this mechanism essentially what you would do if you were to implement authentication for a GUI (presentation oriented) web application? So essentially you can use the same mechanism to secure both service-oriented (REST) and presentation-oriented (e.g. JSF) web applications?Yield
Also, this requires a back-end database for the REST application to keep the session tokens on the server-side, right? Or I guess they can be kept in the memory (e.g. in the servlet context using setAttribute) as well if the volume is low?Yield
Yes, you'd need to keep the session information somewhere accessible to all load-sharing servers, can keep in-memory if you don't want sessions to survive server restart and load-share. I don't think memory is a consideration, unless your sessions are extremely long.Oneirocritic
C
2

Based on your requirements I think OAuth 2.0 might actually be an interesting option. OAuth is indeed an authorization protocol, but it also Authenticates the client with an clientId and clientSecret. You can use the Client Credential Flow and chose not to include an Refresh Token, this way the user has an Access Token, which expires after a certain amount of time. And since OAuth is a widely used protocol their are already many client and server side libraries for you and your clients to use.

If you think OAuth is too heavy or too complicated for your application I would probably stick with Basic Authentication over HTTPS. But as I also stated in another answer to a similar question, I would never invent my own authentication mechanism.

For more info you can also have a look at the other answer I've given earlier to a similar question: https://mcmap.net/q/391062/-rest-service-authentication

Cheap answered 1/11, 2013 at 13:42 Comment(1)
Thanks for your response Jos. However, don't I need to implement both OAuth and OpenID? It seems to me that OpenID is required for my third requirement "Support for 3rd party credentials", is that not true?Outherod
S
1

You could use HTTP Basic Auth, where the transfered password is not actually a password but a token, that the client acquired on a different resource request, where he/she/it had to provide his/her/its password once and only once (maybe even over a different channel). This does not secure man-in-the-middle attacks (as there's not message signing), but the idea is, that you can always require the client to generate a dynamic token somehow (i.e. on an auth service of your own) and then have it send that token as a password replacement, so the actual password is not constantly transfered over the wire. Yes, this appears like one of the "custom auth solutions", but it actually isn't because you can impose what ever rules you want on the token-password, like using a signature token as the password that is session-bound or recomputed on every request (without sharing of any secrets) so the server can validate the message - what ever your needs are. the idea is to send the validating token as the "password" of the HTTP Basic Auth request and not rely on more complicated protocols, while not ruling those out (to your option).

Statistical answered 18/3, 2014 at 23:38 Comment(0)
G
1

I've implemented and released as open source a basic service which allows authentication, it can easily be changed to allow 3-tuples login if needed. It is about 2 years old and written in Java over Spring so you might want to reconsider the technology, but it works and you can get the basic idea of how it's done. Find it here on google, or follow my blog posts about it. Note that the app no longer loads on cloudbees but if you set it up on your account all should be ok.

Gandhiism answered 6/9, 2014 at 19:20 Comment(0)
A
0

I suggest using Spring Boot for your RESTful web services because then you can use their Spring Security to implement your own custom authentication based on their templates. You can implement you own custom authentication by extending or implementing their base security classes and interfaces respectively. You also have an option to incorporate those other auth mechanism you've listed in Spring Boot if needed.

Archibald answered 27/7, 2017 at 20:30 Comment(0)
I
0

OAuth 2.0 is the way to go if you only need authorization.You could use OpenID Connect, which provides authentication and supports OAuth2.0 for authorization. For OepnID Connect, there are many certified products available if you need to setup service yourself, there are many online services available too.

Intracardiac answered 28/8, 2019 at 8:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.