dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.57k stars 10.05k forks source link

ASP.NET Core SPA Templates Need Better Options for Authentication #42158

Closed Grauenwolf closed 10 months ago

Grauenwolf commented 2 years ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

I am trying to create basic SPA applications that manage their own passwords without the cost and complexity of third-party products like Identity Server.

Other's I'm talking to just want simple social media authentication.

We're all at a loss as to how to achieve this because none of the SPA templates give us any direction on how to proceed. There are out-of-band tutorials we can look at. But they are often incomplete or confusing, which is not acceptable for something that has to be perfect on day one. The phrase, "I'm learning authentication by trial-and-error" is quite frightening.

Describe the solution you'd like

The SPA templates for Angular, React, Blazor, etc. should include options for...

Additional context

We are regularly seeing posts on Reddit with titles like "Why is authentication such a XXXX show with .NET 6?" and "Does anyone else feel as lost as I do in the .NET Identity documentation?". The community is having a really hard time with this and needs far better guidance than what we're getting.

MJomaa commented 2 years ago

+ 1

I don't even know why you would need identity server when starting out with a web project. It's overkill and requires licensing.

WebApp with internal API

I wish there was a SPA template with session cookie authentication, CSRF protection, Microsoft+Google federated login and scaffolded UI where you change everything, even the routes.

Public API

If you want to offer a public API it's trivial to implement client credentials flow where the client credentials can be generated in the web app (usually under "organization" or "account settings")

toddbauermeister commented 2 years ago

+1

My recent experience with Blazor Server and scaffolding in Auth pages for customisation (which are .cshtml and not .razor pages) was not super fun or intuitive tbh 😅

It would have been really nice to have a template with a choice of provider(s) / auth components to be included in the template by default, and the support to scaffold in .razor pages (or even include some of the most important ones in the project by default) many people including myself have been confused that there is a project with pages which 'don't exist' in the solution until you scaffold them in.

DavidKrowitz commented 2 years ago

Pretty please with a bow on top!

Would make the lives of working professional coders a lot easier.

GuerrillaCoder commented 2 years ago

Also an example using openiddict which is free instead of identity server that would require a license for us to use.

atresnjo commented 2 years ago

Also an example using openiddict which is free instead of identity server that would require a license for us to use.

https://github.com/openiddict/openiddict-samples/tree/dev/samples/Hollastin/Hollastin.Server

dajma00 commented 2 years ago

Even trying to do an API with auth, we are at a loss. A Laravel team tried and failed. Went back to Laravel.

robheffo79 commented 2 years ago

Honestly, Authentication is terrible. It's overcomplicated and slow.

I implemented my own Authentication platform that completely hides the default built-in system, It's much faster than the stock system. I would share it but it's for a client and I don't own the rights to the code

Authentication needs to be split out into its own libraries and not as part of the core of ASP.NET 6.

MJSanfelippo commented 2 years ago

That would be fantastic.

taylorchasewhite commented 2 years ago

Here are related issues I wrote (focused on the documentation, but certainly reflect the same concerns):

  1. Understanding & Using Microsoft Identity (StackOverflow)
  2. Blazor WASM Additional Authentication Scenarios (#221222)
  3. AzureAD Blazor Issues #19803
  4. AzureAD Blazor Claims Issues #19576
  5. BaseAddressAuthorizationMessageHandler #18344

FWIW, we largely did our own work as well to make auth work in our Blazor WASM app and divorce from Identity Server, but I would much rather use a well supported foundation than what I built.

Thanks @Grauenwolf for your suggestions.

prince272 commented 2 years ago

I'm happy that these are now concerns to the community. When standalone react and api application was introduced, I thought authentication would be improved upon but I rather saw complexity of third-party products like Identity Server, etc. I'm currently considering identify server 4 with OID client and still stuck with Net 5. But I'm hoping there would be a better solution like what @MJomaa suggested. Thank you

kyledevans commented 2 years ago

I've managed to implement both username/password and the Microsoft Identity Web platform into a react SPA + backend API project. But it's been a hugely complicated task, and while it's great when I look back at how much I've learned, I doubt anyone wants to spend 6+ months digging into the deepest depths of ASP in order to come up with a production-ready implementation. The only reason I was able to do it is because Covid forced me to take a lot of time off work.

If it's at all helpful, I have a working implementation here: Kiddo (Username/Password/Azure Ad web app). It uses JWTs instead of cookies, but on the server side it still uses the ASP Identity framework for managing usernames/passwords.

I fully get that adding even a stripped down version of what I've managed to get working is a bit much for a template. There's simply so much boilerplate necessary simply to get the server-side API to work. That's not considering all of the UI components and integration with your site branding and design.

I've wondered at the possibility that we (the community and ASP teams) could come up with a REST protocol to at least streamline the server-side component. From there it would be up to individual teams to write the actual SPA frontend that integrates with the API.

chindilhan commented 2 years ago

Yes this is a must have, easy to use feature. We've switched few projects to other techs just because of this auth nightmare.

robert-txt commented 2 years ago

Something has already started to happen in this matter: https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-preview-5/#jwt-authentication-improvements-automatic-authentication-configuration Is it the right direction?

Grauenwolf commented 2 years ago

Something has already started to happen in this matter: https://devblogs.microsoft.com/dotnet/asp-net-core-updates-in-dotnet-7-preview-5/#jwt-authentication-improvements-automatic-authentication-configuration Is it the right direction?

It is a good thing, but somewhat orthogonal to what we're talking about.

The JWT improvements will help someone who already has a JWT based authentication provider running. But it's useless to someone who is starting from scratch and just needs an internal solution like ASP.NET Identity.

kyledevans commented 2 years ago

Yeah @Grauenwolf is exactly right. Those changes look like they will make it marginally easier and cleaner for someone that's already written a complete JWT auth solution. For someone just starting out, it's extremely overwhelming to figure out what needs to be manually implemented, how to configure the built in stuff correctly, and then digging through all of the ASP library code so that when we have to re-implement something we are compatible with the rest of the ASP ecosystem.

For example one area I had trouble with was getting a JWT implementation of ASP.NET Identity to co-exist with the Microsoft Identity Web platform. Getting it to work involved asking for help from the Microsoft Identity Web developers, sleuthing through the ASP code, and a ton of trial and error. There's still places I don't fully understand, and am afraid to touch because I may break what I somehow got working.

davidfowl commented 2 years ago

@dajma00 Can you comment on this? If you have details it would be great!

dajma00 commented 2 years ago

@dajma00 Can you comment on this? If you have details it would be great!

On the move from Laravel to .NET?

davidfowl commented 2 years ago

@dajma00 On how the auth is much better in Laravel (for whatever scenario this team was trying to accomplish).

gulshan commented 2 years ago

Please consider porting scenarios from other major web frameworks like Laravel, Django, passport.js etc. A basic guideline will be helpful.

kevinchalet commented 2 years ago

Also an example using openiddict which is free instead of identity server that would require a license for us to use.

@GuerrillaCoder you may want to take a look at the openiddict-samples repository:

A year ago, @blowdart and I informally discussed about potential options and having an equivalent of Microsoft.AspNetCore.ApiAuthorization.IdentityServer based on OpenIddict was mentioned.

Microsoft.AspNetCore.ApiAuthorization.IdentityServer is used in the Blazor WASM template when you enable individual authentication and is basically a set of opinionated helpers that configure IdSrv without exposing most of the plumbing.

Have you guys tried it? If so, what do you think of it? Is it something that could qualify as a good enough option for SPA/Blazor apps?

dajma00 commented 2 years ago

@dajma00 On how the auth is much better in Laravel (for whatever scenario this team was trying to accomplish).

I wasn't saying Laravel was better/easier for auth, I don't have much experience with that. I am consulting for a small team to do new projects in .NET and when they tried to start with .NET6 APIs, auth was their first obstacle and they couldn't get to speed for a month so they basically gave up temporarily. I understand that the team has no experience in .NET at all, so probably it wasn't entirely .NET's fault, but still auth in .NET6 needs to be easier and better explained. That is exactly the point here that auth needs to be something that new teams can embrace quickly, even if they are coming from other frameworks. We need to note that not all teams who want to embrace .NET have much or any experience with .NET. Some might be smarter and be able to deduce/learn from tutorials and websites. But many have difficulty understanding, especially when it comes to MS documentation. I myself, usually look at MS documentation for a few minutes and then move on to other search results quickly. I have produced many Blazor applications, all of them with auth and even mult-tenant apps but I cannot say with confidence how to go about using auth in .NET. Should I use Identity?, Duende? API authentication for public facing APIs, user websites, cookies vs JWT. I also understand there is a lot to cover here but when your audience is large and varied, you have to cater to all levels of programmers, not just the best ones. So that is where initial templates can be helpful and as more experience is gained, better understanding will come as well.

davidfowl commented 2 years ago

@dajma00 Great! I was just making sure there wasn't something I was missing. The team is working through the very generic "auth is hard" feedback and are digging into specifics. When other frameworks come up we got looking for examples and I've yet to see something that was easy, but I want to make sure we're being kept honest (so keep sending the feedback).

For teams/developers that don't know where to start or how to answer any of the relevant questions about authentication scheme, user management, supported clients etc., we need to have a stronger opinion here. We're going to spend a bunch of time building out samples to cover some "steel thread" scenarios based on the feedback we've received from several mediums.

GuerrillaCoder commented 2 years ago

When other frameworks come up we got looking for examples and I've yet to see something that was easy, but I want to make sure we're being kept honest (so keep sending the feedback).

@davidfowl I consider ServiceStack auth to be easy to implement and well documented. Not sure if there are any parallels that help.

Grauenwolf commented 2 years ago

It's not only people with no .NET experience that are struggling.

A lot of us came spent the last 2 decades using Active Directory integration for everything, including SPAs. Now that we're moving to cloud-based deployments where AD isn't an option, the comparative difficulty level is coming as a shock.

Which is why I'm advocating so hard for the samples to be directly offered in the VS templates. While better guidance at all would be beneficial, the ability to start a project with authentication from minute one is the goal.

kyledevans commented 2 years ago

Some of the issues I've faced when starting a new SPA project:

I seem to have faced the following scenario in multiple new projects the last couple years. Say I'm starting my React SPA project with a simple username/password system using a built in IdentityServer (since that's what Microsoft currently recommends it seems).

How do I login a React app? There's the MSAL javascript library, but that (by design) doesn't deal with the actual login process. For that we need to have an HTML form to let the user type in their credentials, then make an ajax call to our internal IdentityServer to validate. From there we need to somehow let the MSAL.js instance know that we are now logged in so that it can start keeping track of tokens, identities, etc. Once all of that is done we can then start making calls to APIs that require access tokens, and it's a simple matter of attaching the appropriate HTTP headers "Authorization: Bearer " for future ajax requests.

Now for a developer that isn't an expert in OAuth, Microsoft Identity Platform, and IdentityServer, learning all of that at once is overwhelming. As far as I know, there doesn't appear to be an API for logging into an IdentityServer and initiating a session. I have no idea how to let MSAL.js know that login succeeded and it can now proceed with the OAuth protocol.

A template that can provide all of that, would go a long way towards at least providing direction on what we need to tweak for our specific project needs.

dajma00 commented 2 years ago

To add to feedback -- Just to be more specific, here is a simple requirement. May be I am missing something but it is not obvious. If I create a default Blazor wasm hosted project with auth individual accounts, and I want to give access to my APIs (not the wasm app) to third parties, what steps should be followed?

kyledevans commented 2 years ago

Feels like death by a thousand paper cuts when it comes to Auth in SPAs. There's so many subtle, but incredibly important details that have to be correct. Any attempt to break down the problem into manageable chunks reveals even more, equally challenging problems.

Perhaps a good exercise for the ASP team members that are investigating this would be to try and recreate what the MVC templates can produce, only for a 100% SPA UI making ajax calls to a backend API. In order to support the functionality built into the ASP.NET Identity framework, it generates the following pages: identity_scaffold Now, add in the fact that right now we have to manually figure out what kind of authentication token to use (Cookie, JWT, etc.). But also how to generate them, how to validate them, and how to maintain them. It's daunting.

Ogglas commented 2 years ago

This should be prioritized for .NET 7 @blowdart @Pilchie

blowdart commented 2 years ago

@Ogglas .NET 7 planning & prioritization was done at the start of the year, as is the case every year. There's likely one preview left for 7 before it moves towards RC. So, no, this won't be part of 7.

@DamianEdwards is looking at making jwt dev easier, so this perhaps could build on that for 8.

davidfowl commented 2 years ago

As I said here, towards the end of .NET 7 the team will embark on an app building exercise to explore. We'll share more once we start.

taylorchasewhite commented 2 years ago

As I said here, towards the end of .NET 7 the team will embark on an app building exercise to explore. We'll share more once we start.

Thanks! Just curious, is that something you'll share here (on this issue), or is there somewhere else we should keep our eyes peeled to look for this (I'd like to stay up to date on any Blazor WASM (SPA) Auth developments.

Grauenwolf commented 2 years ago

@Ogglas .NET 7 planning & prioritization was done at the start of the year, as is the case every year. There's likely one preview left for 7 before it moves towards RC. So, no, this won't be part of 7.

Why would it need to be part of .NET 7?

These are templates. They can be a Visual Studio feature or even a completely separate component just like 3rd party templates.

In fact, I would highly recommend the SPA templates not be part of .NET 7. The underlying dependencies change too frequently and they should be updated far more often than once a year.

davidfowl commented 2 years ago

Thanks! Just curious, is that something you'll share here (on this issue), or is there somewhere else we should keep our eyes peeled to look for this (I'd like to stay up to date on any Blazor WASM (SPA) Auth developments.

This issue will be the one that we'll update.

davidfowl commented 2 years ago

@Grauenwolf We're not building any templates yet, we're going to start by building samples. We're not committing to what will or will not be templates.

Grauenwolf commented 2 years ago

@davidfowl Long term, I still think we really need templates. But building samples first is a perfectly reasonable stepping stone.

davidfowl commented 2 years ago

Templates for every scenario would be a nightmare to maintain, no promises.

Grauenwolf commented 2 years ago

Again, I think that's perfectly fair.

taylorchasewhite commented 2 years ago

@Ogglas .NET 7 planning & prioritization was done at the start of the year, as is the case every year. There's likely one preview left for 7 before it moves towards RC. So, no, this won't be part of 7.

Why would it need to be part of .NET 7?

These are templates. They can be a Visual Studio feature or even a completely separate component just like 3rd party templates.

In fact, I would highly recommend the SPA templates not be part of .NET 7. The underlying dependencies change too frequently and they should be updated far more often than once a year.

Realistically though, they're going to need to make code changes that are a part of the .NET Framework to even do this, unless the templates are going to contain a ton of logic.

dajma00 commented 2 years ago

Templates for every scenario would be a nightmare to maintain, no promises.

I agree. Samples should be good enough.

cyril265 commented 2 years ago

In my opinion spring (boot) security gets it right. It's very easy to configure cookie/basic auth backed by a DB source. Basically you need to configure 2 things: authentication type and some handler that retrieves the user data by username. Everything else is pre-configured but can be overridden:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

// hard coded in memory as an example but you basically need to implement
// UserDetailsService.loadUserByUsername which retrieves some UserDetails object (from DB, other service)
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        UserDetails user =
             User.withDefaultPasswordEncoder()
                .username("user")
                .password("password")
                .roles("USER")
                .build();

        return new InMemoryUserDetailsManager(user);
    }
}

Correct me if I'm wrong but the new JWT configuration doesn't provide any calls or services (or you need to read the source) for generating tokens. The whole JWT signing configuration is there. The only thing missing is some handler that retrieves users by username. Then again maybe I missed it.

davidfowl commented 2 years ago

@cyril265 Cookies + user is the one thing that is easy out of the box with ASP.NET Core. Authorization policies are usually specified on individual endpoints so unlike your code where it's done globally, it's specified on each of the routes. There's no path based security built into the stack.

This issue details more complicated types of authN (token based).

Here's a brain dump of the variables that go into decision making process of "which auth type should I use":

User management

How and where do I store my users?

Authentication schemes

What protocol does the client use to exchange credentials for an identity+claims.

External Identity

Users can be managed externally to your application and so can authentication (I'm sure some of are missing).

Clients

What types of clients are going to access your application?

Client libs

What client libraries exist to "do the authentication protocol".

App types (our templates)

What type of application is being built? (These can be mixed as well)

So dealing with a multi dimensional matrix. Still we want to first build a repository full of samples before we get to the next stage.

brockallen commented 2 years ago

Client libs

You forgot your own ASP.NET OpenID Connect handler.

davidfowl commented 2 years ago

Impressive that's the only thing I forgot.

ssippe commented 2 years ago

@cyril265 Cookies + user is the one thing that is easy out of the box with ASP.NET Core. Authorization policies are usually specified on individual endpoints so unlike your code where it's done globally, it's specified on each of the routes. There's no path based security built into the stack.

This issue details more complicated types of authN (token based).

Here's a brain dump of the variables that go into decision making process of "which auth type should I use":

User management

How and where do I store my users?

  • ASP.NET Core Identity
  • Custom database
  • Active Directory
  • External
  • External + Identity (local user profile associated with external user id)

Authentication schemes

What protocol does the client use to exchange credentials for an identity+claims.

  • Cookie
  • API key
  • Basic
  • JWT
  • OIDC
  • OAuth2

External Identity

Users can be managed externally to your application and so can authentication (I'm sure some of are missing).

  • Active Directory
  • OIDC based

    • Auth0/Okta/etc
    • Azure AD
    • B2C
  • OAuth2 based

Clients

What types of clients are going to access your application?

  • Browser
  • Mobile
  • Desktop Client

Client libs

What client libraries exist to "do the authentication protocol".

  • MSAL
  • ADAL
  • oidc client
  • Custom code

App types (our templates)

What type of application is being built? (These can be mixed as well)

  • SPA with API (including Blazor WASM)
  • SPA with no backend (direct calls to db from client, firebase)
  • Server rendered (Razor Pages, MVC Views)
  • SignalR
  • Blazor Server
  • REST API
  • Mobile App iOS and Android using Maui
  • Mobile App iOS using Swift and Android via Java
  • .NET based Desktop App (Winforms, WPF, Maui)

So dealing with a multi dimensional matrix. Still we want to first build a repository full of samples before we get to the next stage.

Please include support for apps that's don't use entity framework.

davidfowl commented 2 years ago

Please include support for apps that's don't use entity framework.

It seems from the docs lots of people believe that entity framework is deeply coupled to the stack. It’s actually an invisible sub bullet under identity as a default provider. It’s the only thing we’re going out ship out of the box but will always allow replacing it (like we already do today)

Grauenwolf commented 2 years ago

It would be useful to have a demonstration of replacing EF with a different ORM in Identity. But that's very, very, very low on the priority list and not something I'd expect from Microsoft directly.

It doesn't hurt to have Identity use EF and the rest of the project using a docent ORM.

davidfowl commented 2 years ago

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity-custom-storage-providers?view=aspnetcore-6.0

davidfowl commented 2 years ago

This was interesting read https://laravel.com/docs/9.x/authentication

luanmm commented 2 years ago

In my recent experience coding in Laravel (for an specific project) after years of .NET development, it was a surprise how simple authentication could be. I was reading this thread and only the last message references the Laravel docs, which is something that I would end up posting here as a reference too.

In my experience, the worst authentication scenario today is for SPAs (which is a very common choice nowadays). And, IMHO, the worst thing is to have a third-party solution in the middle of the process (IdentityServer, that is a commercial product), which isn't easy to implement as other things are in .NET (I know stateless authentication has its challenges).

Laravel offers a simple cookie authentication for SPAs (when you don't need stateless sessions and work in a single domain), which has better security than JWT (avoiding XSS, for instance) and is simpler to work with (as you don't need to code the session management mechanisms, like refreshing tokens, etc). I know .NET offers cookie authentication too, but is designed to work with Razor/MVC, in a very opinionated way (I stopped trying to make it work in an SPA scenario because of the difficulties).

In the stateless world, things are somehow a bit more complicated naturally (at least when the team is caring about security), so this is really a point to explore carefully. As not every team or project could have a security expert, it would be awesome if the configuring process helps somehow the developers avoiding some design mistakes (this article may help in this subject and why JWT can be problematic if not used with security in mind all the time: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid).

Anyway, hope you guys could find a good path that makes .NET authentication simpler and robust like the framework is in other areas!

Grauenwolf commented 2 years ago

I for one would love a cookie/ASP.NET Identity option for SPAs.

I realize that not everyone is comfortable with storing passwords in a local database, but ASP.NET Identity makes it easy to do it correctly.