I created a spring boot application with graphql.I need to add spring security for authentication and authorization. My requirement is as below.
I need to validate headers, for example validate userId for incoming requests. When signIn or signUp mutations are called, there is no userId to be validated in headers. I need to permit only those signIn/signUp mutations without validating userIds in their headers.
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
.authorizeHttpRequests(registry -> {
registry.requestMatchers("/signIn", "/signUp").permitAll(); // Permit signIn, and signUp
registry.anyRequest().authenticated(); // All other requests require authentication
})
.build();
}
}
This type of filtering cannot afford here because there is only a single endpoint http://localhost:8080/graphql. How can I handle this scenario?
If it is not a good approach what are the best practices of doing this authentication & authorization part in spring boot + graphql application?
Thanks.
It is generally better to leave "system level" actions, like signing in, outside of GraphQL. Not because there's anything wrong with doing in GraphQL, but because you avoid reconfiguring Spring Security and potentially avoid having special mutations that need a different access level from everything else. Additionally, if GraphQL isn't the only API you offer, you'll end up having to support 2 different security entry points, where a preconfigured one would have sufficed. That said, if GraphQL is your only API, I can also understand standardizing on that instead of forcing a REST call to log in.
With GraphQL, you either protect all operations the same (by protecting /graphql) or you have to think of operation-level security, as each query (at any level), and each mutation, could have different access restrictions. The easiest way to achieve the latter with Spring, is to slap @PreAuthorize on all methods exposed over GraphQL that you want to protect, and leave /graphql public.
If your only exceptions are the signIn and signUp mutations, and all other operations have the same access rules, I'd honestly suggest you leave those 2 out of GraphQL. Alternatively, you could expose a whole new GraphQL endpoint for public operations, like /graphql/public, but that sounds like a hassle for the client, and is unusual enough to confuse the tooling, so I wouldn't advise going there.
If you decide to go with protecting everything via @PreAuthorize, you simply leave the 2 special mutations unprotected, and implement your sign-in/up logic in their bound methods. This makes perfect sense, and would be my preferred way, if you have various access rules across different operations. If the rules are always the same (e.g. the user just has to be logged in), then adding @PreAuthorize with identical rules everywhere and having to remember to keep adding it for every future operation is just asking for trouble.