{"id":91727,"date":"2019-05-13T08:30:39","date_gmt":"2019-05-13T05:30:39","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/?p=91727"},"modified":"2019-05-20T15:11:55","modified_gmt":"2019-05-20T12:11:55","slug":"spring-security-oauth-through-java-hipster","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2019\/05\/spring-security-oauth-through-java-hipster.html","title":{"rendered":"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster"},"content":{"rendered":"<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n<p>Using unit and integration tests to verify your code quality is an excellent way to show you care about your code. I recently did a bunch of work in the popular JHipster open source project to upgrade it to use the latest release of Spring Security.<\/p>\n<p>Spring Security 5.1+ adds OAuth 2.0 and OIDC as first-class citizens that you can configure with its elegant DSL (a.k.a. cool method chaining, a.k.a. the builder pattern). I\u2019ve been motivated to use it ever since Rob Winch and crew first launched it. It\u2019s been fun collaborating with them on a very innovative project. Spring Security makes OAuth awesome!<\/p>\n<p>I added OAuth 2.0 support to JHipster in the fall of 2017. The experience influenced me greatly. I learned a ton about Keycloak, Docker Compose, and how to switch between identity providers (IdPs).<\/p>\n<p>I spent the last month upgrading&nbsp;<a href=\"https:\/\/www.jhipster.tech\/\">JHipster<\/a>&nbsp;to use Spring Security 5.1 (the default in Spring Boot 2.1). I experienced some frustrations along the way, shook my fist at Travis CI, and rejoiced when I figured out solutions. I also learned quite a bit in the process. I\u2019m going to share those experiences with you today.<\/p>\n<h2 class=\"wp-block-heading\" id=\"logout-with-oauth-2-0-and-oidc\">Logout with OAuth 2.0 and OIDC<\/h2>\n<p>Soon after integrating support for Keycloak and Okta in JHipster, the project received a lot of complaints from users that they couldn\u2019t log out. JHipster users were familiar with clicking&nbsp;<strong>Logout<\/strong>&nbsp;(check with latest) and being&nbsp;<em>completely<\/em>&nbsp;logged out. With the default Spring Security support, users would be logged out of the local app, but not the IdP.<\/p>\n<p>It took me a year, but I finally added&nbsp;<a href=\"https:\/\/github.com\/jhipster\/generator-jhipster\/pull\/8757\">global SSO logout<\/a>&nbsp;earlier this year. Both Keycloak and Okta require you to send a GET request to an endpoint with the ID token and the URL to redirect to. Therefore, I created a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">LogoutResource<\/code>&nbsp;that returns these values.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@RestController\npublic class LogoutResource {\n    private final Logger log = LoggerFactory.getLogger(LogoutResource.class);\n    private final UserInfoRestTemplateFactory templateFactory;\n    private final String accessTokenUri;\n\n   public LogoutResource(UserInfoRestTemplateFactory templateFactory,\n                         @Value(\"${security.oauth2.client.access-token-uri}\") String accessTokenUri) {\n       this.templateFactory = templateFactory;\n       this.accessTokenUri = accessTokenUri;\n   }\n\n    \/**\n     * POST  \/api\/logout : logout the current user\n     *\n     * @return the ResponseEntity with status 200 (OK) and a body with a global logout URL and ID token\n     *\/\n    @PostMapping(\"\/api\/logout\")\n    public ResponseEntity&lt;?&gt; logout(HttpServletRequest request, Authentication authentication) {\n        log.debug(\"REST request to logout User : {}\", authentication);\n        OAuth2RestTemplate oauth2RestTemplate = this.templateFactory.getUserInfoRestTemplate();\n        String idToken = (String) oauth2RestTemplate.getAccessToken().getAdditionalInformation().get(\"id_token\");\n\n        String logoutUrl = accessTokenUri.replace(\"token\", \"logout\");\n        Map&lt;String, String&gt; logoutDetails = new HashMap&lt;&gt;();\n        logoutDetails.put(\"logoutUrl\", logoutUrl);\n        logoutDetails.put(\"idToken\", idToken);\n        request.getSession().invalidate();\n        return ResponseEntity.ok().body(logoutDetails);\n    }\n}\n<\/pre>\n<p>The Angular client calls the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">\/api\/logout<\/code>&nbsp;endpoint and constructs the IdP logout URL.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">this.authServerProvider.logout().subscribe(response =&gt; {\n  const data = response.body;\n  let logoutUrl = data.logoutUrl;\n  \/\/ if Keycloak, uri has protocol\/openid-connect\/token\n  if (logoutUrl.indexOf('\/protocol') &gt; -1) {\n    logoutUrl = logoutUrl + '?redirect_uri=' + window.location.origin;\n  } else {\n    \/\/ Okta\n    logoutUrl = logoutUrl + '?id_token_hint=' +\n    data.idToken + '&amp;post_logout_redirect_uri=' + window.location.origin;\n  }\n  window.location.href = logoutUrl;\n});\n<\/pre>\n<p>Testing the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">LogoutResource<\/code>&nbsp;was pretty straightforward. The bulk of the work involved mocking the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">UserInfoRestTemplateFactory<\/code>&nbsp;so it returned an ID token.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@RunWith(SpringRunner.class)\n@SpringBootTest(classes = JhipsterApp.class)\npublic class LogoutResourceIntTest {\n\n    @Autowired\n    private MappingJackson2HttpMessageConverter jacksonMessageConverter;\n\n    private final static String ID_TOKEN = \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\" +\n        \".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm\" +\n        \"p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M\" +\n        \"Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr\" +\n        \"oqqUrg\";\n\n    @Value(\"${security.oauth2.client.access-token-uri}\")\n    private String accessTokenUri;\n\n    private MockMvc restLogoutMockMvc;\n\n    @Before\n    public void before() {\n        LogoutResource logoutResource = new LogoutResource(restTemplateFactory(), accessTokenUri);\n        this.restLogoutMockMvc = MockMvcBuilders.standaloneSetup(logoutResource)\n            .setMessageConverters(jacksonMessageConverter).build();\n    }\n\n    @Test\n    public void getLogoutInformation() throws Exception {\n        String logoutUrl = accessTokenUri.replace(\"token\", \"logout\");\n        restLogoutMockMvc.perform(post(\"\/api\/logout\"))\n            .andExpect(status().isOk())\n            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))\n            .andExpect(jsonPath(\"$.logoutUrl\").value(logoutUrl))\n            .andExpect(jsonPath(\"$.idToken\").value(ID_TOKEN));\n    }\n\n    private UserInfoRestTemplateFactory restTemplateFactory() {\n        UserInfoRestTemplateFactory factory = mock(UserInfoRestTemplateFactory.class);\n        Map&lt;String, Object&gt; idToken = new HashMap&lt;&gt;();\n        idToken.put(\"id_token\", ID_TOKEN);\n        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(\"my-fun-token\");\n        token.setAdditionalInformation(idToken);\n        when(factory.getUserInfoRestTemplate()).thenReturn(mock(OAuth2RestTemplate.class));\n        when(factory.getUserInfoRestTemplate().getAccessToken()).thenReturn(token);\n        return factory;\n    }\n}<\/pre>\n<p>I merged global logout support into JHipster\u2019s master branch in late January, and started upgrading Spring Security\u2019s OIDC support a few weeks later.<\/p>\n<p>Upgrade Spring Security\u2019s OIDC Support<br \/>I started by creating issue #9276 to track my goals, motivations, and known issues.<\/p>\n<p>At this point, if you\u2019re not intimately familiar with Spring Security, you\u2019re probably wondering: why is upgrading to Spring Security\u2019s latest release so cool? Long story short: they\u2019ve deprecated annotations, added features, and have made it easier to integrate OAuth 2.0 and OIDC into your applications. Thanks, Spring Security team!<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Using @EnableOAuth2Sso and @EnableResourceServer is no longer recommended in Spring Boot 2.1+ (a.k.a., Spring Security 5.1+). The reasons for the change can be found in Josh Long\u2019s Bootiful Podcast, published on Jan 25, 2019. It\u2019s an interview with Madhura Bhave and the discussion starts at 21:30.<\/p>\n<\/blockquote>\n<p>In addition to converting all the Java code and YAML configuration to use the latest Spring Security bits, I also decided to make every JHipster app a resource server by default. Here\u2019s the logic from JHipster\u2019s SecurityConfiguration.java.ejs template:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@Override\npublic void configure(HttpSecurity http) throws Exception {\n    \/\/ @formatter:off\n    http\n        ...\n        &lt;%_ } else if (authenticationType === 'oauth2') { _%&gt;\n            &lt;%_ if (['monolith', 'gateway'].includes(applicationType)) { _%&gt;\n        .and()\n            .oauth2Login()\n            &lt;%_ } _%&gt;\n        .and()\n            .oauth2ResourceServer().jwt();\n        &lt;%_ } _%&gt;\n        \/\/ @formatter:on\n  }\n}<\/pre>\n<p>To make sure the implementation was OIDC compliant, I overrode the default&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">JwtDecoder<\/code>&nbsp;bean with one that does audience validation.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@Value(\"${spring.security.oauth2.client.provider.oidc.issuer-uri}\")\nprivate String issuerUri;\n\n@Bean\nJwtDecoder jwtDecoder() {\n    NimbusJwtDecoderJwkSupport jwtDecoder = (NimbusJwtDecoderJwkSupport)\n        JwtDecoders.fromOidcIssuerLocation(issuerUri);\n\n    OAuth2TokenValidator&lt;Jwt&gt; audienceValidator = new AudienceValidator();\n    OAuth2TokenValidator&lt;Jwt&gt; withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);\n    OAuth2TokenValidator&lt;Jwt&gt; withAudience = new DelegatingOAuth2TokenValidator&lt;&gt;(withIssuer, audienceValidator);\n\n    jwtDecoder.setJwtValidator(withAudience);\n\n    return jwtDecoder;\n}<\/pre>\n<p>After I had all the runtime code working, I moved onto refactoring tests. Tests are the most reliable indicator of refactoring success, especially with a project that has&nbsp;<a href=\"https:\/\/arxiv.org\/abs\/1710.07980\">26,000<\/a>&nbsp;combinations like JHipster does!<\/p>\n<p>I encountered a number of challenges along the way. Since I learned a lot solving these challenges, I thought it\u2019d be fun to explain them and how I solved them.<\/p>\n<h2 class=\"wp-block-heading\" id=\"how-to-mock-an-authenticatedprincipal-with-an-id-token\">How to Mock an AuthenticatedPrincipal with an ID Token<\/h2>\n<p>The first challenge I encountered was with the updated&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">LogoutResource<\/code>. Below is the code after I refactored it to use Spring Security\u2019s&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ClientRegistrationRepository<\/code>.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@RestController\npublic class LogoutResource {\n    private ClientRegistration registration;\n\n    public LogoutResource(ClientRegistrationRepository registrations) {\n        this.registration = registrations.findByRegistrationId(\"oidc\");\n    }\n\n    \/**\n     * {@code POST  \/api\/logout} : logout the current user.\n     *\n     * @param request the {@link HttpServletRequest}.\n     * @param idToken the ID token.\n     * @return the {@link ResponseEntity} with status {@code 200 (OK)} and a body with a global logout URL and ID token.\n     *\/\n    @PostMapping(\"\/api\/logout\")\n    public ResponseEntity&lt;?&gt; logout(HttpServletRequest request,\n                                    @AuthenticationPrincipal(expression = \"idToken\") OidcIdToken idToken) {\n        String logoutUrl = this.registration.getProviderDetails()\n            .getConfigurationMetadata().get(\"end_session_endpoint\").toString();\n\n        Map&lt;String, String&gt; logoutDetails = new HashMap&lt;&gt;();\n        logoutDetails.put(\"logoutUrl\", logoutUrl);\n        logoutDetails.put(\"idToken\", idToken.getTokenValue());\n        request.getSession().invalidate();\n        return ResponseEntity.ok().body(logoutDetails);\n    }\n}<\/pre>\n<p>I tried to mock out the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">OAuth2AuthenticationToken<\/code>&nbsp;in&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">LogoutResourceIT.java<\/code>, thinking this would lead to the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">AuthenticationPrincipal<\/code>&nbsp;being populated.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@RunWith(SpringRunner.class)\n@SpringBootTest(classes = JhipsterApp.class)\npublic class LogoutResourceIT {\n\n    @Autowired\n    private ClientRegistrationRepository registrations;\n\n    @Autowired\n    private MappingJackson2HttpMessageConverter jacksonMessageConverter;\n\n    private final static String ID_TOKEN = \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\" +\n        \".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm\" +\n        \"p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M\" +\n        \"Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr\" +\n        \"oqqUrg\";\n\n    private MockMvc restLogoutMockMvc;\n\n    @Before\n    public void before() {\n        LogoutResource logoutResource = new LogoutResource(registrations);\n        this.restLogoutMockMvc = MockMvcBuilders.standaloneSetup(logoutResource)\n            .setMessageConverters(jacksonMessageConverter).build();\n    }\n\n    @Test\n    public void getLogoutInformation() throws Exception {\n\n        Map&lt;String, Object&gt; claims = new HashMap&lt;&gt;();\n        claims.put(\"groups\", \"ROLE_USER\");\n        claims.put(\"sub\", 123);\n        OidcIdToken idToken = new OidcIdToken(ID_TOKEN, Instant.now(),\n            Instant.now().plusSeconds(60), claims);\n\n        String logoutUrl = this.registrations.findByRegistrationId(\"oidc\").getProviderDetails()\n            .getConfigurationMetadata().get(\"end_session_endpoint\").toString();\n        restLogoutMockMvc.perform(post(\"\/api\/logout\")\n            .with(authentication(createMockOAuth2AuthenticationToken(idToken))))\n            .andExpect(status().isOk())\n            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))\n            .andExpect(jsonPath(\"$.logoutUrl\").value(logoutUrl));\n    }\n\n    private OAuth2AuthenticationToken createMockOAuth2AuthenticationToken(OidcIdToken idToken) {\n        Collection&lt;GrantedAuthority&gt; authorities = new ArrayList&lt;&gt;();\n        authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));\n        OidcUser user = new DefaultOidcUser(authorities, idToken);\n\n        return new OAuth2AuthenticationToken(user, authorities, \"oidc\");\n    }\n}<\/pre>\n<p>However, this resulted in the following error:<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">Caused by: java.lang.IllegalArgumentException: tokenValue cannot be empty\n    at org.springframework.util.Assert.hasText(Assert.java:284)\n    at org.springframework.security.oauth2.core.AbstractOAuth2Token.&lt;init&gt;(AbstractOAuth2Token.java:55)\n    at org.springframework.security.oauth2.core.oidc.OidcIdToken.&lt;init&gt;(OidcIdToken.java:53)\n    at java.base\/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)\n    at java.base\/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)\n    at java.base\/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)\n    at java.base\/java.lang.reflect.Constructor.newInstance(Constructor.java:490)\n    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:172)<\/pre>\n<p>I&nbsp;<a href=\"https:\/\/stackoverflow.com\/questions\/55163989\/how-to-test-authenticationprincipal-and-getting-an-id-token-in-spring-security\">posted this problem to Stack Overflow<\/a>&nbsp;and sent an email to the Spring Security team as well.&nbsp;<a href=\"https:\/\/twitter.com\/joe_grandja\">Joe Grandja<\/a>&nbsp;responded with a solution to the problem.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">AuthenticationPrincipalArgumentResolver<\/code>&nbsp;is not getting registered in your test.<br \/>It automatically gets registered when the &#8220;full&#8221; spring-web-mvc is enabled, e.g&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@EnableWebMvc<\/code>.<\/p>\n<p>However, in your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@Before<\/code>, you have:<\/p>\n<p><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">MockMvcBuilders.standaloneSetup()<\/code>&nbsp;&#8211; this does not initialize the full web-mvc infrastructure &#8211; only a subset.<\/p>\n<p>Try this instead:<br \/><code class=\"highlighter-rouge\" style=\"font-size: 13px;\">MockMvcBuilders.webAppContextSetup(this.context)<\/code>&nbsp;&#8211; this will register&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">AuthenticationPrincipalArgumentResolver<\/code>&nbsp;and your test should resolve the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">OidcIdToken<\/code>.<\/p>\n<\/blockquote>\n<p>Joe was correct. I changed the test to the following and the test passed. \u2705<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@RunWith(SpringRunner.class)\n@SpringBootTest(classes = JhipsterApp.class)\npublic class LogoutResourceIT {\n\n    @Autowired\n    private ClientRegistrationRepository registrations;\n\n    @Autowired\n    private WebApplicationContext context;\n\n    private final static String ID_TOKEN = \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9\" +\n        \".eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsIm\" +\n        \"p0aSI6ImQzNWRmMTRkLTA5ZjYtNDhmZi04YTkzLTdjNmYwMzM5MzE1OSIsImlhdCI6MTU0M\" +\n        \"Tk3MTU4MywiZXhwIjoxNTQxOTc1MTgzfQ.QaQOarmV8xEUYV7yvWzX3cUE_4W1luMcWCwpr\" +\n        \"oqqUrg\";\n\n    private MockMvc restLogoutMockMvc;\n\n    @Before\n    public void before() throws Exception {\n        Map&lt;String, Object&gt; claims = new HashMap&lt;&gt;();\n        claims.put(\"groups\", \"ROLE_USER\");\n        claims.put(\"sub\", 123);\n        OidcIdToken idToken = new OidcIdToken(ID_TOKEN, Instant.now(),\n            Instant.now().plusSeconds(60), claims);\n        SecurityContextHolder.getContext().setAuthentication(authenticationToken(idToken));\n        SecurityContextHolderAwareRequestFilter authInjector = new SecurityContextHolderAwareRequestFilter();\n        authInjector.afterPropertiesSet();\n\n        this.restLogoutMockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();\n    }\n\n    @Test\n    public void getLogoutInformation() throws Exception {\n        String logoutUrl = this.registrations.findByRegistrationId(\"oidc\").getProviderDetails()\n            .getConfigurationMetadata().get(\"end_session_endpoint\").toString();\n        restLogoutMockMvc.perform(post(\"\/api\/logout\"))\n            .andExpect(status().isOk())\n            .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))\n            .andExpect(jsonPath(\"$.logoutUrl\").value(logoutUrl))\n            .andExpect(jsonPath(\"$.idToken\").value(ID_TOKEN));\n    }\n\n    private OAuth2AuthenticationToken authenticationToken(OidcIdToken idToken) {\n        Collection&lt;GrantedAuthority&gt; authorities = new ArrayList&lt;&gt;();\n        authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));\n        OidcUser user = new DefaultOidcUser(authorities, idToken);\n        return new OAuth2AuthenticationToken(user, authorities, \"oidc\");\n    }\n}\n<\/pre>\n<p>Getting the logout functionality properly tested was a big milestone. I moved on to upgrading JHipster\u2019s microservices architecture.<\/p>\n<h2 class=\"wp-block-heading\" id=\"how-to-pass-an-oauth-2-0-access-token-to-downstream-microservices-with-zuul\">How to Pass an OAuth 2.0 Access Token to Downstream Microservices with Zuul<\/h2>\n<p>JHipster uses Netflix Zuul to proxy requests from the gateway to downstream microservices. I created an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">AuthorizationHeaderFilter<\/code>&nbsp;to handle access token propagation.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">public class AuthorizationHeaderFilter extends ZuulFilter {\n\n    private final AuthorizationHeaderUtil headerUtil;\n\n    public AuthorizationHeaderFilter(AuthorizationHeaderUtil headerUtil) {\n        this.headerUtil = headerUtil;\n    }\n\n    @Override\n    public String filterType() {\n        return PRE_TYPE;\n    }\n\n    @Override\n    public int filterOrder() {\n        return Ordered.LOWEST_PRECEDENCE;\n    }\n\n    @Override\n    public boolean shouldFilter() {\n        return true;\n    }\n\n    @Override\n    public Object run() {\n        RequestContext ctx = RequestContext.getCurrentContext();\n        Optional&lt;String&gt; authorizationHeader = headerUtil.getAuthorizationHeader();\n        authorizationHeader.ifPresent(s -&gt; ctx.addZuulRequestHeader(TokenRelayRequestInterceptor.AUTHORIZATION, s));\n        return null;\n    }\n}<\/pre>\n<p>However, adding this did not result in successful access token propagation. With&nbsp;<a href=\"https:\/\/github.com\/mraible\/jhipster-ms-oidc-improved\/pull\/1#issuecomment-471328682\">help from Jon Ruddell<\/a>, I discovered this was because JHipster had a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">LazyInitBeanFactoryPostProcessor<\/code>&nbsp;that caused all beans to be lazy-loaded. The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ZuulFilterInitializer<\/code>&nbsp;was included in this logic. Making&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ZuulFilterInitializer<\/code>&nbsp;an eagerly-loaded bean caused everything to work as it did before.<\/p>\n<p>At this point, I had everything working, so I&nbsp;<a href=\"https:\/\/github.com\/jhipster\/generator-jhipster\/pull\/9416\">created a pull request to upgrade JHipster\u2019s templates<\/a>.<\/p>\n<p>I knew that what I checked in required Keycloak to be running for integration tests to pass. This is because of OIDC discovery and how the endpoints are looked up from&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.well-known\/openid-configuration<\/code>.<\/p>\n<h2 class=\"wp-block-heading\" id=\"how-to-handle-oidc-discovery-in-spring-boot-integration-tests\">How to Handle OIDC Discovery in Spring Boot Integration Tests<\/h2>\n<p>I wasn\u2019t too concerned that Keycloak needed to be running for integration tests to pass. Then some of our Azure and Travis builds started to fail. JHipster developers noted they were seeing errors like the following when Keycloak wasn\u2019t running.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">Factory method 'clientRegistrationRepository' threw exception; nested exception is\njava.lang.IllegalArgumentException: Unable to resolve the OpenID Configuration\nwith the provided Issuer of \"http:\/\/localhost:9080\/auth\/realms\/jhipster\"<\/pre>\n<p>I did some spelunking through Spring Security\u2019s OAuth and OIDC tests and came up with a&nbsp;<a href=\"https:\/\/github.com\/jhipster\/generator-jhipster\/pull\/9484\">solution<\/a>. The fix involved adding a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">TestSecurityConfiguration<\/code>&nbsp;class that overrides the default Spring Security settings and mocks the beans so OIDC discovery doesn\u2019t happen.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@TestConfiguration\npublic class TestSecurityConfiguration {\n    private final ClientRegistration clientRegistration;\n\n    public TestSecurityConfiguration() {\n        this.clientRegistration = clientRegistration().build();\n    }\n\n    @Bean\n    ClientRegistrationRepository clientRegistrationRepository() {\n        return new InMemoryClientRegistrationRepository(clientRegistration);\n    }\n\n    private ClientRegistration.Builder clientRegistration() {\n        Map&lt;String, Object&gt; metadata = new HashMap&lt;&gt;();\n        metadata.put(\"end_session_endpoint\", \"https:\/\/jhipster.org\/logout\");\n\n        return ClientRegistration.withRegistrationId(\"oidc\")\n            .redirectUriTemplate(\"{baseUrl}\/{action}\/oauth2\/code\/{registrationId}\")\n            .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)\n            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)\n            .scope(\"read:user\")\n            .authorizationUri(\"https:\/\/jhipster.org\/login\/oauth\/authorize\")\n            .tokenUri(\"https:\/\/jhipster.org\/login\/oauth\/access_token\")\n            .jwkSetUri(\"https:\/\/jhipster.org\/oauth\/jwk\")\n            .userInfoUri(\"https:\/\/api.jhipster.org\/user\")\n            .providerConfigurationMetadata(metadata)\n            .userNameAttributeName(\"id\")\n            .clientName(\"Client Name\")\n            .clientId(\"client-id\")\n            .clientSecret(\"client-secret\");\n    }\n\n    @Bean\n    JwtDecoder jwtDecoder() {\n        return mock(JwtDecoder.class);\n    }\n\n    @Bean\n    public OAuth2AuthorizedClientService authorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {\n        return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);\n    }\n\n    @Bean\n    public OAuth2AuthorizedClientRepository authorizedClientRepository(OAuth2AuthorizedClientService authorizedClientService) {\n        return new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService);\n    }\n}<\/pre>\n<p>Then in classes that use&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@SpringBootTest<\/code>, I configured this as a configuration source.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">@SpringBootTest(classes = {MicroApp.class, TestSecurityConfiguration.class})<\/pre>\n<h2 class=\"wp-block-heading\" id=\"running-end-to-end-tests-on-jhipster-microservices-that-are-secured-with-oauth-2-0\">Running End-to-End Tests on JHipster Microservices that are Secured with OAuth 2.0<\/h2>\n<p>The final issue surfaced shortly after. The&nbsp;<a href=\"https:\/\/dev.azure.com\/hipster-labs\/jhipster-daily-builds\/_build\/results?buildId=1995\">jhipster-daily-builds<\/a>&nbsp;(running on Azure DevOps) were failing when they tried to test microservices.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">Caused by: java.lang.IllegalArgumentException: Unable to resolve the OpenID Configuration\n with the provided Issuer of \"http:\/\/localhost:9080\/auth\/realms\/jhipster\"<\/pre>\n<p>We don\u2019t include Keycloak Docker Compose files for microservices because we don\u2019t expect them to be run standalone. They require a gateway to access them, so their OAuth 2.0 settings should match your gateway and the gateway project contains the Keycloak files.<\/p>\n<p>The end-to-end tests that were running on Azure where 1) starting the microservice, and 2) hitting its health endpoint to ensure it started successfully. To fix,&nbsp;<a href=\"https:\/\/twitter.com\/pascalgrimaud\">Pascal Grimaud<\/a>&nbsp;<a href=\"https:\/\/github.com\/hipster-labs\/jhipster-daily-builds\/commit\/5b8f125131a3d39c190e0572dd60fd4c3d7a44d4\">disabled starting\/testing microservices<\/a>. He also created a&nbsp;<a href=\"https:\/\/github.com\/hipster-labs\/jhipster-daily-builds\/issues\/6\">new issue<\/a>&nbsp;to improve the process so a full microservices stack is generated using JHipster\u2019s JDL.<\/p>\n<h2 class=\"wp-block-heading\" id=\"upgrade-to-spring-security-5-1-and-its-first-class-oidc-support\">Upgrade to Spring Security 5.1 and its First-Class OIDC Support<\/h2>\n<p>I hope this list of challenges and fixes has helped you. If you\u2019re using the deprecated&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@EnableOAuth2Sso<\/code>&nbsp;or&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">@EnableResourceServer<\/code>, I encourage you to try upgrading to Spring Security 5.1. The&nbsp;<a href=\"https:\/\/github.com\/jhipster\/generator-jhipster\/issues\/9276\">issue I used to track the upgrade<\/a>&nbsp;has links that show all the required code changes.<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/mraible\/jhipster-oidc-improved\/pull\/1\">Code changes required for a monolith<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/mraible\/jhipster-ms-oidc-improved\/pull\/1\">Code changes required for a microservices architecture<\/a><\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\" id=\"use-jhipster-6-to-generate-a-spring-boot-react-app-with-oidc-for-auth\">Use JHipster 6 to Generate a Spring Boot + React app with OIDC for Auth<\/h2>\n<p>JHipster 6 uses the latest and greatest versions of Spring Boot and Spring Security. It supports Angular and React for its front-end. It&nbsp;<a href=\"https:\/\/github.com\/jhipster\/jhipster-vuejs\">supports Vue too<\/a>, it\u2019s just not part of the main generator.<\/p>\n<p>If you generate an application with JHipster 6, all of the test features mentioned in this post will be in your application. How do you do that? I\u2019m glad you asked!<br \/>Start by installing a beta of JHipster 6:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">npm install -g generator-jhipster@beta<\/pre>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">npm<\/code>&nbsp;command is part of&nbsp;<a href=\"https:\/\/nodejs.org\/\">Node.js<\/a>. You\u2019ll need Node 10.x to install JHipster and run useful commands.<\/p>\n<\/blockquote>\n<p>JHipster 6 supports Java 8, 11, and 12 (thanks to Spring Boot 2.1). I recommend managing your Java SDK with&nbsp;<a href=\"https:\/\/sdkman.io\/\">SDKMAN!<\/a>&nbsp;For example, you can install Java 12 and make it the default.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">sdk install java 12.0.0-open\nsdk default java 12.0.0-open<\/pre>\n<p>You can create a JHipster app that uses React and OIDC with just a few commands:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">mkdir app &amp;&amp; cd app\n\necho \"application { config { baseName reactoidc, \\\n  authenticationType oauth2, clientFramework react } }\" &gt;&gt; app.jh\n\njhipster import-jdl app.jh\n<\/pre>\n<p><p>Below is a terminal recording that shows the results of these commands.<\/p>\n<p><script id=\"asciicast-240996\" src=\"https:\/\/asciinema.org\/a\/240996.js\" async=\"\"><\/script><\/p>\n<p>The configured OIDC provider must be running for a JHipster-generated Spring Boot app to start successfully. You can start Keycloak using Docker Compose:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:java\">docker-compose -f src\/main\/docker\/keycloak.yml up -d<\/pre>\n<p>Then start your application using Maven:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">.\/mvnw<\/pre>\n<p>When startup completes, open&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\"><a class=\"bare\" href=\"http:\/\/localhost:8080\/\">http:\/\/localhost:8080<\/a><\/code>, and click&nbsp;<strong>sign in<\/strong>. You\u2019ll be redirected to Keycloak, where you can enter&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">admin\/admin<\/code>&nbsp;to log in.<\/p>\n<h3 class=\"wp-block-heading\" id=\"why-okta-instead-of-keycloak\">Why Okta instead of Keycloak?<\/h3>\n<p>Keycloak works great, but this is a post on the Okta developer blogs, so let me show you how you can use Okta! Why should you use Okta? That\u2019s a great question.<br \/>Okta is an always-on identity provider that provides authentication and authorization services for developers. It also allows you to manage your users. I like to call it Users As a Software Service, but UASS isn\u2019t a great acronym. User Management as a Software Service (UMASS) rolls off the tongue a bit easier. Anyway, it\u2019s a great service and you should give it a try.<\/p>\n<h3 class=\"wp-block-heading\" id=\"register-your-secure-spring-boot-application\">Register Your Secure Spring Boot Application<\/h3>\n<p>To begin, sign up for a&nbsp;<a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">free Okta developer account<\/a>&nbsp;(or sign in if you already have an account).<\/p>\n<p>Once you\u2019re signed in to Okta, register your Spring Boot application.<\/p>\n<ul class=\"wp-block-list\">\n<li>In the top menu, click on&nbsp;<strong>Applications<\/strong><\/li>\n<li>Click on&nbsp;<strong>Add Application<\/strong><\/li>\n<li>Select&nbsp;<strong>Web<\/strong>&nbsp;and click&nbsp;<strong>Next<\/strong><\/li>\n<li>Enter a&nbsp;<strong>Name<\/strong><\/li>\n<li>Change the Login redirect URI to be&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\"><a class=\"bare\" href=\"http:\/\/localhost:8080\/login\/oauth2\/code\/oidc\">http:\/\/localhost:8080\/login\/oauth2\/code\/oidc<\/a><\/code><\/li>\n<li>Click&nbsp;<strong>Done<\/strong>, then&nbsp;<strong>Edit<\/strong>, and add&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\"><a class=\"bare\" href=\"http:\/\/localhost:8080\/\">http:\/\/localhost:8080<\/a><\/code>&nbsp;as a Logout redirect URI<\/li>\n<li>Click&nbsp;<strong>Save<\/strong><\/li>\n<\/ul>\n<p>Your settings should resemble the screenshot below when you\u2019re finished.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"1009\" height=\"1024\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/app-settings-1009x1024.png\" alt=\"\" class=\"wp-image-91730\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/app-settings-1009x1024.png 1009w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/app-settings-296x300.png 296w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/app-settings-768x779.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/app-settings-70x70.png 70w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/app-settings.png 1470w\" sizes=\"(max-width: 1009px) 100vw, 1009px\" \/><\/figure>\n<\/div>\n<p>Create an&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">okta.env<\/code>&nbsp;file in your project\u2019s root directory and replace the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">{..}<\/code>&nbsp;values with those from your Okta application:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">export SPRING_SECURITY_OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER_URI=https:\/\/{yourOktaDomain}\/oauth2\/default\nexport SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_ID={clientId}\nexport SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_OIDC_CLIENT_SECRET={clientSecret}\n<\/pre>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Add&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">*.env<\/code>&nbsp;to your&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.gitignore<\/code>&nbsp;file so this file won\u2019t end up on GitHub.<\/p>\n<\/blockquote>\n<h3 class=\"wp-block-heading\" id=\"create-groups-and-add-them-as-claims-to-the-id-token\">Create Groups and Add them as Claims to the ID Token<\/h3>\n<p>JHipster is configured by default to work with two types of users: administrators and users. Keycloak is configured with users and groups automatically, but you need to do some one-time configuration for your Okta organization.<\/p>\n<p>Create a&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ROLE_ADMIN<\/code>&nbsp;and&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">ROLE_USER<\/code>&nbsp;group (<strong>Users<\/strong>&nbsp;&gt;&nbsp;<strong>Groups<\/strong>&nbsp;&gt;&nbsp;<strong>Add Group<\/strong>) and add users to them. You can use the account you signed up with, or create a new user (<strong>Users<\/strong>&nbsp;&gt;&nbsp;<strong>Add Person<\/strong>). Navigate to&nbsp;<strong>API<\/strong>&nbsp;&gt;&nbsp;<strong>Authorization Servers<\/strong>, and click on the the&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">default<\/code>&nbsp;server. Click the&nbsp;<strong>Claims<\/strong>&nbsp;tab and&nbsp;<strong>Add Claim<\/strong>. Name it&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">groups<\/code>, and include it in the ID Token. Set the value type to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">Groups<\/code>&nbsp;and set the filter to be a Regex of&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\">.*<\/code>. Click&nbsp;<strong>Create<\/strong>.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"1024\" height=\"841\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/add-claim-1024x841.png\" alt=\"\" class=\"wp-image-91731\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/add-claim-1024x841.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/add-claim-300x246.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/add-claim-768x631.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/add-claim.png 1226w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<p>Start your application with the following commands:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">source okta.env\n.\/mvnw\n<\/pre>\n<p>Navigate to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\"><a class=\"bare\" href=\"http:\/\/localhost:8080\/\">http:\/\/localhost:8080<\/a><\/code>&nbsp;and use your Okta credentials to log in.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"1024\" height=\"611\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/authenticated-by-okta-1024x611.png\" alt=\"\" class=\"wp-image-91732\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/authenticated-by-okta-1024x611.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/authenticated-by-okta-300x179.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/authenticated-by-okta-768x458.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/authenticated-by-okta.png 1600w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<p>Pretty hip, don\u2019t you think?! \ud83e\udd13<\/p>\n<h2 class=\"wp-block-heading\" id=\"better-java-testing-with-jhipster\">Better Java Testing with JHipster<\/h2>\n<p>JHipster generates an app for you that has good test coverage out of the box. Code coverage is analyzed using&nbsp;<a href=\"https:\/\/sonarcloud.io\/\">SonarCloud<\/a>, which is automatically configured for you. Run the following command to start Sonar in a Docker container.<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">docker-compose -f src\/main\/docker\/sonar.yml up -d<\/pre>\n<p>Then run the following Maven command:<\/p>\n<pre class=\"wp-block-preformatted gutter: false;brush:bash\">.\/mvnw -Pprod clean test sonar:sonar -Dsonar.host.url=http:\/\/localhost:9001<\/pre>\n<p>Once the process completes, navigate to&nbsp;<code class=\"highlighter-rouge\" style=\"font-size: 13px;\"><a class=\"bare\" href=\"http:\/\/localhost:9001\/projects\">http:\/\/localhost:9001\/projects<\/a><\/code>&nbsp;and you\u2019ll see your project\u2019s report.<\/p>\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" width=\"1024\" height=\"189\" src=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/sonar-report-1024x189.png\" alt=\"\" class=\"wp-image-91733\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/sonar-report-1024x189.png 1024w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/sonar-report-300x55.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/sonar-report-768x142.png 768w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2019\/05\/sonar-report.png 1546w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The code coverage is much higher than what\u2019s shown in this report. We changed many tests to run in the integration test phase recently, and haven\u2019t figured out how to report this data to Sonar.<\/p>\n<\/blockquote>\n<p>See&nbsp;<a href=\"https:\/\/www.jhipster.tech\/code-quality\/\">JHipster\u2019s Code Quality documentation<\/a>&nbsp;for more information about this feature.<\/p>\n<p>Support for JUnit 5 in JHipster is&nbsp;<a href=\"https:\/\/github.com\/jhipster\/generator-jhipster\/issues\/9498\">also in the works<\/a>.<\/p>\n<h2 class=\"wp-block-heading\" id=\"learn-more-about-spring-security-spring-boot-and-jhipster\">Learn More about Spring Security, Spring Boot, and JHipster<\/h2>\n<p>I hope you\u2019ve enjoyed my story about upgrading JHipster to use Spring Security 5.1 and its stellar OAuth 2.0 + OIDC support. I really like what that Spring Security team has done to simplify its configuration and make OIDC discovery (among other things) just work.<\/p>\n<p>I did not create a GitHub repository for this example since JHipster generated all the code and I didn\u2019t need to modify anything.<\/p>\n<p>If you\u2019d like to learn more about JHipster 6, see&nbsp;<a href=\"https:\/\/developer.okta.com\/blog\/2019\/04\/04\/java-11-java-12-jhipster-oidc?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Better, Faster, Lighter Java with Java 12 and JHipster 6<\/a>. If you\u2019re interested in JHipster\u2019s CRUD generation abilities and PWA support, I encourage you to check out my blog post on&nbsp;<a href=\"https:\/\/developer.okta.com\/blog\/2018\/06\/25\/react-spring-boot-photo-gallery-pwa?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">how to build a Photo Gallery PWA with React, Spring Boot, and JHipster<\/a>.<\/p>\n<p>We\u2019ve also published a number of posts about testing and Spring Security 5.1:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/03\/28\/test-java-spring-boot-junit5?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Test Your Spring Boot Applications with JUnit 5<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2018\/05\/02\/testing-spring-boot-angular-components?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">The Hitchhiker\u2019s Guide to Testing Spring Boot APIs and Angular Components with WireMock, Jest, Protractor, and Travis CI<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/03\/12\/oauth2-spring-security-guide?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">A Quick Guide to OAuth 2.0 with Spring Security<\/a><\/li>\n<li><a href=\"https:\/\/developer.okta.com\/blog\/2019\/03\/05\/spring-boot-migration?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Migrate Your Spring Boot App to the Latest and Greatest Spring Security and OAuth 2.0<\/a><\/li>\n<\/ul>\n<p>Want more tech tips? Follow us on social networks {&nbsp;<a href=\"https:\/\/twitter.com\/oktadev\">Twitter<\/a>,&nbsp;<a href=\"https:\/\/www.linkedin.com\/company\/oktadev\">LinkedIn<\/a>,&nbsp;<a href=\"https:\/\/www.facebook.com\/oktadevelopers\/\">Facebook<\/a>,&nbsp;<a href=\"https:\/\/www.youtube.com\/channel\/UC5AMiWqFVFxF1q9Ya1FuZ_Q\">YouTube<\/a>&nbsp;} to be notified when we publish new content.<br \/><em>Have a question about Okta that\u2019s unrelated to this post? Please ask it on our&nbsp;<a href=\"https:\/\/devforum.okta.com\/\">developer forums<\/a>.<\/em><\/p>\n<p><a href=\"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\" (opens in a new tab)\">&#8220;Upgrading Spring Security OAuth and JUnit Tests through the&nbsp;&nbsp;of a Java Hipster&#8221;<\/a>&nbsp;was originally published on the Okta developer blog on April 15, 2019.<\/p>\n<p><span style=\"font-size: 20px;\"><b>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever.<\/b> Tired of building the same login screens over and over? <a href=\"https:\/\/developer.okta.com\/signup\/?utm_campaign=text_website_all_multiple_dev_ciam_testing-spring-security-oauth-with-junit_null&amp;utm_source=jcg&amp;utm_medium=cpc\">Try the Okta API for hosted authentication, authorization, and multi-factor auth.<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u201cI love writing authentication and authorization code.\u201d ~ No Java Developer Ever. Tired of building the same login screens over and over? Try the Okta API for hosted authentication, authorization, and multi-factor auth. Using unit and integration tests to verify your code quality is an excellent way to show you care about your code. I &hellip;<\/p>\n","protected":false},"author":13127,"featured_media":240,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[274,30,125],"class_list":["post-91727","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-junit","tag-spring","tag-spring-security"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn about Java Hipster? Check our article explaining how to upgrade Upgrading Spring Security OAuth and JUnit Tests with java hipster.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn about Java Hipster? Check our article explaining how to upgrade Upgrading Spring Security OAuth and JUnit Tests with java hipster.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2019-05-13T05:30:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-05-20T12:11:55+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Matt Raible\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@mraible\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Matt Raible\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"19 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/05\\\/spring-security-oauth-through-java-hipster.html\"},\"author\":{\"name\":\"Matt Raible\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\"},\"headline\":\"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster\",\"datePublished\":\"2019-05-13T05:30:39+00:00\",\"dateModified\":\"2019-05-20T12:11:55+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/05\\\/spring-security-oauth-through-java-hipster.html\"},\"wordCount\":2363,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"keywords\":[\"JUnit\",\"Spring\",\"Spring Security\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2019\\\/05\\\/spring-security-oauth-through-java-hipster.html\",\"url\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit\",\"name\":\"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"datePublished\":\"2019-05-13T05:30:39+00:00\",\"dateModified\":\"2019-05-20T12:11:55+00:00\",\"description\":\"Interested to learn about Java Hipster? Check our article explaining how to upgrade Upgrading Spring Security OAuth and JUnit Tests with java hipster.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/spring-logo.jpg\",\"width\":150,\"height\":150,\"caption\":\"spring-interview-questions-answers\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/developer.okta.com\\\/blog\\\/2019\\\/04\\\/15\\\/testing-spring-security-oauth-with-junit#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/54edd49deb980d7706e2af51514c3f7f\",\"name\":\"Matt Raible\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g\",\"caption\":\"Matt Raible\"},\"description\":\"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.\",\"sameAs\":[\"https:\\\/\\\/developer.okta.com\",\"https:\\\/\\\/x.com\\\/mraible\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/matt-raible\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster - Java Code Geeks","description":"Interested to learn about Java Hipster? Check our article explaining how to upgrade Upgrading Spring Security OAuth and JUnit Tests with java hipster.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit","og_locale":"en_US","og_type":"article","og_title":"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster - Java Code Geeks","og_description":"Interested to learn about Java Hipster? Check our article explaining how to upgrade Upgrading Spring Security OAuth and JUnit Tests with java hipster.","og_url":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2019-05-13T05:30:39+00:00","article_modified_time":"2019-05-20T12:11:55+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","type":"image\/jpeg"}],"author":"Matt Raible","twitter_card":"summary_large_image","twitter_creator":"@mraible","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Matt Raible","Est. reading time":"19 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/05\/spring-security-oauth-through-java-hipster.html"},"author":{"name":"Matt Raible","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f"},"headline":"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster","datePublished":"2019-05-13T05:30:39+00:00","dateModified":"2019-05-20T12:11:55+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2019\/05\/spring-security-oauth-through-java-hipster.html"},"wordCount":2363,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","keywords":["JUnit","Spring","Spring Security"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2019\/05\/spring-security-oauth-through-java-hipster.html","url":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit","name":"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#primaryimage"},"image":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","datePublished":"2019-05-13T05:30:39+00:00","dateModified":"2019-05-20T12:11:55+00:00","description":"Interested to learn about Java Hipster? Check our article explaining how to upgrade Upgrading Spring Security OAuth and JUnit Tests with java hipster.","breadcrumb":{"@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/spring-logo.jpg","width":150,"height":150,"caption":"spring-interview-questions-answers"},{"@type":"BreadcrumbList","@id":"https:\/\/developer.okta.com\/blog\/2019\/04\/15\/testing-spring-security-oauth-with-junit#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Upgrading Spring Security OAuth and JUnit Tests through the \ud83d\udc40 of a Java Hipster"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/54edd49deb980d7706e2af51514c3f7f","name":"Matt Raible","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/753d82443e50aed1ed2746573af191fe3e45c277ff3bd29873012a1b614355a7?s=96&d=mm&r=g","caption":"Matt Raible"},"description":"Java Champion and Developer Advocate @okta with a passion for skiing, mtn biking, VWs, &amp; good beer.","sameAs":["https:\/\/developer.okta.com","https:\/\/x.com\/mraible"],"url":"https:\/\/www.javacodegeeks.com\/author\/matt-raible"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/91727","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/13127"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=91727"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/91727\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/240"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=91727"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=91727"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=91727"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}