feat(swagger): OAuth2/Keycloak PKCE flow в Swagger UI + docs links

OpenApiConfig:
- Добавлена OAuth2 security scheme (authorization_code flow с Keycloak
  realm `nstart`). Auth/token URLs из ordinis.openapi.oauth.issuer-uri
  configuration property (default: auth.nstart.space/realms/nstart).
- BearerAuth scheme сохранён secondary — для pre-issued tokens из CI/scripts.
- Servers list переупорядочен — prod первый, staging второй.
- Description обновлён с pointer на /docs/ для full integration guide.

application.yml:
- springdoc.swagger-ui.oauth: client-id (env override), use-pkce-with-
  authorization-code-grant=true. Public client `ordinis-swagger`
  настраивается отдельно в Keycloak — see keycloak-setup-swagger-client.md
  в ordinis-infra repo.
- ORDINIS_OPENAPI_OAUTH_ISSUER_URI env var для override realm на разных
  окружениях.

docs/integration/api/read-endpoints.md:
- Swagger UI section обновлён: акцент на Authorize button + Keycloak
  PKCE login (no client_secret needed), tip про bearerAuth fallback.

docs/index.md:
- Добавлен tab "Я хочу пощупать API" с link на Swagger UI.

После deploy:
- https://ordinis.k8s.264.nstart.cloud/swagger-ui.html  — Swagger UI
- https://ordinis.k8s.264.nstart.cloud/v3/api-docs      — OpenAPI spec
Authorize → выбрать oauth2 → Keycloak login (PKCE) → Try it out с JWT.
This commit is contained in:
Zimin A.N.
2026-05-08 00:08:29 +03:00
parent c12f515f43
commit b601c4636f
4 changed files with 63 additions and 7 deletions
@@ -5,9 +5,13 @@ import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.Scopes;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -23,8 +27,15 @@ import java.util.List;
@Configuration
public class OpenApiConfig {
/** Keycloak issuer URI — base для auth/token endpoints. По умолчанию prod realm. */
@Value("${ordinis.openapi.oauth.issuer-uri:https://auth.nstart.space/realms/nstart}")
private String oauthIssuer;
@Bean
public OpenAPI ordinisOpenAPI() {
String authUrl = oauthIssuer + "/protocol/openid-connect/auth";
String tokenUrl = oauthIssuer + "/protocol/openid-connect/token";
return new OpenAPI()
.info(new Info()
.title("Ordinis НСИ ЦУОД — Admin / Read API")
@@ -43,28 +54,46 @@ public class OpenApiConfig {
но с поддержкой `?lang=ru/en` для flatten i18n и `?at=<iso>` для
bitemporal queries.
**Auth:** Bearer JWT от Keycloak (`auth.nstart.space/realms/nstart`).
Роль `ordinis-public` достаточна для чтения. На staging авторизация
может быть выключена (`ORDINIS_AUTH_REQUIRED=false`).
**Авторизация:**
- **Try it out** в Swagger UI — нажми кнопку Authorize → выбери
"oauth2" → Keycloak login flow (PKCE, без client_secret).
- **m2m интеграции** — service account через client_credentials
flow (см. /docs/integration/api/auth.html).
**Документация интеграции:** `docs/integration/altum-imaging-order.md`,
`docs/tech/api-integration.md`.
**Полная интеграция:** https://ordinis.k8s.264.nstart.cloud/docs/
""")
.contact(new Contact()
.name("Ordinis team")
.email("zimin.an@nstart.space"))
.license(new License().name("Internal").url("https://nstart.space")))
.servers(List.of(
new Server().url("https://ordinis.k8s.265.nstart.cloud").description("staging (cluster.265)"),
new Server().url("https://ordinis.k8s.264.nstart.cloud").description("prod (cluster.142)"),
new Server().url("https://ordinis.k8s.265.nstart.cloud").description("staging (cluster.265)"),
new Server().url("http://localhost:8080").description("local dev")))
.components(new Components()
// Primary scheme: OAuth2 PKCE (для interactive Swagger UI users).
// Keycloak realm `nstart`, public client `ordinis-swagger` с PKCE.
.addSecuritySchemes("oauth2",
new SecurityScheme()
.type(SecurityScheme.Type.OAUTH2)
.description("Keycloak OAuth2 — interactive login через Swagger UI с PKCE flow.")
.flows(new OAuthFlows()
.authorizationCode(new OAuthFlow()
.authorizationUrl(authUrl)
.tokenUrl(tokenUrl)
.scopes(new Scopes()
.addString("openid", "OIDC user profile")
.addString("profile", "User profile")
.addString("email", "Email")))))
// Secondary scheme: pre-issued bearer token (для curl / scripts).
.addSecuritySchemes("bearerAuth",
new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.description("Keycloak realm `nstart`. Service account для m2m: попросить у Ordinis team.")))
.description("Pre-issued JWT (например через client_credentials у service account).")))
// Both schemes available — user picks one в Authorize dialog.
.addSecurityItem(new SecurityRequirement().addList("oauth2"))
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"));
}
}