spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.72k stars 5.87k forks source link

Guide/Documentation for JWT Authentication implementation using OAuth Resource Server #9423

Open cromefire opened 3 years ago

cromefire commented 3 years ago

Expected Behavior Ideally there would be some official documentation of this because judging from the amount of results you can find the seems some demand for the feature, but no one seems to know it's already supported (all articles I've seen involve writing some custom logic).

Current Behavior

If you search for "spring security jwt" (we seems reasonable) you don't get any idea that this is possible via the oauth2 resource server functions, as far as I've researched it (and I've invested quite some time into it) the only reference to that seems #6315 and I only found out about that by explicitly searching though 10s of issues.

Context This is builtin and documented well by many other web frameworks: ASP: https://devblogs.microsoft.com/aspnet/jwt-validation-and-authorization-in-asp-net-core/ AdonisJS: https://adonisjs.com/docs/4.1/authentication#_jwt Ktor: https://ktor.io/docs/jwt.html And probably a lot more I didn't search for...

jzheaux commented 3 years ago

Hi, @cromefire, thanks for the report.

Spring Security's support for JWT is documented, though I'm open to suggestions for improvement. There are also a few samples in the sample repo.

Do you have a recommendation for what to change?

cromefire commented 3 years ago

Just a quick note because I think I did a bad job describing what I mean by JWT. When I'm referring to JWT here (and I know the title is worded pretty bad, I'll try and correct that), I'm describing plain JWT authentication without using OAuth, so no IDP, just manual creation of JWTs and then just using that as a special kind of API key. So a person who will search for this probably doesn't have anything with OAuth in mind and won't drill deeper on that topic. For example if you search the guides for "JWT" there's no real helpful result: No Title or description contains "JWT" and the closest one that may seem worth looking at "Spring Security Architecture" doesn't mention JWT.

So the 2 things that are "missing" I think are some key words/sentences/headings/references and/or maybe like ASP and Ktor have done it: Some simpler blog/guide style page. Why it is correct that this is documented, this is nested quite deep into the OAuth2 docs which is probably not quite where one would expect it normally IMO (I get that it technically makes sense, which is not a bad thing, but this doesn't seem to a place where you'd easily find it, because most people probably don't read the entire documentation. All the examples I've given for instance list this separately from OAuth2).

For the main docs maybe some separate section (on the same level as OAuth and SAML) that either explains that this can be created using the OAuth resource server and the refers to the resource server documentation or even just a link to the static configuration might be very helpful, so that people can immediately see that plain JWT is implemented via the OAuth resource server.

As for a guide something that is based on oauth2/resource-server/static and maybe a simple login/test page sounds quite good. I'd envision it going something along the lines of:

This would be quite similar to what is in place for LDAP.

cromefire commented 3 years ago

Also I'm not sure where to report that, but the IDEA Guide is broken.

jzheaux commented 3 years ago

@cromefire please report the IDEA Guide issue here: https://github.com/spring-guides/gs-intellij-idea

jzheaux commented 3 years ago

@cromefire I see what you mean now.

Yes, this is something that Spring Security does not support directly, which is why there isn't any written documentation just yet. There is a sample that demonstrates what an application can do to achieve that outcome.

This is a feature that I think needs adding to Spring Security. Would you mind if I repurposed this ticket as the documentation ticket for that new feature?

cromefire commented 3 years ago

No I wouldn't mind at all (the sample looks like what I'm describing BTW)

jzheaux commented 3 years ago

I've created https://github.com/spring-projects/spring-security/issues/9424 to track the corresponding feature.

bojanv55 commented 2 years ago

This works nicely. Is there any support to read JWT token from Cookie, and not from Authorization header?

bojanv55 commented 2 years ago

nvm, I found out this is the only thing I needed:

  @Bean
  BearerTokenResolver bearerTokenResolver(){
    return request -> Stream.ofNullable(request.getCookies())
        .flatMap(Arrays::stream)
        .filter(c -> c.getName().equals("access_token"))
        .findFirst()
        .map(Cookie::getValue)
        .orElse(null);
  }
bojanv55 commented 2 years ago

Wanted also to have redirection if unauthorized, this seems to do the trick:

@Bean
  BearerTokenResolver bearerTokenResolver() {
    return request -> Stream.ofNullable(request.getCookies())
        .flatMap(Arrays::stream)
        .filter(c -> c.getName().equals("access_token"))
        .findFirst()
        .map(Cookie::getValue)
        .orElseThrow(() -> new OAuth2AuthenticationException("Must auth"));
  }

and in configure(HttpSecurity http)

.oauth2ResourceServer(
            x -> x.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/auth/login"))
                .jwt())
        .sessionManagement(
            (session) -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .exceptionHandling((exceptions) -> exceptions
            .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
            .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
jzheaux commented 2 years ago

@bojanv55, please see https://github.com/spring-projects/spring-security/issues/9230