Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to use cookie and bearer auth for separate API service? #192

Closed
zzstuzor opened this issue Sep 5, 2022 · 7 comments
Closed

How to use cookie and bearer auth for separate API service? #192

zzstuzor opened this issue Sep 5, 2022 · 7 comments

Comments

@zzstuzor
Copy link

zzstuzor commented Sep 5, 2022

This is not a bug, rather I'm wondering if someone can point me in the right direction...

I'm trying to implement Duende server, but am having troubles with an auth scenario.

I have swagger UI set up for my identity server but I want to hide swagger to only be visible to users with a sysadmin role.

I created some middleware to check if context.User.Identity.IsAuthenticated, and also to check their role. I throw an exception when they're forbidden.

When I run this on my identity server it works great. The IDS Login method seems to set the auth token in the cookie or something like that, which gets picked up when I visit /swagger and the http context User seems to be authenticated, although I'm not clear how that gets set.

But I have a second service also using swagger, under the same host name but a different subdomain, and when my swagger protection middleware gets hit it sees context.User.Identity.IsAuthenticated as false. How can I populate this User identity when I visit the second service?

In my service collection configuration for all my services I have used AddAuthentication with "Bearer" and subsequently call AddJwtBearer on the AuthenticationBuilder. I've also tried calling AddCookie with the same cookie name used by IDS - would that approach work?

How can I get my second service to read the cookie set by the IDS and automatically populate the context User?

I have swagger set up with authorization too, which redirects me to the IDS and back and successfully sets the bearer token, and that is all working smoothly. But now I want to HIDE the swagger page based on the user's role.

I've also considered reading and decrypting the cookie in my protect swagger middleware and somehow try to log the user in that way, but that seems odd.

Can anyone recommend a best approach?

All the articles I see online seem to be from the perspective of having authentication and the API in the same single service, so I'm finding it hard to adapt the knowledge to the microservice approach.

Thanks in advance

@brockallen
Copy link
Member

I have swagger UI set up for my identity server but I want to hide swagger to only be visible to users with a sysadmin role.

Does this swagger endpoint run in your IdentityServer host or in your API host? Given how you've written some of the things above, it sounds like it's in your IdentityServer host.

If that's the case, then to me this means you want that path to be interactive, which means cookie authentication (not bearer tokens). So given that the programming mode for IdentityServer assumes that the cookie authentication handler will be the main scheme used, then it's just a matter of applying an authorization policy to these swagger endpoints. I don't know swagger, tho, so I don't how to do that. Maybe check their docs?

But I have a second service also using swagger, under the same host name but a different subdomain, and when my swagger protection middleware gets hit it sees context.User.Identity.IsAuthenticated as false. How can I populate this User identity when I visit the second service?

Are you sure the cookie is being processed? I'pd suggest adding a middleware after the authN middleware to do some investigation. Also, check the HTTP traffic from the browser to see if the cookie is actually being sent.

In my service collection configuration for all my services I have used AddAuthentication with "Bearer" and subsequently call AddJwtBearer on the AuthenticationBuilder.

In your IdentityServer? If you call AddAuthentication("Bearer") you're changing the default scheme to use tokens (and not cookies), thus breaking some assumptions about the security model of the host (and any UI pages). If you really want this, then it's ok, but you need to tell IdentityServer by setting the cookie auth scheme setting on the options:

https://docs.duendesoftware.com/identityserver/v6/reference/options/#authentication

Then you'd need to do something similar for the swagger endpoints, I guess.

I might be wrong, but it sounds like for all the schemes you have in your IdentityServer there might need to be more clarity on how each path/endpoint is configured so it can process the right/intended scheme for the correct credential.

@zzstuzor
Copy link
Author

zzstuzor commented Sep 7, 2022

Does this swagger endpoint run in your IdentityServer host or in your API host? Given how you've written some of the things above, it sounds like it's in your IdentityServer host.

Yes, it runs in my Identity Host. I run a swagger client on each of my API services too.

If that's the case, then to me this means you want that path to be interactive, which means cookie authentication (not bearer tokens). So given that the programming mode for IdentityServer assumes that the cookie authentication handler will be the main scheme used, then it's just a matter of applying an authorization policy to these swagger endpoints. I don't know swagger, tho, so I don't how to do that. Maybe check their docs?

I suppose I could try configuring swagger to use cookies. I was a bit out of my depth when I first added the swagger UI, and admittedly perhaps I still am!

Let's assume I go with that approach, I still have the same question as before - how then do I load a cookie created by the IDS service into another API service and use that cookie for authentication? Do I need to configure the DataProtector the same on each? Have you got any tips or suggestions for this?

Are you sure the cookie is being processed? I'pd suggest adding a middleware after the authN middleware to do some investigation. Also, check the HTTP traffic from the browser to see if the cookie is actually being sent.

No. The cookie is being created by the IDS and works fine for using UI pages on the IDS, but it doesn't get read by my separate API host, and I don't know how to make it 'process' that cookie, as you termed it.

In your IdentityServer? If you call AddAuthentication("Bearer") you're changing the default scheme to use tokens (and not cookies), thus breaking some assumptions about the security model of the host (and any UI pages). If you really want this, then it's ok, but you need to tell IdentityServer by setting the cookie auth scheme setting on the options:

Well, I'm now using multiple schemes, Jwt and Cookies, with a PolicyScheme and a defaultSelector.

Ultimately I have 4 types of clients:

  • API services need to be able to call each other directly (to catch up when out of sync with AMQP), using client_credentials, and a special scope for services
  • React UI front end to call APIs on behalf of a user, using authorization_code and offline_access / refresh tokens etc.
  • a desktop client to be able to call some of the APIs, using password grant and offline_access etc.
  • a single swagger UI client with access to all scopes, for my devs to be able to test the APIs during development, using authorization_code. Ideally I'd hide this swagger endpoint unless the user has a "dev" or "sysadmin" role claim, but I just need to be able to load the user auth / cookie / whatever on my API services.

I simplified my code and put it up at the following link, in case you're interested in taking a look. It's a working example where the Bearer works for swagger for both hosts, following the oauth2 flow, and the cookie works for using the local pages on the IDS.
https://github.com/zzstuzor/duende-example

@zzstuzor
Copy link
Author

zzstuzor commented Sep 7, 2022

As per this site, Swagger doesn't support cookie authentication. Maybe that's why I went with bearer and OAuth flow.

Note for Swagger UI and Swagger Editor users: Cookie authentication is currently not supported for "try it out" requests due to browser security restrictions. See this issue for more information. SwaggerHub does not have this limitation.

@brockallen
Copy link
Member

Ok, if swagger doesn't allow cookies, and you want authenticated requests you'd need to mark that endpoint with an ASP.NET Core authorization policy for the token scheme you've registered with our local token support: https://docs.duendesoftware.com/identityserver/v6/apis/add_apis/

I don't know much about swagger, so unfortunately I can't help you with that beyond what I've mentioned above.

@zzstuzor
Copy link
Author

zzstuzor commented Sep 7, 2022 via email

@brockallen
Copy link
Member

How does any separate asp.net MVC application load an auth cookie set by the identity server?

It doesn't -- it sets its own based on the OIDC authentication protocol response from IdentityServer.

If you're unfamiliar with the workflows, then I'd suggest one of our trainings to learn those fundamentals:

https://duendesoftware.com/training/

@zzstuzor
Copy link
Author

zzstuzor commented Sep 9, 2022

OK thanks that makes sense.

@zzstuzor zzstuzor closed this as completed Sep 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
2 participants