17

Overview

I am currently in the process of creating an API for an image sharing app that will run on the web and sometime in the future, on mobile. I understood the logical parts of API building, but I'm still struggling to meet my own requirements for the authentication part.

So, my API must be accessible to the world: those with guest access (non logged in people can upload, for example), and also to registered users. So when a registered user uploads, I obviously want the user information to be sent along with the request and to attach that user information to the uploaded image via foreign keys in my database.


Authentication via OAuth2 - Implementation

I have understood that OAuth2 is the way to go when it comes to API authentication, so I am going to implement this one, but I'm really struggling to wrap my head around on how to handle my situation. I thought of using the client credentials grant and generating only one set of credentials for my web app, and having it send requests to the API with its client secret to obtain the access token and let users do stuff. The user registration process itself would be handled with this grant.

But what about when the user is registered and logged in? How do I handle authentication now? Would this require another grant to take over? I was thinking of doing some authorization process during user signin, to generate a new access token. Is this approach wrong?


What I need help with

I need your input on how to handle the authentication flow correctly for my case. This two-way authentication process might not be what I need, but it is the way I've understood it. I would highly appreciate your support.

Community
  • 1
  • 1
aborted
  • 4,481
  • 14
  • 69
  • 132
  • What kind of client are you building for your API? Is it a JavaScript application calling your API from the browser? Or does it run on the server? – MvdD Jun 05 '16 at 03:09
  • @MvdD It will be a Javascript web app calling the API, yes. – aborted Jun 05 '16 at 09:09
  • @Aborted to clarify, when you say "my web app" you're talking about your javascript application running in the browser? – kag0 Jun 11 '16 at 05:52
  • @kag0 Yes, I'm talking about a ReactJS website, fully made in Javascript. – aborted Jun 11 '16 at 15:00
  • @Dugi - Just curious: What solution did you wind up using? – anon Jun 13 '19 at 17:25

3 Answers3

9

Your approach seems workable.

Oauth2 has 4 main parts:

  • Resource Server (your API)
  • Resource Owner (end user who has data on the resource server)
  • Authorization Server (gets authorization and issues tokens)
  • Client (your web app - and future apps)

Bear in mind with the Client Credentials grant, the token you are issued probably won't have any user context. So if your API endpoints rely on a user identifier / resource owner being contained within the token, then you will need to code around that for this type of token.

If you do need the token to have some resource owner context for your API, and your web application happens to be your identity provider, then then you could use the resource owner password grant which will give you a token and refresh token in the context of a resource owner/user.

The Authorization code grant is fine providing your future API consumers are web apps (i.e. run on servers). If you plan to allow mobile/native apps to use your API then you should consider allowing the Implicit Grant in your Authorization Server.

If your API doesn't have end users and each client has varying access to the API depending on what app it is, then you can use the client-credentials grant and use scopes to limit the API access.

EDIT

So my API must be accessible to the world with guest access (non logged in people can upload, for example) and to registered users. So when a registered user uploads, I obviously want the user to be sent along with the request and attach that user to the uploaded image

To achieve this your API upload endpoint could process Oauth2.0 Bearer tokens but not be dependent on them. e.g. the endpoint could be used by anyone, and those who supply an access token in the headers will have their upload associated with their user context obtained by the API from within the token. You could then make other endpoints dependent on the token if required.

EDIT based on comments

the registration process itself will use the client credentials grant, correct?

I don't think the registration process itself should be a resource protected by Oauth. Ideally registration should be handled by your identity provider (e.g. google, facebook or your own user membership database). One of the plus things about Oauth2.0 is that it removes the need for APIs to have to do user admin stuff.

Community
  • 1
  • 1
iandayman
  • 4,357
  • 31
  • 38
  • Hey, thanks for your response. My API will have quite some endpoints that do not require any user (they can do things as guests), so in this case I think the client credentials grant would do the job. However, when the user is registered (the registration process itself will use the client credentials grant, correct?) then obviously the same "guest" actions must no include a user context. This part is confusing me a little. How would I go about tackling this issue? – aborted Jun 02 '16 at 16:54
  • How do you handle token expiration using password grant, when the token is saved in LocalStorage for further Web API requests? – Legends Jun 08 '16 at 20:50
  • Password grant will give you an access token. That token should contain details on issue / expiry time, so you can calculate if it's expired, or close to expiration, and you can use your refresh token to get a new one. – iandayman Jun 08 '16 at 21:34
  • If I got you right, I have to remember on the client when the token will expire and close to expiration make a call to my web app, which has stored a user related refresh token and on the basis of this refresh token the web app requests a new token from the OAuth server and my web app then sends the new token back to the User Agent (Browser) for further web api calls, right? – Legends Jun 09 '16 at 13:38
  • @Legends I'd recommend asking a separate question putting in details of your specific scenario. Ordinarily, your web app wouldn't send a token back to the browser but much more detail needed to give proper answer. – iandayman Jun 09 '16 at 17:30
  • @iandayman This question is closely related to the current one, actually it goes into a bit more detail... Discussions always help. How often I have found solutions in comments... – Legends Jun 09 '16 at 17:53
  • @Legends you probably should create your own question, but you can read about refresh tokens [here](https://tools.ietf.org/html/rfc6749#section-1.5) – kag0 Jun 11 '16 at 05:59
  • @kag0 This link does not answer the question above – Legends Jun 11 '16 at 10:33
  • @iandayman To sum this up, which grant do you think is the best to use in my case? I still didn't get that part. Also, could you please explain the registration process itself for an user to me as well? Thank you, your answer is really helpful. – aborted Jun 11 '16 at 15:15
  • @Aborted I've added another answer which addresses that more specifically. – kag0 Jun 11 '16 at 17:55
  • @Aborted I'd use the implicit grant if your app is fully javascript running in a browser – iandayman Jun 11 '16 at 19:55
  • @iandayman that might not be the case in the long term though. As I said, I might go for mobile apps in the future and also let users create their own "apps" and get an API key etc. Would this work in the long term? Can I have multiple grants? – aborted Jun 11 '16 at 20:05
  • yes you can have multiple grants: mobile apps - implicit grant; web apps - auth code grant is how I would aim to implement it – iandayman Jun 11 '16 at 20:16
8

You don't really need oauth to authenticate to your own API.

OAuth2 is usefull if you want another application to access your API.

Let me explain a little bit how OAuth2 works:

  • A Client (application) wants to use your API so you give him Client credentials (client_token and client_secret). And you set in your database a set of redirect locations that the client can use.
  • The Client needs the user authorization for him to use your API in the user's behalf. So, the client sends the user to a url on your site (with the client_token, scope the client needs [you define the meaning of the different scopes], a redirect uri and a response_type [oauth2 defines different response_type but let's focus on 'code'])
  • The user logs into your site and accepts to give access to the client to your API on the user's behalf. When the user accepts this you'll generate a grant (the grant contains info of the user, the credentials requested [scope] and the client who can 'claim' the granted access).
  • The user is then redirected to the redirect_uri that the client requested (When the client sent the user to your auth site) and in the URL parameters you'll include the grant code (it's just an id).
  • At this stage, the client will make a request to your API providing the grant code, his own client_token, his client_secret and the grant_type (authorization_code) and he will get on the response the following: an authorization_token, refresh_token, token_type (for this case, Bearer), expires_in (expiration time in seconds) and the scope.
  • After all this the client will be able to make requests to your API on the user's behalf using the access_token privided until the token expires. Once the token expires the client will have to request for a new access_token using the refresh_token (instead of the authorization code).
Juanín
  • 841
  • 6
  • 16
  • I plan to let my users register applications on my web app in the future and I understand that OAuth2 is the perfect way to handle that. So with that in mind, I thought that using OAuth2 from the beginning to authenticate my own app would be wiser, since one day I'm gonna end up implementing it anyway. My API will be written in Laravel and I'm unsure if I can attach multiple authentication methods to my application, so I wanted to make a right pick in the beginning and go with that long term. – aborted Jun 11 '16 at 15:04
  • If you are going to let users register applications on your WEB then you are on the right track. I've never used Laravel before but I strongly recommend you to use a third party library to implement OAuth2 because it's very complex to implement from the server side. – Juanín Jun 13 '16 at 05:14
7

iandayman's answer has lots of good information, but I think a narrower more specific answer might help you.

So for starters, the client credentials grant is not for you. If we look at the OAuth2 spec, the client credentials grant is for

when the authorization scope is limited to the protected resources under the control of the client ... when the client is acting on its own behalf

This is not right for you for two reasons.
Firstly there are no protected resources under the control of your client. All resources you are accessing are either unprotected (non-logged in people uploading) or are under the control of an end user. Further, you cannot keep secrets (such as the client secret) in the browser; any user of your application could just use the developer tools of the browser to view and compromise the secret.
Secondly, as I mentioned, the client is never acting on it's own behalf. It's always acting on behalf of a user who may or may not be logged in.

You want the resource owner password credentials grant.
When a user is not logged in (like you mentioned for uploads) you just have no authorization. When a user logs in, you send their credentials to the authorization server. If the password matches the username, the authorization server makes a token and persists a mapping from that token to the user and returns the token. Then every time your client makes another request for a logged in user, you put that token in the Authorization header. On the back end you say "if there is a token in the authorization header, find out which user it corresponds to, and associate them with this upload (or check if they're allowed to upload at all)".

How does user registration work? Simple, you post some user object like

name: jim beam
username: jimb
password: correct horse battery staple

to your user creation endpoint (POST /users or something). You generate a salt and hash the password, and then store the user's information along with the salt and hash in the database. There is no authorization on this endpoint whatsoever.

Hopefully this is more what you are looking for.

Community
  • 1
  • 1
kag0
  • 5,624
  • 7
  • 34
  • 67
  • Is it safe to have no authorization at all? Is there any potential abuse possible from this? My question might sound absurd and funny, but I'm genuinely asking if there's something that could go wrong? Same question for the registration endpoint. – aborted Jun 11 '16 at 19:31
  • @Aborted it's only safe to have no authorization for unprotected resources(things anyone can do). Those are going to be things like the javascript application itself, public profiles, media, etc. For things which are protected(private images, modifying users settings, etc) you will want to ensure the person calling the endpoint is authorized. The registration endpoint doesn't need to be controlled (assuming anyone can register). Your potential issues here are people using more of those public resources than you can handle. Those aren't strictly security issues, but rather logic and scaling. – kag0 Jun 12 '16 at 02:17
  • 1
    The password grant is fine for use by your app only but you *would not* use this grant type for apps not developed by you but using your API. If you plan to expose your API publicly, please look at other grant types for use by them. – iandayman Jun 12 '16 at 09:07
  • @kag0 - Now that it's been a few years out, would you say that ROPC is still a good choice? For example, there's this article by one of the main devs of Identity Server: https://www.scottbrady91.com/OAuth/Why-the-Resource-Owner-Password-Credentials-Grant-Type-is-not-Authentication-nor-Suitable-for-Modern-Applications – anon Jun 13 '19 at 17:35
  • 1
    @anon I agree with pretty much everything he has in that article. But ROPC is still the right grant in this case. One thing that is important to understand is that OAuth is an authoriZation protocol, but the question is about how to apply it for autheNtication on his own app. The article mentions this as well "If you own the authorization server as well as the client application then this is a little more forgivable". I would also advise going off-spec and adding FIDO/U2F/webauthn for user accounts (this will ensure only your client application can use password credentials). – kag0 Jun 14 '19 at 00:52