There's a helpful Microsoft doc that describes how to configure security for a daemon client application. This works ok but it means the client app must present a client id and client secret to the /token endpoint of AAD in order to obtain the OAuth2 access token.
This makes no use of managed identity and means I need to ensure the security of the client secret of the daemon app. If the client id and secret of this app were to fall into the wrong hands, there's nothing to prevent a bad actor obtaining an access token and calling the target service.
I realise that a certificate can be used instead of a client secret but my question is, can this be avoided through the use of the managed identity of the client daemon app?
Related
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.
We have a microservices environment using Identity Server 3. Identity is provided to http microservices via bearer tokens in the authorisation http header, where the token is a JWT. That JWT usually represents a logged in end user, but it can also sometimes represent a system user that has authenticated via client credentials flow.
Messages are published on a queue (RabbitMQ) by these microservices, to be processed asynchronously. Currently, we have a windows service which consumes those messages. It authenticates as a system user with client credentials, and sends that JWT in the auth header to other http microservices.
We would like to maintain the identity of the user that publishes the messages throughout the flow, including within the machine-to-machine (m2m) communication when a message is consumed from the queue and when that consumer calls other microservices. Ie, when Service A (which was provided with a JWT) publishes a message to the queue, then the windows service should be able to impersonate the user represented in Service A's JWT, and should be able to provide a JWT representing that same user when calling Service B.
Service A (running as alice) --> RMQ
RMQ <-- Win Service (running as alice) --> Service B (running as alice)
Only clients with the correct claim should be able to impersonate a user in this way.
Which flow should I use in order to return the JWT to the Windows Service and how should this be achieved in Identity Server 3? I've managed to generate the JWT using Resource Owner flow, passing in a dummy username and password (overriding AuthenticateLocalAsync), although I've not yet attempted to check that the Win Service's client has a valid claim to impersonate. Or should this be a custom flow, implementing ICustomGrantValidator? Perhaps client credentials flow can be used?
Note that the original JWT can be provided with the message, or just the user id itself. The original JWT may have expired, which is why the windows service has to re-authenticate in some way.
My understanding is you want to propagate authenticated identities through a distributed architecture that includes async messaging via RabbitMQ message broker.
When you send/publish messages to RabbitMQ you might consider including the JWT in the message headers i.e. similar to how JWTs are included in HTTP headers for calls to protected HTTP routes. Alternatively if you're feeling a bit lazy, you could just have the JWT directly on the message payload. Your async (Windows service) consumer could validate the JWT on it's way through or it might just pass it through on the subsequent HTTP requests to protected routes of 'other http microservices'.
I'm not sure if you're question about 'which flow should I use' is relevant as presumably the user is already authenticated (via one of the OIDC/authN flows e.g. authentication code grant, implicit, ROPC...) and you're just looking to propagate the JWT through the distributed architecture for authZ purposes...
In terms of sending custom message headers, I have done this with RabbitMQ and MassTransit, but it was for (OpenTracing) trace Id propagation between asynchronous message broker operations. Repo is on GitHub here - might give you some ideas about how to achieve this...
[edit] following clarification below:
Below are some options I can think of - each one comes with some security implications:
Give the async (windows service) consumer the JWT signing key. If
you go down this path it probably makes more sense to use symmetric
signing of JWTs - any service with the symmetric key would be able
to re-create JWTs. You could probably still achieve the same result
with asymmetric signing by sharing the private key, but (IMO) the
private key should be only be known to the authorization server (when using asymmetric signing).
When the user authenticates, request a refresh token by adding
offline_access to the list of scopes specified on the /token
endpoint. You could then pass the refresh token through to the async
(windows service) consumer, which would be able to use the refresh
token to obtain a new access token if the previous one has expired (or just get a new one each time).
There's probably some security considerations that you'd need to
think about before going down this path.
Increase the timeout
duration of the access tokens so that there's enough time for the
async (windows service) consumer to handle the requests. Not sure if
this is viable for your scenario, but would be the easiest option.
I have a web app (C# / Javascript) where I want to call a back-end service that I own. I want to secure that service so only my app(s) can call it. Seems like if I use Oauth on the client side, the secret is exposed? All the docs I read about Oauth give solutions when the user of the app owns the resource, not when the app itself owns it. I was looking at how google apis work, and the JavaScript libraries seem to expose the key on the client side, no?
Yes you can accomplish this with OAuth, but how you go about it depends on the details of how the data accessed via your back-end service is organized. If the data is actually user-specific, then your user really is the resource owner. In this case you would use the typical authorization code grant. With this grant type you register a client with the OAuth auth server and receive a client_id and client_secret. The client_id is, indeed, exposed in the browser, but the client_secret sits in your web app server and is never exposed. It is only sent on back-channel (non-browser) requests to your auth server. The main thing here is that only your own client web app would be registered and receive the client_id/client_secret. You simply need to not provide any public registration endpoints so no other clients can register. With this grant type, in order for your web app to gain authorization to access the user's data on the back-end service, the user would need to approve the authorization in the browser as part of the process.
On the other hand if the data you're accessing on your back-end service is not user-specific, then you can use the OAuth Client Credentials grant. With this grant type you register the client as before and receive a client_id and client_secret. The secret is stored securely on your web app server and only passed in back-channel requests. You would avoid allowing any other clients to register. Your web app can then gain authorization to your back-end service without even needing any user authorization in the browser.
I'm afraid there is no way to restrict your API to be called just by the code of your applications. Browser applications with public codes cannot hold any secret (such as certificate), that would identify them, because anyone can extract it from the code. Desktop and mobile applications compiled to bytecode are not so easy to read, but with some effort, attacker could find the secret data. That's also the reason why these applications (so called public clients) don't hold client_secret if they act as OAuth2 clients. They use a one-time secret instead - PKCE.
What you can do, is to check the audience (what client ID the token was issued for) of an access token sent from a frontend application to your backend. You can get this info either from the token introspection endpoint (aud attribute) or from JWT attributes if the token is of JWT type.
Our apis are being consumed by 3rd party deamon applications as well as client applications. For third party deamon application we can expose the api via the client credential oauth flow and for the client application(S) we use the implicit grant outh flow.
The challenge we are facing is that in case of the implicit grant flow the user details are fetched from the ACCESS TOKEN. But when the same api is used for the client credential flow the user details can not be fetched from the ACCESS token as it has only application specific details.
What is the the best api design approach to handle the above challenge ?
Do I need two set of api(s) one for integrating with client application and one for integrating with server application ?
Will the usage of any alternative oauth flow help ?
Refer to Authentication scenarios for Azure AD documentation, as you stated correctly user interaction is not possible with a daemon application, which requires the application to have its own identity. This type of application requests an access token by using its application identity and presenting its Application ID, credential (password or certificate), and application ID URI to Azure AD. After successful authentication, the daemon receives an access token from Azure AD, which is then used to call the web API.
The quintessential OAuth2 authorization code grant is the authorization grant that uses two separate endpoints. The authorization endpoint is used for the user interaction phase, which results in an authorization code. The token endpoint is then used by the client for exchanging the code for an access token, and often a refresh token as well. Web applications are required to present their own application credentials to the token endpoint, so that the authorization server can authenticate the client.
Hence, the recommended way is two have two version of api implemented with two different type of authentication based on your scenario.
Reference -
Daemon or server application to web API
Understanding the OAuth2 implicit grant flow in Azure Active Directory (AD)
I have been trying to understand how OAuth2 works. At first I thought it was redundant to spend one extra step exchanging auth code + client secret for access token - why not have server return access token directly. For that I found this explanation.
Then what confuses me is, why does it need a clientId and a client secret, instead of just a secret? A secret which can both declare and prove itself. The client app then can simply pass it to server when it sends user there to authorize itself for accessing server resource.
Thanks!
Imagine the client signs the request with the secret and sends just the signature. How does the server know which secret to use? Presumably the server supports multiple consumers.
The client id is sent in the first part of the token dance to identify the client. This id is sent in an insecure way, in the URL. Even on the authz server end of this request the id may be exposed in an insecure way where the authz server redirects the user agent to the authorization page. So the client id is not meant to be secure, just to identify the client.
Only after receiving the authorization code (after user authorization), does the client then need to obtain the access token in a more secured way. This is where the client secret is used over TLS.
You can have the server return the access token directly. You need to request Implicit grant (response_type with the value token instead of code).
The authorization server returns the access token directly.
This type of grant is intended to be used for user-agent-based clients (e.g. single page web apps) that can’t keep a client secret or client id because all of the application code and storage is easily accessible. If your client can keep a secret, it is recommended that you use a more secure grant type.