Команда Spring АйО перевела статью о том, как правильно настраивать безопасность на MCP серверах с использованием возможностей OAuth2 в свете новейшей спецификации MCP, вышедшей в свет 26-го марта 2025-го года, то есть совсем недавно.
Spring AI предлагает поддержку для Model Context Protocol или, сокращенно, MCP, что позволяет ИИ моделям взаимодействовать и получать доступ к внешним инструментам и ресурсам структурированно. С помощью Spring AI разработчики могут создавать свои собственные MCP сервера и давать ИИ моделям доступ к их возможностям всего в несколько строчек кода.
Авторизация и безопасность в MCP
MCP сервера могут работать локально, используя передачу по STDIO. Чтобы сделать MCP сервер доступным для внешнего мира, он должен предоставлять несколько стандартных HTTP эндпоинтов. В то время как MCP сервера, используемые локально и с целями тестирования, могут не требовать строгой аутентификации, продакшен деплойменты нуждаются в строжайшей безопасности и эффективном управлении permission-ами для доступных внешнему миру эндпоинтов. Эта проблема была решена в последней версии спецификации MCP (от 26-го марта 2025), которую выпустили на прошлой неделе. Она закладывает фундамент для безопасных коммуникаций между клиентами и серверами с использованием популярного протокола OAuth2.
Мы не собираемся делать полный обзор OAuth2 в рамках этой статьи, но немного освежить наши знания о нем будет полезно. В черновике спецификации MCP сервер описывается как одновременно и сервер ресурсов (он же OAuth2 Resource Server), и сервер авторизации (он же OAuth2 Authorization Server).
Будучи сервером ресурсов он выполняет проверки для авторизации входящих запросов, проверяя заголовок Authorization. Заголовок должен содержать OAuth2 access_token, который представляет из себя строку, описывающую “разрешения” (permissions-ы) клиента. Этот токен может быть JSON Web Token (JWT) или opaque token, который сам по себе не несет никакой информации. Если токен отсутствует или невалиден, (неправильно сформирован, истек, неверный получатель и т.д.), MCP сервер, будучи сервером ресурсов, отклоняет запрос. При использовании таких токенов типичный запрос может выглядеть вот так:
curl https://mcp.example.com/sse -H "Authorization: Bearer <a valid access token>"
В качестве сервера авторизации, MCP сервер должен также обладать способностью выпускать access_token`ы для клиентов безопасным образом. Прежде чем выпустить токен, сервер должен проверить креды клиента и, в некоторых случаях, identity клиента, который пытается получить доступ к серверу. Сервер авторизации принимает решения по характеристикам токена, таким как дата его истечения, scope-ы и т.д.
Используя Spring Security и Spring Authorization Server, мы можем легко добавить обе эти возможности к существующему Spring MCP серверу.

Добавление OAuth2 к вашему Spring MCP серверу
В приведенном примере мы добавим поддержку OAuth 2 к тестовому MCP серверу, который предоставляет дополнительные "погодные" данные (температура, влажность и т.д.) для LLM. Исходные коды MCP сервера можно найти в репозитории с примерами для Spring AI. Мы не будем заострять внимание на действиях клиентской стороны, только убедимся в том, что наш сервер может выпускать токены и валидировать их.
Прежде всего, импортируем необходимые нам Boot стартеры в pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId> </dependency>
Далее, сконфигурируем OAuth2 клиент в нашем файле application.properties, чтобы мы могли запрашивать токены доступа:
spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-id=mcp-client spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-secret={noop}secret spring.security.oauth2.authorizationserver.client.oidc-client.registration.client-authentication-methods=client_secret_basic spring.security.oauth2.authorizationserver.client.oidc-client.registration.authorization-grant-types=client_credentials
Это самый простой из возможных клиентов. Мы можем взаимодействовать с сервером авторизации напрямую через POST запросы, браузер не нужен, и мы будем использовать прописанные в коде логин и пароль mcp-client / secret.
Последний шаг — включить использование возможностей авторизационного сервера и сервера ресурсов. Мы сделаем это, создав конфигурационный класс для возможностей по безопасности, например, SecurityConfiguration, в котором мы дадим доступ к бину SecurityFilterChain:
import static org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer.authorizationServer; @Configuration @EnableWebSecurity class SecurityConfiguration { @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .with(authorizationServer(), Customizer.withDefaults()) .oauth2ResourceServer(resource -> resource.jwt(Customizer.withDefaults())) .csrf(CsrfConfigurer::disable) .cors(Customizer.withDefaults()) .build(); } }
Эта цепочка фильтров сделает несколько вещей:
Гарантирует, что каждый запрос аутентифицируется. Благодаря этому, наш MCP сервер будет разрешать только запросы с
access_token.Разрешает использование как Spring Authorization Server, так и Spring Resource Server.
Отключает CSRF (Cross-Site Request Forgery). MCP сервер не предназначен для взаимодействия с браузерами, поэтому CSRF-защита здесь не нужна.
Включает поддержку CORS (Cross-Origin Resource Sharing), чтобы мы могли продемонстрировать сервер при помощи MCP инспектора.
Эти действия обеспечивают безопасность нашему приложению, которое теперь будет принимать только те запросы, в которых есть токен доступа. В противном случае запросы будут отклонены с ошибкой HTTP 401 Unauthorized. Например:
curl http://localhost:8080/sse --fail-with-body # # Response: # # curl: (22) The requested URL returned error: 401
Чтобы использовать наш MCP сервер, нам сперва необходимо получить токен доступа. Мы используем client_credentials, выданные OAuth2, что используется в сценариях “от машины к машине” или “сервисный аккаунт”:
curl -XPOST http://localhost:8080/oauth2/token --data grant_type=client_credentials --user mcp-client:secret # # Response: # # {"access_token":"<YOUR-ACCESS-TOKEN>","token_type":"Bearer","expires_in":299}%
Копируем значение access_token. Оно начинается с букв "ey". Теперь мы можем использовать этот токен для создания запросов, и они должны быть успешными. Например, используя curl, вы сможете заменить YOUR_ACCESS_TOKEN скопированным выше значением:
curl http://localhost:8080/sse -H"Authorization: Bearer YOUR_ACCESS_TOKEN" # # Response: # # id:918d5ebe-9ae5-4b04-aae8-c1ff8cdbb6e0 # event:endpoint # data:/mcp/message?sessionId=918d5ebe-9ae5-4b04-aae8-c1ff8cdbb6e0
Можно также использовать токен доступа напрямую в MCP инспекторе, начиная с версии 0.6.0. Просто запустите инспектор и вставьте токен доступа в поле "Authentication > Bearer" в меню слева. Затем нажмите “Connect”: теперь у вас должна появиться возможность отправлять MCP вызовы.

Если вы хотите запустить эти программы самостоятельно, ��ы можете взять код примера из репозитория spring-ai-examples.
Что дальше?
В нашем примере мы реализовали базовые возможности OAuth2 в MCP сервере.
Очевидный следующий шаг — обновить MCP клиент и позволить ему аутентифицироваться на сервере с использованием OAuth2 authorization_code grant-а вместо client_credentials. При таком сценарии пользователи смогут залогиниться со своими собственными кредами и получить свои пользовательские токены, что позволяет более точно назначать пермишены, например с помощью Roles-Based Access Control (RBAC).
В будущем, мы также посмотрим на внешний сервер авторизации OAuth2 и выпуск токенов с его помощью, используя только возможности сервера ресурсов (OAuth2 Resource Server-а) внутри нашего MCP сервера.

Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.
