1

I'm building a web REST API. Users must be able to authenticate themselves to this API.

I don't know ahead of time which clients will want to use the API. I want to allow for the possibility of anyone creating their own client, like a custom web frontend application or a native mobile app, for example. I don't need to support confidential clients (clients with client secrets) but not sure if that matters. My purpose in using OAuth is that it provides a mechanism for authorizing these clients to acts on behalf of users, without the clients ever seeing a user's password. It seems like OAuth fits well for this.

However, in order to use OAuth, some client must first authenticate with username and password, in order to be able to provide consent to other clients (you can't provide consent without authenticating as the consenting user after all). So I must have some way for a client to authenticate via username and password. Otherwise there is no way to start the OAuth flow in the first place.

So if that is the case, why not use the OAuth password grant type? I know that it is deprecated, but the only alternative I see is to implement my own custom login API route which would essentially work in exactly the same way. So I fail to see how the fact that I am or am not using it has any impact on the security of the system.

The password grant type does not seem to support 2-factor authentication, which is an issue. But I'd need to support it in some custom fashion in my login form anyway, so I still see it as better to use OAuth with some kind of 2FA extension on top, rather than a fully-custom login flow.

Am I misunderstanding something or is OAuth perhaps not a good fit for this use case somehow? Is there a better way to achieve what I want?

10
  • AFAIK consent is not required to use OAuth. Consent is used by your auth system to decide whether user can or cannot login though the given client as an additional security measure. So your own web-site can use your own OAuth system without any consent from users. Commented Sep 3 at 12:14
  • Not sure I understand what you mean by that, maybe you can be more specific? How can "my own website" (I suppose my own frontend application) use the OAuth system (say, the authorization code flow) if it doesn't somehow authenticate as the user first, by using a username and password to login? I mean somehow during the OAuth flow, a user must type their username and password (or have done so before) and agree to allow the requesting client to act on their behalf. That is at least how I understand it. My question is, if the user must type their password to login, why not use the password grant?
    – SorteKanin
    Commented Sep 3 at 12:22
  • Indeed, it looks like I misunderstood your problem, sorry. But it is always a bad idea to transfer a plain password over the wire as it is done in password grant query. Commented Sep 3 at 12:33
  • "But it is always a bad idea to transfer a plain password over the wire as it is done in password grant query" - but this is done all the time for normal username and password login forms, no? How can this be a bad idea?
    – SorteKanin
    Commented Sep 3 at 14:37
  • @SorteKanin: It's not a bad idea to transmit the password (assuming TLS is used, of course). What is a bad idea is to unnecessarily share the password with a client when only the authorization server needs to see it.
    – Ja1024
    Commented Sep 3 at 15:51

2 Answers 2

2

The mistake you're making is that you assume the component which asks for the user credentials is yet another OAuth client, which would indeed lead to a conundrum where one client has to use the Password grant to then allow passwordless authorization/authentication for the other clients.

However, the authentication component is not an OAuth client. It's a part of the authorization server.

For example, if the Authorization Code Grant type is used, then the client who wants access to a resource first redirects the resource owner to the authorization server. The authorization server then somehow authenticates the resource owner and asks whether resource access should be granted to the client. How exactly the authentication procedure looks like isn't defined in OAuth – it could be a classical log-in form asking for a username/e-mail and a password, it could be a page which triggers TLS client certificate authentication, it could be some 2FA solution. This is entirely up to you. After the authorization server has both authenticated the user and established consent, it hands over an authorization code to the client through a redirect.

When you understand that resource owner authentication isn't the job of an OAuth client, it should be clear that no client ever needs to see the owner's credentials. The Resource Owner Password Credentials Grant type is therefore unnecessary in most cases and should be avoided, because it turns the client into an additional entity which knows the resource owner credentials.

Edit: Since it still doesn't seem to be clear why your approach is a bad idea and doesn't really work, I'll try to go into more details.

If I understand you correctly, you envision the following workflow.

+------+
| user | 
+------+
 |
sends password through log-in form
 |
 v
+----------------------------+
| SPA acting as OAuth client |
+----------------------------+
 |
forwards password through Password Grant
 |
 v
+----------------------+
| authorization server |
+----------------------+
 |
(now some non-OAuth magic happens to authorize the other clients)
 |
 v
+---------------+
| other clients |
+---------------+

What the workflow according to the OAuth protocol should look like instead (assuming Authorization Code Grant):

+------+
| user | 
+------+
 |
sends password through log-in form
 |
 v
+----------------------+
| authorization server |
+----------------------+
 |
sends Authorization Code (forwarded by user)
 |
 v
+--------+
| client |
+--------+

What's the difference, and why is your approach bad?

  • You're redefining the OAuth roles and their responsibilities. In OAuth, authenticating users and granting clients access to a resource is the job of the authorization server. You've instead introduced a “master client” which also takes care of authentication and authorization. This is sloppy, redundant and makes the implementation more complex.
  • Since you don't use the clients and the authorization server according to specification, you now need to add nonstandard steps to make your scheme work. For example, the idea of a “master client” which authorizes other clients doesn't exist in OAuth, so after the Password Grant has been checked by the authorization server, you need to somehow change the authorization status of all other clients as well. Maybe you send a bulk of access tokens around, maybe you let all clients share the same token – in any case, this has nothing to do with OAuth.
  • As you can clearly see in the diagram, you've added an entirely unnecessary level of indirection. Instead of simply letting the user authenticate directly towards the authorization server, they have to send their password to the “master client” which then forwards it to the authorization server. This not only increases the complexity. It also means the “master client” is now an additional entity which knows the user password (besides the authorization server). OAuth is supposed to prevent this exact problem!
  • The Password Grant is deprecated and has been completely removed in OAuth 2.1. If your entire scheme depends on this feature, there's clearly a design error.
12
  • In my case, I want to use a classical login form with username and password but my API provides no built-in UI. There needs to be some kind of client for any kind of UI. In that case, what is the difference security-wise of using a custom login form versus using the OAuth password grant type? Surely any security issues that apply to the password grant would equally apply to my custom non-OAuth authorization method. What is the benefit in me building this custom login method rather than using the OAuth password grant?
    – SorteKanin
    Commented Sep 3 at 16:24
  • @SorteKanin: The Password Grant doesn’t provide a log-in form. It actually has nothing to do with an interactive log-in at all. It’s a way for the client(!) to get an access token from the authorization server even if that server doesn’t understand any of the secure grant types. So it’s a workaround for a broken or extremely limited implementation. It’s not an alternative to a log-in form, and it’s not something you would ever use under normal circumstances (i.e., if you have access to a proper authorization server).
    – Ja1024
    Commented Sep 3 at 17:09
  • I understand that the grant doesn't provide any form - but in order to use the grant, I must provide the user with some kind of UI to input the username and password. That would be the job of a client to render that UI. Why does it matter whether the client uses a custom login API or the OAuth password grant type behind the scenes? I don't really understand why that changes the security of the situation. Or are you saying that any client rendering a login form is insecure always? But isn't that super common?
    – SorteKanin
    Commented Sep 3 at 18:48
  • @SorteKanin: Rendering – a – login – form – is – not – the – job – of – an – OAuth client. I’m not sure why you keep insisting on this. Your idea of a “authentication client” which renders a log-in form, checks the user credentials and then somehow authenticates the other clients doesn’t make any sense in the OAuth protocol. In fact, it completely defeats the purpose of OAuth, because this protocol was designed to not share the user credentials with any clients. If you do want to share the credentials with a client, then use a different protocol.
    – Ja1024
    Commented Sep 3 at 19:09
  • Speaking - like - this - does not make your argument more convincing or educational. "this protocol was designed to not share the user credentials with any clients" But a user must share their credentials with some client unless you propose that a user should manually send their credentials via a curl command or something? Even then, curl is a client. So the user must authenticate themselves with their credentials via some client - my question is, why should that client not use OAuths password grant? I don't see any security problems with this - maybe you can enlighten me?
    – SorteKanin
    Commented Sep 4 at 12:22
0

I'm assuming that you mean "Resource Owner Password Credentials", defined in 1.3.3 of the OAuth RFC.

The recommended grant type for the app you describe would be the "Authorization Code" grant type. The difference between the 2 is that, in the password credentials grant type, the client would need to access the user's username and password in order to get an access token. With the authorization code grant type, on the other hand, the client never sees the user's username or password; the user authenticates separately with the authorization server, which passes back a short lived authorization code which the client then exchanges for an access token.

You're right in thinking OAuth is a good fit for your use case, because in both cases, the client has no need for the username and password once it has obtained the access token. But in the password grant type the client does need to access the username and password to obtain the access token.

Note also the separation of the roles of resource server (your API) and authorization server (the thing that authenticates users and issues tokens) - it doesn't have to be your API that authenticates users (and sees their password).

17
  • I am aware of the authorization code grant - however, as you note, in order to use that grant "the user authenticates separately with the authorization server". What I don't understand is this: Why can't I just use the password grant flow to do this separate authentication? It seems suited for that. If I don't use that, I will need to make another custom way to authenticate to the authorization server. That's what I'm asking - if "the user authenticates separately with the authorization server" anyway, why not use the password grant type for that? Or is there some other recommended way?
    – SorteKanin
    Commented Sep 3 at 14:13
  • I mean it's kind of a catch-22. I am not supposed to use the password grant so I should use the authorization code grant type instead. But in order to use the authorization code grant type, I must already have authenticated! Some client must break this paradox and use the username and password to authenticate - if that client needs to that, why not use the password grant? I hope I am being clear :)
    – SorteKanin
    Commented Sep 3 at 14:15
  • @SorteKanin if you use password grant then the user passes credentials to the client which then presents those credentials at the authorization server - which means that client gets to access credentials. With auth code only the authorization server gets to see the credentials because the user authenticates directly. This also means that the authorization server can require MFA. Hope that's clear?
    – andycaine
    Commented Sep 3 at 14:50
  • "With auth code only the authorization server gets to see the credentials because the user authenticates directly" - in my case, the auth server and the backend API is the same. This is purely an API - there is no user interface baked in. Which means, in order to present a user with a login screen, I need to have a frontend application with a login form. But this frontend application is also just a client! The user types in their username and password in this application. Why should this application not just use the password grant type to authenticate? What else would it do, if not that?
    – SorteKanin
    Commented Sep 3 at 14:59
  • To use the auth code grant the user must authenticate with the authorization server. That authorization server cannot then be an OAuth client (I see now why you think it's a catch-22). I would highly recommend using a dedicated OAuth provider rather than trying to build it into your API - but if your API is your authorization server, then it needs to be able to authenticate users directly (not via an OAuth client) in order to use auth code grant. Then you get the benefits mentioned originally - only the authorization server ever accesses the user credentials.
    – andycaine
    Commented Sep 3 at 15:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .