
Ask HN: Rest api authorization - vskr
I am working on service which exposes REST API.<p>What is the best way to implement authorization for  incoming requests.<p>* Identify who is making the request. Can we use api key for this.<p>* Make sure this REST api can be used just as easily using curl. I am not sure how to do this, as I dn&#x27;t think exposing API key is a good idea. I can ask clients to hash request params with api key, but that makes it non-trivial to use with curl.<p>What are the standard practices, and what are the trade offs.<p>Please be kind and helpful. If I said anything wrong, please correct me instead of flagging this.<p>Any help would be appreciated. Glad to provide any info that makes it useful to answer
======
jaypaulynice
OAuth2 is the way to go for REST services especially if you plan to let users
give other apps/developers access without giving out their passwords. For
better security, you want to decouple the authentication server from your web
application (2 separate databases at least)

The authentication server stores email/username, encrypted password, and
roles. To access the web app, you first get a token from the authentication
server by exchanging a client_id, secret, username, password and grant type.
The token is used whenever you want to make a request to the web app. The
authentication server has an endpoint that lets the web app check to see if
the token is valid and what roles the client has.

The token is only valid for a short time and can be revoked. To know who is
making the request, you associate the username/email from the authentication
server with a user object on the web application so you can look up based on
username/email.

It's not worth doing this from scratch as there are plenty of open source
implementations out there already like Spring Security Oauth2 and other
libraries for Django/python, but they all require some reading to get started.

I've used Spring Security Oauth2, but it's not very well documented. I've
thought about open sourcing my work, but not sure yet.

~~~
aprdm
Isn't having two distinct servers one for auth and one for business logic too
much for small start ups / services?

I can see the benefit when scaling but starting with this design seems to be a
little bit of an overkill / harder to manage? Care to elaborate?

Cheers

~~~
jaypaulynice
For a quick prototype, I think it's ok to have both in same server/database,
but beyond a prototype you should think about security and scaling.
Redesigning later can be a nightmare and most people end up not doing it
instead just leaving what they already have.

The good thing with 2 separate servers is that if one is compromised, then the
bad actor doesn't get access to all your data. Also you could use any
language/database that makes sense for your auth server or services.

------
RandomOpinion
I've seen people use JWT
([https://jwt.io/introduction/](https://jwt.io/introduction/)) for REST API
auth. There are a variety of libraries that implement it and it's fairly
simple to use.

Since it's just another HTTP header field, cURL can include it easily enough.
Granted, you'll have to generate the encoded token externally but you would
have had to do that with any other auth mechanism anyway.

------
atmosx
HMAC for auth to avoid having the key exposed at every request.

For the rest: [http://www.javabeat.net/rest-api-best-
practices/](http://www.javabeat.net/rest-api-best-practices/)

And documentation:
[https://github.com/Rebilly/ReDoc/blob/master/README.md](https://github.com/Rebilly/ReDoc/blob/master/README.md)

There many more comprehensive resources about sane API design (use HATEOAS,
pagination, etc.) but you don't have to implement everything from v1

ps. SSL goes without saying even if it's a public API

------
johnjuuljensen
Use basic authentication and ssl. The users credentials will be encrypted and
the API will be easily consumable from cli and from browsers.

~~~
romanovcode
Best answer here. KISS is the way to go.

------
tom_b
I have semi-copied what AWS did a couple of years ago. Each api consumer has
an api key with a private key known to the consumer and server-side. Requests
are SSL only and are signed with the private key by the consumer side
(including any parameters and a client-side timestamp). For example, using
curl:

    
    
      #!/bin/bash
    
      TS=$(date +"%s000")
    
      SIG=$(echo -ne 'GET\nhttps://servername:port/api/resources?api_id=1&ts='$TS | openssl dgst -sha256 -hmac "secret-key" -binary | xxd -p -c 32)
    
      curl -H "Content-type: application/vnd.collection+json" 'https://servername:port/api/resources?api_id=1&ts='$TS'&signature='$SIG
    

I have consumers of the api using node.js and Java as app dev languages with
various http client libraries successfully. The actual server-side api is
written with Clojure using the Liberator library (highly enjoyed working with
this combo).

Server-side uses the api_id to check the signature using the shared secretkey.
(Edit to clarify). There are two timestamps flying around here. One is a
timestamp from the client call to the api ($TS above). This timestamp has to
be "close" \- completely configurable on server-side - to the server-side time
or the request is not valid. A little more subtle is that each resource has a
timestamp that is the last time the resource was changed server-side. As part
of the authorization for the api call to change a resource, it has to be make
the call to the api with the resource's most current value for that timestamp
to succeed. This is a little goofy logically.

This approach works very well when you have a requirement to allow multiple
different apps to call the api rather than say, allowing _users_ to call the
api from their browser. I don't have a case where users are in a web browser
app that directly calls the REST api.

By the way, if you are using SSL, you don't have to worry about the api_id
being exposed in either the query parameters or the request headers.

------
rashkov
I really wish this topic got discussed more because there don't seem to be a
lot of great options.

I personally use an OAuth 2 library using the "Resource Owner Password
Credentials Grant" which is where you POST a username and password, and you
get back a session token. OAuth 2 has a few other types of grant flows but
they don't make as much sense for REST only APIs.

The downside of this password grant flow is that anyone can create a client to
work against your API, and potentially they can steal passwords in a man-in-
the-middle fashion. One way to prevent this is to give your "trusted clients"
a secret token, and then verify that token before issuing a session.

However you can't hide a secret in browser-side JavaScript and even mobile
apps can be be decompiled, so this isn't perfect either. Some devices provide
a hardware enclave to store your secrets in, but most don't.

Another weakness is that if your SSL breaks, then you're essentially sending
the passwords in clear text over the wire. Another commenter mentioned HMAC
encryption of the password which might help. That this isn't recommended by
oauth is concerning. It's not the best standard and password grant is its
weakest form. [Edit: now that I think about it, HMAC requires having another
shared secret between your API and your client. Storing secrets on the client
is difficult, as discussed in the previous paragraph]

JWT seems new and not too widely used but worth looking into. It has its own
downsides like some difficulty with revoking sessions from the server side,
but there are workarounds for this.

I wish there was an industry standard answer that was secure and we could all
be happy with but there doesn't seem to be much interest in the topic, going
by how rarely it gets discussed. Best of luck!

~~~
rashkov
By the way, you may want to have a look at Auth0. They run the jwt.io
informational site. Their services look interesting. Their claim is that you
can use their service and their SDKs to add authentication to your service
super easily.

~~~
atmosx
JWT looks very interesting, thanks for bringing this up.

JWT website: [https://jwt.io/introduction/](https://jwt.io/introduction/)

------
weitzj
Be aware of JWT when it comes to Login/Logout behavior. JWT is not a good fit
for user facing login unless you have a session ID on the server. But then you
could as well use Cookies and a sessionID.

So I would do a Login via Basic Auth or a Form post or a JSON post with
username/password and then get some kind of token/sessionID/JWT which expires
on the server side. The token might be encrypted on the server side with a
secret only known to the server, never the client. Use the sessionStore to
implement a proper session expiration scheme.

------
nickmancol
Maybe you can take a look of an api gateway like apiman which can leverage the
auth & authz to keycloak, or perhaps kong may be the one.

------
aprdm
I've used mostly JWT, the tokens with a short TTL which makes it easier to
control revoking/banning in the backend.

It is really simple to set up. In the frontend it's pretty straight forward to
implement logout and other common behaviors even if the token is still valid
because of the TTL.

------
amingilani
Jwts are very straightforward to use, and you can get up and running with
Auth0 for free in a few minutes.

They do have a 700 DAU limit, but when you need to, you can always implement
your own JWT server

------
quickben
Look into identity server 4. YouTube some videos about it and it should get
you going. The rest is just picking what's popular for your platform/language.

------
emmelaich
Regarding cURL, note that Firefox and Chrome allow you to copy the request as
a Curl command with their Developer Tools. (F12/inspect...)

------
diggernaut
you can (and should :)) use it (token auth) with ssl. To get SSL is not a
problem today, and will cost you nothing if you use letsencrypt.org

