I have a Spring application that is secured using Oauth provided by Twitch. What I am trying to do is make it so that when the user clicks the logout button they have to reenter their Twitch credentials to log back into the site. From the reading I have done my understanding of the situation is that single sign off is fairly hard to achieve with Oauth. That said, Twitch's API seems to indicate that there is a way to tell them to invalidate an Oauth token: https://dev.twitch.tv/docs/authentication#revoking-access-tokens.
I have seen some information about a prompt=login parameter in OIDC but I have not been able to find any information about it or how to use it (on top of that I'm pretty sure that will require the users to reenter their credentials EVERY time rather than simply when they logout).
My initial approach to this problem was the number 1 answer in this thread but that did not actually change anything. I still was not required to enter my credentials upon trying to access one of the restricted endpoints, Spring simply quickly reauthenticated with Twitch and sent me through.
My current approach was to directly hit the endpoint in the Twitch api with a POST request (this was inspired by a comment in this thread). This approach is also not doing anything. I will include the code of that approach below.
I would much prefer to solve this problem with something built into Spring (holding out hope that there is something that I have somehow missed). An interesting thing I have been noticing happening is that when I hit /logout my browser will be redirected to Twitch's authorization endpoint which is making me think that for some reason Spring is trying to send a token revoke request to the authorization endpoint OR is logging me back into the endpoint as soon as I am logged out of it. Thought this was worth mentioning.
Any help replicating the initially mentioned behavior would be much appreciated.
SpringSecurityConfiguration:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SpringSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
//This allows users to access the "/" and "/Info" endpoints without authenticating with Twitch. To go anywhere else they will have to authenticate.
httpSecurity.antMatcher("/**").authorizeRequests().antMatchers("/", "/Info", "/token/deletion").permitAll().anyRequest().authenticated().and().oauth2Login().and()
//This configures logout tells spring to do the logout with the method in the logoutSuccessHandler
.logout().logoutSuccessUrl("http://localhost:8080/token/deletion").invalidateHttpSession(true).clearAuthentication(true).deleteCookies("JSESSIONID", "JWT");
}
application.properties:
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.security.oauth2.client.registration.twitch=twitch
spring.security.oauth2.client.registration.twitch.client-id=redacted
spring.security.oauth2.client.registration.twitch.client-secret=redacted
spring.security.oauth2.client.registration.twitch.client-authentication-method=post
spring.security.oauth2.client.registration.twitch.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.twitch.redirect-uri=http://localhost:8080/login/oauth2/code/twitch
spring.security.oauth2.client.registration.twitch.scope=user:read:email
spring.security.oauth2.client.registration.twitch.client-name=Twitch
spring.security.oauth2.client.provider.twitch.authorization-uri=https://id.twitch.tv/oauth2/authorize
spring.security.oauth2.client.provider.twitch.token-uri=https://id.twitch.tv/oauth2/token
spring.security.oauth2.client.provider.twitch.jwk-set-uri=https://id.twitch.tv/oauth2/keys
spring.security.oauth2.client.provider.twitch.user-info-uri=https://id.twitch.tv/oauth2/userinfo
spring.security.oauth2.client.provider.twitch.user-info-authentication-method=post
spring.security.oauth2.client.provider.twitch.user-name-attribute=sub
TokenRemovalController:
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@Controller
public class TokenRemovalController {
@RequestMapping("/token/deletion")
public void removeTokenFromTwitch(HttpServletResponse response, @RegisteredOAuth2AuthorizedClient("twitch") OAuth2AuthorizedClient authorizedClient) throws IOException {
//Get access token of current user
String accessToken = authorizedClient.getAccessToken().getTokenValue();
//POST Request to Twitch endpoint
URL url = new URL("https://id.twitch.tv/oauth2/revoke");
HttpsURLConnection https = (HttpsURLConnection)url.openConnection();
https.setRequestMethod("POST");
https.setDoOutput(true);
https.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
String data = "client_id=redacted&token=" + accessToken;
byte[] out = data.getBytes(StandardCharsets.UTF_8);
OutputStream stream = https.getOutputStream();
stream.write(out);
String redirectString = "/error";
if (https.getResponseCode() == 200) {
redirectString = "/Info";
}
https.disconnect();
response.sendRedirect(redirectString);
}
}
Project Structure:
Another thing I forgot to mention was that if I delete all of my browsers cookies then I do get logged out of my site. Is it potentially possible to replicate this effect when users attempt to log out (obviously without deleting all of the users other cookies)?