Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusImplementar seguridad OAuth en API REST de Spring con GitHub
La implementación de OAuth 2.0 con GitHub en una API REST de Spring Boot requiere configurar tanto el cliente OAuth como los endpoints de seguridad. A diferencia de las aplicaciones web tradicionales, nuestra API REST devolverá respuestas JSON y manejará la autenticación de forma stateless.
Configuración inicial del proyecto
Primero necesitamos agregar las dependencias necesarias en nuestro pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Configuración de GitHub OAuth App
Para conectar con GitHub, necesitamos registrar nuestra aplicación en GitHub y obtener las credenciales OAuth. Ve a GitHub Settings > Developer settings > OAuth Apps y crea una nueva aplicación con:
- Application name: Tu nombre de aplicación
- Homepage URL:
http://localhost:8080
- Authorization callback URL:
http://localhost:8080/login/oauth2/code/github
GitHub te proporcionará un Client ID
y Client Secret
que necesitaremos para la configuración.
Configuración de propiedades
En application.yml
, configuramos los parámetros de OAuth:
spring:
security:
oauth2:
client:
registration:
github:
client-id: ${GITHUB_CLIENT_ID}
client-secret: ${GITHUB_CLIENT_SECRET}
scope:
- user:email
- read:user
provider:
github:
authorization-uri: https://github.com/login/oauth/authorize
token-uri: https://github.com/login/oauth/access_token
user-info-uri: https://api.github.com/user
user-name-attribute: id
server:
port: 8080
Configuración de Spring Security
Creamos la clase de configuración que define cómo manejar la autenticación OAuth:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/", "/login", "/error").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
)
.logout(logout -> logout
.logoutSuccessUrl("/")
.permitAll()
)
.csrf(csrf -> csrf.disable());
return http.build();
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new OAuth2AuthenticationSuccessHandler();
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new OAuth2AuthenticationFailureHandler();
}
}
Manejadores de autenticación
Implementamos manejadores personalizados para responder con JSON en lugar de redirecciones:
@Component
public class OAuth2AuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
Map<String, Object> attributes = token.getPrincipal().getAttributes();
// Crear respuesta JSON con información del usuario
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("name", attributes.get("name"));
userInfo.put("email", attributes.get("email"));
userInfo.put("avatar_url", attributes.get("avatar_url"));
userInfo.put("authenticated", true);
response.setContentType("application/json");
response.setStatus(HttpStatus.OK.value());
ObjectMapper mapper = new ObjectMapper();
response.getWriter().write(mapper.writeValueAsString(userInfo));
}
}
@Component
public class OAuth2AuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception) throws IOException {
Map<String, Object> errorResponse = new HashMap<>();
errorResponse.put("error", "authentication_failed");
errorResponse.put("message", "No se pudo autenticar con GitHub");
errorResponse.put("authenticated", false);
response.setContentType("application/json");
response.setStatus(HttpStatus.UNAUTHORIZED.value());
ObjectMapper mapper = new ObjectMapper();
response.getWriter().write(mapper.writeValueAsString(errorResponse));
}
}
Controlador REST para manejo de autenticación
Creamos un controlador que proporciona endpoints REST para la autenticación:
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@GetMapping("/user")
public ResponseEntity<Map<String, Object>> getCurrentUser(Authentication authentication) {
if (authentication == null || !authentication.isAuthenticated()) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(Map.of("authenticated", false));
}
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
Map<String, Object> attributes = token.getPrincipal().getAttributes();
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("id", attributes.get("id"));
userInfo.put("name", attributes.get("name"));
userInfo.put("email", attributes.get("email"));
userInfo.put("avatar_url", attributes.get("avatar_url"));
userInfo.put("authenticated", true);
return ResponseEntity.ok(userInfo);
}
@GetMapping("/status")
public ResponseEntity<Map<String, Object>> getAuthStatus(Authentication authentication) {
boolean isAuthenticated = authentication != null && authentication.isAuthenticated();
return ResponseEntity.ok(Map.of(
"authenticated", isAuthenticated,
"provider", isAuthenticated ? "github" : null
));
}
}
Controlador de recursos protegidos
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
Ejemplo de un controlador que requiere autenticación para acceder:
@RestController
@RequestMapping("/api/protected")
public class ProtectedController {
@GetMapping("/profile")
public ResponseEntity<Map<String, Object>> getUserProfile(Authentication authentication) {
OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication;
Map<String, Object> attributes = token.getPrincipal().getAttributes();
// Procesar información adicional del usuario
Map<String, Object> profile = new HashMap<>();
profile.put("username", attributes.get("login"));
profile.put("company", attributes.get("company"));
profile.put("location", attributes.get("location"));
profile.put("public_repos", attributes.get("public_repos"));
profile.put("followers", attributes.get("followers"));
return ResponseEntity.ok(profile);
}
@GetMapping("/dashboard")
public ResponseEntity<Map<String, Object>> getDashboard(Authentication authentication) {
String username = authentication.getName();
Map<String, Object> dashboard = new HashMap<>();
dashboard.put("welcome_message", "Bienvenido " + username);
dashboard.put("last_login", new Date());
dashboard.put("permissions", List.of("read", "write"));
return ResponseEntity.ok(dashboard);
}
}
Página de inicio para OAuth
Para facilitar el flujo de autenticación, creamos un endpoint simple que inicie el proceso:
@Controller
public class LoginController {
@GetMapping("/")
public ResponseEntity<Map<String, String>> home() {
Map<String, String> response = new HashMap<>();
response.put("message", "API REST con OAuth GitHub");
response.put("login_url", "/oauth2/authorization/github");
response.put("status_url", "/api/auth/status");
return ResponseEntity.ok(response);
}
@GetMapping("/login")
public void login(HttpServletResponse response) throws IOException {
// Redirige automáticamente a GitHub OAuth
response.sendRedirect("/oauth2/authorization/github");
}
}
Variables de entorno
Para mayor seguridad, configura las credenciales como variables de entorno:
export GITHUB_CLIENT_ID=tu_client_id_aqui
export GITHUB_CLIENT_SECRET=tu_client_secret_aqui
O crea un archivo .env
en el directorio raíz del proyecto:
GITHUB_CLIENT_ID=tu_client_id_aqui
GITHUB_CLIENT_SECRET=tu_client_secret_aqui
Flujo de autenticación
El flujo completo funciona de la siguiente manera:
- 1. El usuario accede a
/login
o/oauth2/authorization/github
- 2. Spring Security redirige a GitHub para autenticación
- 3. GitHub redirige de vuelta con el código de autorización
- 4. Spring Security intercambia el código por un token de acceso
- 5. Se obtiene la información del usuario desde la API de GitHub
- 6. El usuario queda autenticado y puede acceder a endpoints protegidos
Esta implementación proporciona una base sólida para integrar OAuth 2.0 con GitHub en tu API REST, manteniendo la simplicidad mientras ofrece la funcionalidad necesaria para autenticar usuarios de forma segura.
Aprendizajes de esta lección de SpringBoot
- Comprender cómo configurar una aplicación OAuth en GitHub para obtener credenciales.
- Aprender a integrar OAuth 2.0 en una API REST con Spring Boot y Spring Security.
- Configurar manejadores personalizados para respuestas JSON en autenticación exitosa o fallida.
- Crear controladores REST que gestionen la autenticación y acceso a recursos protegidos.
- Entender el flujo completo de autenticación OAuth 2.0 con GitHub en un entorno stateless.
Completa este curso de SpringBoot y certifícate
Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs