diff --git a/github/README.MD b/github/README.MD
index 08233ad..3e59bac 100644
--- a/github/README.MD
+++ b/github/README.MD
@@ -8,7 +8,7 @@
Для запуска понадобиться обзавестить своим **GitHub OAuth App**.
1. Переходим в [Developer settings](https://github.com/settings/developers)
-2. Создём новое OAuth приложение
+2. Создаём новое OAuth приложение

3. Заполняем обязательно следующие поля
- **Homepage URL**: `http://127.0.0.1:8080`
diff --git a/settings.gradle b/settings.gradle
index 4c71bac..bc1372e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,3 +2,4 @@ rootProject.name = 'spring-oauth2-examples'
include('discord')
include('github')
+include('twitch')
diff --git a/twitch/README.MD b/twitch/README.MD
new file mode 100644
index 0000000..6c8985b
--- /dev/null
+++ b/twitch/README.MD
@@ -0,0 +1,42 @@
+# Spring Boot + OAuth2 Twitch
+
+
+
+
+## Перед запуском
+### Создание Application
+Для запуска понадобиться обзавестить своим **Twitch Application**.
+
+1. Переходим в [Twitch Developers](https://dev.twitch.tv/console)
+2. Создаём новое OAuth приложение
+ 
+3. Заполняем поля
+ ⚠️ **Внимание!** Есть ряд ограничений.
+
+ Для **Name**:
+ - Не должен содежрать слово "twitch"
+
+ Для **OAuth Redirect URLs**:
+ - Если запуск **не** локальный, требуется HTTPS протокол
+ - Если запуск локальный, то вводить не `127.0.0.1`, а `localhost`
+
+ 
+4. После переходим в управление приложением
+ 
+5. Сгенерировать новый **Client Secret**
+ 
+ 
+
+### Настройка Spring
+Открываем файл `src/main/resources/application.yml` и указываем там **Client ID** и **Client Secret**:
+
+```yaml
+spring:
+ security:
+ oauth2:
+ client:
+ registration:
+ twitch:
+ client-id: 89fwqw0i5b9857n5orpz3sb3dyfhti
+ client-secret: mlatyu8twmzq69mx0um1hbahfi7p31
+```
diff --git a/twitch/build.gradle b/twitch/build.gradle
new file mode 100644
index 0000000..19982c8
--- /dev/null
+++ b/twitch/build.gradle
@@ -0,0 +1,21 @@
+plugins {
+ id 'org.springframework.boot' version '2.6.6'
+ id 'io.spring.dependency-management' version '1.0.11.RELEASE'
+ id 'java'
+}
+
+group = 'example.oauth2'
+version = '1.0-SNAPSHOT'
+sourceCompatibility = JavaVersion.VERSION_11
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation('org.springframework.boot:spring-boot-starter-web')
+ implementation('org.springframework.boot:spring-boot-starter-freemarker')
+
+ implementation('org.springframework.boot:spring-boot-starter-security')
+ implementation('org.springframework.security:spring-security-oauth2-client')
+}
diff --git a/twitch/docs/1.png b/twitch/docs/1.png
new file mode 100644
index 0000000..07aba9e
Binary files /dev/null and b/twitch/docs/1.png differ
diff --git a/twitch/docs/2.png b/twitch/docs/2.png
new file mode 100644
index 0000000..672ada3
Binary files /dev/null and b/twitch/docs/2.png differ
diff --git a/twitch/docs/3.png b/twitch/docs/3.png
new file mode 100644
index 0000000..5e19a70
Binary files /dev/null and b/twitch/docs/3.png differ
diff --git a/twitch/docs/4.png b/twitch/docs/4.png
new file mode 100644
index 0000000..24fe5a6
Binary files /dev/null and b/twitch/docs/4.png differ
diff --git a/twitch/docs/5.png b/twitch/docs/5.png
new file mode 100644
index 0000000..3720813
Binary files /dev/null and b/twitch/docs/5.png differ
diff --git a/twitch/docs/twitch.svg b/twitch/docs/twitch.svg
new file mode 100644
index 0000000..b9e12a7
--- /dev/null
+++ b/twitch/docs/twitch.svg
@@ -0,0 +1,19 @@
+
+
diff --git a/twitch/src/main/java/example/oauth2/twitch/ApplicationTwitch.java b/twitch/src/main/java/example/oauth2/twitch/ApplicationTwitch.java
new file mode 100644
index 0000000..7df7ace
--- /dev/null
+++ b/twitch/src/main/java/example/oauth2/twitch/ApplicationTwitch.java
@@ -0,0 +1,13 @@
+package example.oauth2.twitch;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ApplicationTwitch {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApplicationTwitch.class, args);
+ }
+
+}
diff --git a/twitch/src/main/java/example/oauth2/twitch/config/MvcConfig.java b/twitch/src/main/java/example/oauth2/twitch/config/MvcConfig.java
new file mode 100644
index 0000000..46f9f7a
--- /dev/null
+++ b/twitch/src/main/java/example/oauth2/twitch/config/MvcConfig.java
@@ -0,0 +1,15 @@
+package example.oauth2.twitch.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MvcConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addViewControllers(ViewControllerRegistry registry) {
+ registry.addViewController("/").setViewName("index");
+ registry.addViewController("/secret").setViewName("secret");
+ }
+}
diff --git a/twitch/src/main/java/example/oauth2/twitch/config/TwitchOAuth2Config.java b/twitch/src/main/java/example/oauth2/twitch/config/TwitchOAuth2Config.java
new file mode 100644
index 0000000..977f24a
--- /dev/null
+++ b/twitch/src/main/java/example/oauth2/twitch/config/TwitchOAuth2Config.java
@@ -0,0 +1,59 @@
+package example.oauth2.twitch.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
+import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+
+/*
+Отдельное спасибо
+- https://www.baeldung.com/spring-security-5-oauth2-login
+- https://github.com/spring-projects/spring-security/blob/main/config/src/main/java/org/springframework/security/config/oauth2/client/CommonOAuth2Provider.java
+- https://discuss.dev.twitch.tv/t/springboot-oauth2-integration-with-twitch/35011
+- https://www.youtube.com/watch?v=n9oO5D-aHCY
+ */
+
+@Configuration
+public class TwitchOAuth2Config {
+ private static final String TWITCH_CLIENT_PROPERTY_KEY = "spring.security.oauth2.client.registration.twitch";
+ private static final String DEFAULT_REDIRECT_URL = "{baseUrl}/{action}/oauth2/code/{registrationId}";
+
+ private final Environment env;
+
+ public TwitchOAuth2Config(Environment env) {
+ this.env = env;
+ }
+
+ @Bean
+ public ClientRegistrationRepository twitchClientRegistrationRepository() {
+ String clientId = env.getProperty(TWITCH_CLIENT_PROPERTY_KEY + ".client-id");
+ String clientSecret = env.getProperty(TWITCH_CLIENT_PROPERTY_KEY + ".client-secret");
+
+ ClientRegistration clientRegistration = ClientRegistration.withRegistrationId("twitch")
+ .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_POST)
+ .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
+ .redirectUri(DEFAULT_REDIRECT_URL)
+ .scope("user:read:email")
+ .authorizationUri("https://id.twitch.tv/oauth2/authorize")
+ .tokenUri("https://id.twitch.tv/oauth2/token")
+ .userInfoUri("https://id.twitch.tv/oauth2/userinfo")
+ .userNameAttributeName("preferred_username")
+ .clientName("Twitch")
+ .clientId(clientId)
+ .clientSecret(clientSecret)
+ .build();
+
+ return new InMemoryClientRegistrationRepository(clientRegistration);
+ }
+
+ @Bean
+ public OAuth2AuthorizedClientService twitchAuthorizedClientService(ClientRegistrationRepository clientRegistrationRepository) {
+ return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
+ }
+}
diff --git a/twitch/src/main/java/example/oauth2/twitch/config/WebSecurityConfig.java b/twitch/src/main/java/example/oauth2/twitch/config/WebSecurityConfig.java
new file mode 100644
index 0000000..58f6d77
--- /dev/null
+++ b/twitch/src/main/java/example/oauth2/twitch/config/WebSecurityConfig.java
@@ -0,0 +1,37 @@
+package example.oauth2.twitch.config;
+
+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;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
+
+@EnableWebSecurity
+@Configuration
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+ private final ClientRegistrationRepository clientRegistrationRepository;
+ private final OAuth2AuthorizedClientService authorizedClientService;
+
+ public WebSecurityConfig(ClientRegistrationRepository twitchClientRegistrationRepository,
+ OAuth2AuthorizedClientService twitchAuthorizedClientService) {
+ this.clientRegistrationRepository = twitchClientRegistrationRepository;
+ this.authorizedClientService = twitchAuthorizedClientService;
+ }
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ //@formatter:off
+ http
+ .authorizeRequests()
+ .antMatchers("/").permitAll() //Доступ разрешен всем пользователей
+ .anyRequest().authenticated() //Все остальные страницы требуют аутентификации
+ .and()
+ .oauth2Login()
+ .clientRegistrationRepository(clientRegistrationRepository)
+ .authorizedClientService(authorizedClientService)
+ ;
+ //@formatter:on
+ }
+}
diff --git a/twitch/src/main/resources/application.yml b/twitch/src/main/resources/application.yml
new file mode 100644
index 0000000..ed75233
--- /dev/null
+++ b/twitch/src/main/resources/application.yml
@@ -0,0 +1,17 @@
+server:
+ address: 127.0.0.1
+ port: 8080
+
+debug: false
+
+spring:
+ freemarker:
+ template-loader-path: classpath:/templates
+ suffix: .ftlh
+ security:
+ oauth2:
+ client:
+ registration:
+ twitch:
+ client-id: 89fwqw0i5b9857n5orpz3sb3dyfhti
+ client-secret: mlatyu8twmzq69mx0um1hbahfi7p31
diff --git a/twitch/src/main/resources/templates/includes/foother.ftlh b/twitch/src/main/resources/templates/includes/foother.ftlh
new file mode 100644
index 0000000..308b1d0
--- /dev/null
+++ b/twitch/src/main/resources/templates/includes/foother.ftlh
@@ -0,0 +1,2 @@
+