JWT Implementation¶
Introduction¶
JWT tokens are an effective method of securing APIs. By ensuring that the request is authorized to view those resources, a baseline of security can be guaranteed. In order to implement JWT my REST api running through Spring Boot Java I decided to use Firebase as my OATH handler. More information can be found on the firebase page pertaining this.
Theory¶
What’s the difference between a token and an actual password? The difference is that the token can store additional information. For example, when the token is generated, the server can store the user’s userid in the token, along with other information, such as a date for the token to expire, and any number of other things. This is done in a cryptographically secure way. In principle, it should not be possible for anyone who has the token to change this information. That means the client can use the token to access resources, but the client can’t modify the token to get more access than what the server assigned to them. If you get a magician’s apprentice token, you can’t access the parts of the magician’s circle meant for the master magicians.
Implementation¶
I first created a SecurityConfig for my Game Microservice. This configuration allows for certain Http calls to be made (note: Java was not a valid code block parser, so I used javascript so markdown can still be shown to some degree).
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**")
.authenticated()
.anyRequest()
.permitAll()
.and()
.oauth2ResourceServer()
.jwt();
}
And then made a FirebaseService:
@Service
public class FirebaseService {
@PostConstruct
public void initializeFirebaseApp() throws IOException {
InputStream serviceAccount = this.getClass().getResourceAsStream("/ramses-firebase-creds.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("REDACTED.com").build();
FirebaseApp.initializeApp(options);
}
}
In my webconfig in the same microservice I added a registry permitting the request from being passed by CORS
@Configuration
@EnableWebMvc
public class webConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
I then configured my Firebase credentials from my Firebase service account and inserted it into my resources folder.
I added the depdencies to my pom file & discovered after many hours of troubleshooting that I imported the wrong library.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.auth/google-auth-library-oauth2-http -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.firebase/firebase-admin -->
<dependency>
<groupId>com.google.firebase</groupId>
<artifactId>firebase-admin</artifactId>
<version>8.1.0</version>
</dependency>
Last but not least, I set the spring security oath resource server to:
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://securetoken.google.com/REDACTED
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=https://www.googleapis.com/service_accounts/v1/jwk/[email protected]
When I used the spring-boot-starter-oath2-resource-server instead of the google-auth-library-oauth2-http it stopped resulting in null pointers.
Validation¶
Here’s a get request with no bearer token:
As can be seen in the screenshot, a 401 unauthorized returns.
Here’s a get request with bogus in the bearer token:
After logging in the website, the token can be retrieved from the console:
And here’s the same get request but with a working bearer token:
2022-05-23 21:25:56.261 WARN 14436 --- [nio-9521-exec-2] o.a.c.util.SessionIdGeneratorBase
Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [271] milliseconds.