Which OAuth 2.0 flow to use? - oauth-2.0

I have read rfc6749 and https://auth0.com/docs/authorization/which-oauth-2-0-flow-should-i-use but I couldn't seem to find the flow that's exactly for my use case.
There will be a native app(essentially a GUI) that will spin up a daemon on end user device. The daemon will try to call internal APIs hosted by the backend. The internal APIs don't need to verify the user identity; but it's preferred that the device identity can be verified to some extent. There will be an OAuth authorization server in the backend to handle the logic. But I couldn't identify which is the correct flow to use for this case.
Originally I thought this is a good fit for client credentials grant type. But then I realized that this might be a public client but client credentials is supposed to be used for confidential clients only.
I then came to find out about authorization code with PKCE flow. This seems to be the recommended flow for native apps but it doesn't make much sense to me as there will be redirects and user needs to interact but the APIs that will be called is supposed to be internal and user shouldn't know about these back channel stuff at all. Also the resource owner should be the same as the client in this case, which should be the machine not the user.
So which flow should I use?
Thanks a lot for the help!

Client Credentials feels like the standard option but there are a few variations:
SINGLE CLIENT SECRET
This is not a good option since anyone who captures a message in transit can access data for any user.
CLIENT SECRET PER USER
Using Dynamic Client Registration might be an option, where each instance of the app gets its own client ID and secret, linked to a user.
The Daemon then uses this value, and if the secret is somehow captured in transit it only impacts one user.
STRONGER CLIENT SECRETS
The client credentials grant can also be used with stronger secrets such as a Client Assertion, which can be useful if you want to avoid sending the actual secret.
This type of solution would involve generating a key per user when they aughenticate, then storing the private key on the device, eg in the keychain.

Related

Access Token JWT validation

Is it really required to validate the access token by decrypting it using the public key? I am asking this question related to the Azure AD. I am understanding that the JWT token can be validated to make sure it was in deed signed by Azure AD. If this is the case, are there any Azure AD endpoints where I can pass the token and get a response whether it was signed by it? All the articles over the internet explains the manual way of grabbing the public key from Azure AD endpoint and then do the decrypt steps by ourselves. Are there any automated way to validate the access tokens?
It would be great if someone can throw light on whether its a standard practice for the APIs to validate the access tokens before servicing the request.
It is considered best security for APIs to validate JWT access tokens on every request. This approach is fast and scales to a microservices architecture, where Service A can forward the access token to Service B and so on.
The result can be termed a 'zero trust architecture', since both calls from internet clients and clients running within the back end involve digital verification before the API logic runs.
You are right that a certain amount of plumbing code is needed to verify JWTs. This is typically coded once in a filter and then you don't need to revisit it. For some examples in various technologies, see the Curity API Guides.
I can confirm that this approach works fine for Azure AD - please post back if you run into any specific problems.
Some Authorization Servers also support token validation via OAuth Introspection, but Azure AD does not support this currently.
Introspection is most commonly used with opaque access tokens (also unsupported by Azure). See the Phantom Token Approach for further details on this pattern.
Yes, you should validate it every time. The reason to use JWT is to authorize request. If you don't care who sent the request and it doesn't matter if it was a hacker or your customer than don't use jwt and oauth. If you do care and use it you have to be sure that the jwt was not changed by some hacker, so signature has to be checked.

Making client secret configurable

We have a number of apps that communicate with each other. One app goes to a customer, and it has to communicate with a central server to get certain information. We use OAuth2 authentication, and we already use username and password to authenticate access to the central server app.
We hardwire an OAuth2 clientid and a client secret into the customer app so that the server app knows it is an instance of the app talking to it. Recently we have been asked to make the client ID and client secret configurable by the customer, so that each customer will have different OAuth clientid and client secret. id and secret would be generated by the server and the customer would set the id and secret on their installation of the app.
Is this normal practice
Does it add any useful security value
References to reputable publications addressing this would be especially welcome.
EDIT: We are using Resource Owner Password Flow, where username and password, as well as clientId and secret, are stored (encrypted) in the client app. The customer who installs the app gets given a username/password/clientid/clientsecret supplied to them, and that combination is always used to connect from client app to server app, whichever end user is logged in to the client app. (The id/secret/username/password combination can be changed if it is compromised, but changing it is expected to be rare.) This effectively makes the installation of the client app the resource owner. (I didn't design this)
I am afraid to say that the way your system uses the Resource Owner Password Flow is not normal practice (Resource Owner Password Flow). When client ID, client secret, username and password are hard wired in the client app, you could as well use the Client Credentials Flow.
Adding a configurable part to the hard wired authentication, poses the challenge to supply this new part to the customer in a secure way. On the other hand it gives you the possibility to revoke the authentication of a single customer in case it got compromised. Doing this in making the client ID and secret configurable is not normal practice. If you change the client app, so that the username and password are configured by the customer you would get closer to the standard Resource Owner Password Flow. This flow is deprecated but could be ok in your case (when to use).
By doing this step the resource is no longer owned by the client, but by a group of customers and customers can be excluded from this group.
Another way would be to change to the Client Credentials Flow and make the client ID and secret configurable. This way the customers clients would appear as different clients. The effect is nearly the same.
Summed up you have two sets of credentials (client ID:secret and username:password). Today both identify the client. One way or the other you could add the ability to identify the customer.
it is not considered best practice to hard code secrets into an app, the encryption of those only shifts the problem to the encryption key; there is a specification that addresses your "dynamic client" use case, called OAuth 2.0 Dynamic Client Registration https://www.rfc-editor.org/rfc/rfc7591

What's so secret about the OAuth secret?

I'm writing a web service which uses OAuth2 for authorization. I'm using C# and WCF, though this isn't really pertinent to my question. Having never used OAuth before, I've been doing my research. I'm on the "verify they're actually authorized to use this service" end of things. I think I have a pretty good idea of how OAuth2 works now, but one aspect of it still confounds me.
OAuth2 is token-based. The token is just text and contains some information, including a "secret" that only your application (the web service, in my case) and the Authorization Server knows. The secret can be just a text phrase or a huge string of semi-random characters (sort of like a GUID). This "proves" the user contacted the Authorization Server and got the secret from it. What confuses me is this only seems to prove that the user contacted the Authorization server sometime in the past. In fact, it doesn't even prove that. It just proves that the user knows the secret. The rest of the token (such as role, duration, other stuff) can all be faked. Once the user gets one token for the service he wants access to, they could whip up new tokens with falsified information as much as they like. In fact, there could be numerous servers set up with thousands of "secrets" for nefarious individuals to use at will. Of course, this wouldn't happen often, but it seems very possible.
Am I correct, or is there something I'm missing? Is this a known weakness of OAuth2?
Whenever the Resource Server (or "service") receives a token, it needs to validate it. Depending on the token type it can check its signature that was created with the private key that Authorization Server has or it can call into the Authorization Server to validate the token. This way a user cannot forge a token: it would be impossible to forge the signature or to make the Authorization Server verify a token that it did not issue.
FWIW: you seem to be conflating the "token" and "client secret" and perhaps even the private key of the Authorization Server; they're all different concepts.

OAuth 2 for native application - what is difference between public and confidential client types?

I trying to implement OAuth 2 provider for web service and then built native application on top of it. Also I want give access to API for third-party developers.
I read OAuth 2 specification already and can't choose right flow. I want authenticate both CLI and GUI apps as well.
First of all we have two client types - public and confidential. Of course both GUI and CLI apps will be public. But what is difference between this two types? In this case for what I need client_secret if I can get access token without it just by changing client type?
I tried to look at some API implementations of popular services like GitHub. But they use HTTP Basic Auth. Not sure it is a good idea.
Is there any particular difference? Does one improve security over the other?
As to the difference between public and confidential clients, see http://tutorials.jenkov.com/oauth2/client-types.html which says:
A confidential client is an application that is capable of keeping a
client password confidential to the world. This client password is
assigned to the client app by the authorization server. This password
is used to identify the client to the authorization server, to avoid
fraud. An example of a confidential client could be a web app, where
no one but the administrator can get access to the server, and see the
client password.
A public client is an application that is not capable of keeping a
client password confidential. For instance, a mobile phone application
or a desktop application that has the client password embedded inside
it. Such an application could get cracked, and this could reveal the
password. The same is true for a JavaScript application running in the
users browser. The user could use a JavaScript debugger to look into
the application, and see the client password.
Confidential clients are more secure than public clients, but you may not always be able to use confidential clients because of constraints on the environment that they run in (c.q. native apps, in-browser clients).
#HansZ 's answer is a good starting point in that it clarifies the difference between a public and private client application: the ability to keep the client secret a secret.
But it doesn't answer the question: what OAuth2 profile should I use for which use cases? To answer this critical question, we need to dig a bit deeper into the issue.
For confidential applications, the client secret is supplied out of band (OOB), typically by configuration (e.g. in a properties file). For browser based and mobile applications, there really isn't any opportunity to perform any configuration and, thus, these are considered public applications.
So far, so good. But I disagree that this makes such apps unable accept or store refresh tokens. In fact, the redirect URI used by SPAs and mobile apps is typically localhost and, thus, 100% equivalent to receiving the tokens directly from the token server in response to a Resource Owner Password Credentials Grant (ROPC) .
Many writers point out, sometimes correctly, that OAuth2 doesn't actually do Authentication. In fact, as stated by the OAuth2 RFC 6749, both the ROPC and Client Credentias (CC) grants are required to perform authentication. See Section 4.3 and Section 4.4.
However, the statement is true for Authorization Code and Implicit grants. But how does authentication actually work for these domains?
Typically, the user enters her username and password into a browser form, which is posted to the authentication server, which sets a cookie for its domain. Sorry, but even in 2019, cookies are the state of the authentication art. Why? Because cookies are how browser applications maintain state. There's nothing wrong with them and browser cookie storage is reasonably secure (domain protected, JS apps can't get at "http only" cookies, secure requires TLS/SSL). Cookies allow login forms to be presented only on the 1st authorization request. After that, the current identity is re-used (until the session has expired).
Ok, then what is different between the above and ROPC? Not much. The difference is where the login form comes from. In an SPA, the app is known to be from the TLS/SSL authenticated server. So this is all-but identical to having the form rendered directly by the server. Either way, you trust the site via TLS/SSL. For a mobile app, the form is known to be from the app developer via the app signature (apps from Google Play, Apple Store, etc. are signed). So, again, there is a trust mechanism similar to TLS/SSL (no better, no worse, depends on the store, CA, trusted root distributions, etc.).
In both scenarios, a token is returned to prevent the application from having to resend the password with every request (which is why HTTP Basic authentication is bad).
In both scenarios, the authentication server MUST be hardened to the onslaught of attacks that any Internet facing login server is subjected. Authorization servers don't have this problem as much, because they delegate authentication. However, OAuth2 password and client_credentials profiles both serve as de facto authentication servers and, thus, really need to be tough.
Why would you prefer ROPC over an HTML form? Non-interactive cases, such as a CLI, are a common use case. Most CLIs can be considered confidential and, thus, should have both a client_id and client_secret. Note, if running on a shared OS instance, you should write your CLI to pull the client secret and password from a file or, at least, the standard input to avoid secrets and passwords from showing up in process listings!
Native apps and SPAs are another good use, imo, because these apps require tokens to pass to REST services. However, if these apps require cookies for authentication as well, then you probably want to use the Authorization Code or Implicit flows and delegate authentication to a regular web login server.
Likewise, if users are not authenticated in the same domain as the resource server, you really need to use Authorization Code or Implicit grant types. It is up to the authorization server how the user must authenticate.
If 2-factor authentication is in use, things get tricky. I haven't crossed this particular bridge yet myself. But I have seen cases, like Attlassian, that can use an API key to allow access to accounts that normally require a 2nd factor beyond the password.
Note, even when you host an HTML login page on the server, you need to take care that it is not wrapped either by an IFRAME in the browser or some Webview component in a native application (which may be able to set hooks to see the username and password you type in, which is how password managers work, btw). But that is another topic falling under "login server hardening", but the answers all involve clients respecting web security conventions and, thus, a certain level of trust in applications.
A couple final thoughts:
If a refresh token is securely delivered to the application, via any flow type, it can be safely stored in the browser/native local storage. Browsers and mobile devices protect this storage reasonably well. It is, of course, less secure than storing refresh tokens only in memory. So maybe not for banking applications ... But a great many apps have very long lived sessions (weeks) and this is how it's done.
Do not use client secrets for public apps. It will only give you a false sense of security. Client secrets are appropriate only when a secure OOB mechanism exists to deliver the secret and it is stored securely (e.g. locked down OS permissions).

Client authentication on Public Client

Studying OAuth2.0 I finally found these 2 refs:
RFC6749 section 2.3,
RFC6749 section 10.1
Correct me if I'm wrong:
It's possible to use unregistered clients, but you have to manage them yourself with security risks.
How should I manage them?
Some more specific questions:
A Native Application (a Public Client indeed) is not able, by definition, to safely store its credentials (client_id + secret). Is it an unregistered client? If I can't verifiy/authenticate it using a secret, what else should I do?
client registration ≠ endpoint registration: the first is about registering Client Credentials (client_id + secret); the second about registering Client Redirection Endpoints. Is the Redirection Endpoint registration sufficient to grant the authenticity of the Client?
Does Client Credential Grant use the same credentials (client_id + secret) for client registration?
I think you could answer me by explaining what does this paragraph (RFC6749 section 10.1) mean.
Please give me some references and practical examples on how to implement the interaction between the authorization server and the resource server.
Thanks
tl;dr:
Native clients cannot be authenticated with client_id and client_secret. If you need to authenticate the client, you'll have to implement an authentication scheme that doesn't entrust the shared secret to the client (or involve the end-user in the client authentication discussion). Depending on your application's security model, you might not need to authenticate the client.
The redirection endpoint is not generally sufficient to authenticate the client (though exceptions exist).
The "client credential" grant type may use any client authentication mechanism supported by the authorization server, including the credentials given out at client registration.
The gist, as I read it, is that you can trust a confidential client's client_id (read: "username") and client_secret (read: "password") to authenticate them with your service. There is no[1] chance that a third-party application will ever represent itself with that client's credentials, because they are reasonably assumed to be stored safely away from prying eyes.
A public client, however, can make no such guarantee – whether a browser-based application or a native desktop application, the client's id and secret are distributed to the world at large. It's quite reasonable to assume that such applications will end up in the hands of skilled developers and hackers who can dig into the client and extract the id and secret. For this reason, Section 10.1 explicitly states that:
The authorization server MUST NOT issue client passwords or other
client credentials to native application or user-agent-based
application clients for the purpose of client authentication.
Okay. So public clients cannot be authenticated by password. However…
The authorization server MAY issue a client password or other
credentials for a specific installation of a native application
client on a specific device.
This exception works because it ties the authentication of the client to a specific device, meaning that even if someone walked away with the client's secret, they couldn't reuse it. Implicit in this exception, however, is that the "specific installation … on a specific device" must be uniquely identifiable, difficult to spoof, and integral to the authentication process for that client.
Not every native application can meet those criteria, and a browser-based application certainly cannot, since there's nothing uniquely identifiable or difficult to spoof in the environment in which it runs. This leads to a couple of options – you can treat the client as unauthenticated, or you can come up with a more appropriate authentication mechanism.
The key to the authentication dance is a shared secret – something that's known only to the authorization server and the authenticating client. For public clients, nothing in the client itself is secret. Thankfully, there are options, and I'm not just talking about RFID key fobs and biometrics (though those would be completely acceptable).
As a thought experiment, let's consider a browser-based client. We can reasonably assume a few things about it: it's running in a browser, it's served from a particular domain, and that domain is controlled by the client's authors. The authentication server should already have a Client Redirection URI, so we've got something there, but as the spec calls out:
A valid redirection URI is not sufficient to verify the client's
identity when asking for resource owner authorization but can be
used to prevent delivering credentials to a counterfeit client
after obtaining resource owner authorization.
So the redirection URI is something we should check, but isn't something we can trust, in large part because the domain could be spoofed. But the server itself can't be, so we could try to ask the domain something that only the client's domain's server would know. The simplest way to do this would be for the authentication server to require a second ("private") URI, on the same domain as the client, where the client's secret will be hosted. When the client application makes an authorization request, the server then "checks in" against that second URI relative to the client's reported hostname, and looks for the shared secret (which should only ever be disclosed to the authorization server's IP address) to authenticate the client.
Of course, this is not a perfect solution. It doesn't work for every application, it's easy to get wrong, and it's potentially a lot of work to implement. Many potential authentication mechanisms (both highly specific and highly general) exist, and any one which does not entrust the client application with private data would be suitable for this problem space.
The other option we have is to implement no further authentication, and treat the client as unauthenticated. This is notably not the same thing as an unregistered client, but the difference is subtle. An unregistered client is a client whose identity is unknown. An unauthenticated client is a client whose identity is known, but untrusted. The security implication for both types of clients is the same: neither should be entrusted with private data. Whether the authorization server chooses to treat these two cases the same, however, seems to be left up to the implementer. It may make sense, for example, for an API to refuse all connections from an unregistered client, and to serve public read-only content to any registered client (even without verifying the client's identity).
Pragmatism, however, may yet win out – an unauthenticated client is fundamentally no different than the SSL "errors" you'll occasionally see when your browser cannot verify the authenticity of the site's SSL certificate. Browsers will immediately refuse to proceed any further and report exactly why, but users are allowed to accept the risk themselves by vouching for the identity of the server. A similar workflow may make sense for many OAuth2 applications.
Why is it important to verify the client's identity, anyway? Without doing so, the chain of trust is broken. Your application's users trust your application. The authorization workflow establishes that your users also trust the client, so your application should trust the client. Without validating client identity, another client can come along and assume the role of the trusted client, with all of the security rights thereof. Everything about client authentication serves to prevent that breach of trust.
Hope this helped!
[1]: Server compromises, where the source code of your application falls into malicious hands, are an exception to this, and there are other safeguards built-in for that case. Having said that, the spec also specifically calls out that a simple username/password combination isn't the safest option:
The authorization server is encouraged to consider stronger
authentication means than a client password.

Resources