diff --git a/pom.xml b/pom.xml
index 345a0ef..fe15c2b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -37,7 +37,24 @@
postgresql
42.7.3
-
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-resource-server
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
diff --git a/src/main/java/de/anxietyprime/swajodel/security/JwtConverter.java b/src/main/java/de/anxietyprime/swajodel/security/JwtConverter.java
new file mode 100644
index 0000000..e59c25c
--- /dev/null
+++ b/src/main/java/de/anxietyprime/swajodel/security/JwtConverter.java
@@ -0,0 +1,60 @@
+package de.anxietyprime.swajodel.security;
+
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.jwt.JwtClaimNames;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Component
+public class JwtConverter implements Converter {
+
+ private final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+
+ private final JwtConverterProperties properties;
+
+ public JwtConverter(JwtConverterProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public AbstractAuthenticationToken convert(Jwt jwt) {
+ Collection authorities = Stream.concat(
+ jwtGrantedAuthoritiesConverter.convert(jwt).stream(),
+ extractResourceRoles(jwt).stream()).collect(Collectors.toSet());
+ return new JwtAuthenticationToken(jwt, authorities, getPrincipalClaimName(jwt));
+ }
+
+ private String getPrincipalClaimName(Jwt jwt) {
+ String claimName = JwtClaimNames.SUB;
+ if (properties.getPrincipalAttribute() != null) {
+ claimName = properties.getPrincipalAttribute();
+ }
+ return jwt.getClaim(claimName);
+ }
+
+ private Collection extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
+ Map resourceAccess = jwt.getClaim("resource_access");
+ Map resource;
+ Collection resourceRoles;
+
+ if (resourceAccess == null
+ || (resource = (Map) resourceAccess.get(properties.getResourceId())) == null
+ || (resourceRoles = (Collection) resource.get("roles")) == null) {
+ return Set.of();
+ }
+ return resourceRoles.stream()
+ .map(role -> new SimpleGrantedAuthority("ROLE_" + role))
+ .collect(Collectors.toSet());
+ }
+}
diff --git a/src/main/java/de/anxietyprime/swajodel/security/JwtConverterProperties.java b/src/main/java/de/anxietyprime/swajodel/security/JwtConverterProperties.java
new file mode 100644
index 0000000..41acec0
--- /dev/null
+++ b/src/main/java/de/anxietyprime/swajodel/security/JwtConverterProperties.java
@@ -0,0 +1,19 @@
+package de.anxietyprime.swajodel.security;
+
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.annotation.Validated;
+
+@Data
+@Validated
+@Configuration
+@ConfigurationProperties(prefix = "jwt.auth.converter")
+
+
+public class JwtConverterProperties {
+
+ private String resourceId;
+ private String principalAttribute;
+}
diff --git a/src/main/java/de/anxietyprime/swajodel/security/SecurityConfig.java b/src/main/java/de/anxietyprime/swajodel/security/SecurityConfig.java
new file mode 100644
index 0000000..780ced2
--- /dev/null
+++ b/src/main/java/de/anxietyprime/swajodel/security/SecurityConfig.java
@@ -0,0 +1,33 @@
+package de.anxietyprime.swajodel.security;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.SecurityFilterChain;
+
+@RequiredArgsConstructor
+@Configuration
+ @EnableWebSecurity
+public class SecurityConfig {
+
+ public static final String ADMIN = "admin";
+ public static final String USER = "user";
+ private final JwtConverter jwtConverter;
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ http.authorizeHttpRequests((authz) ->
+ authz.requestMatchers(HttpMethod.GET, "/messages/").permitAll()
+ .anyRequest().authenticated());
+
+ http.sessionManagement(sess -> sess.sessionCreationPolicy(
+ SessionCreationPolicy.STATELESS));
+ http.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtConverter)));
+
+ return http.build();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index f440c33..50fef08 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,5 @@
spring.application.name=SWA-Jodel
+
+# Security Configuration
+spring.security.oauth2.resourceserver.jwt.issuer-uri=https://keycloak.anxietyprime.de/realms/Jodel
+spring.security.oauth2.resourceserver.jwt.jwk-set-uri=${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs