feat: implement Google OAuth support for Android and iOS

- Added support for Google OAuth with separate client IDs for Android and iOS.
- Updated `verify_google_id_token` to validate `aud` against both client IDs and check `email_verified`.
- Modified `google_oauth_handler` to accept and process the new client IDs.
- Enhanced security by enforcing explicit JWT algorithm validation.
- Updated mobile app to handle Google OAuth flow using `expo-auth-session`.
- Fixed API request to send `id_token` in snake_case as expected by the backend.
- Added necessary environment variables for Google client IDs in mobile app.
- Implemented intent filter for Google OAuth redirect in AndroidManifest.xml.
This commit is contained in:
2026-03-19 15:24:08 -03:00
parent 31c47fe69f
commit 34cbd4a861
16 changed files with 972 additions and 220 deletions
+78
View File
@@ -487,6 +487,84 @@ GET /api/v1/filaments/:id/label.svg?width_mm=22&height_mm=14&fields=color,name,q
---
## Mudanças Recentes (19/03/2026) — segunda entrada
### ✅ Google OAuth — suporte a client IDs Android e iOS
**Arquivos modificados**: `src/config.rs`, `src/adapters/inbound/auth_handler.rs`
**Problema**: o backend lia apenas `GOOGLE_CLIENT_ID` (Android). Tokens emitidos pelo fluxo iOS tinham `aud` diferente e eram rejeitados.
**Mudanças**:
- `Config` ganhou campo `google_client_id_ios: String` lido de `GOOGLE_CLIENT_ID_APPLE`
- `verify_google_id_token` aceita agora dois client IDs e valida `aud` contra ambos:
```rust
let valid_ids = [client_id_android, client_id_ios];
let audience_valid = valid_ids.iter().any(|id| !id.is_empty() && *id == aud);
if !audience_valid { return Err(AppError::Unauthorized); }
```
- Assinatura atualizada: `verify_google_id_token(id_token, client_id_android, client_id_ios)`
- Call site em `google_oauth_handler` passa `state.config.google_client_id` e `state.config.google_client_id_ios`
**Variável de ambiente adicionada**:
| Variável | Valor no .env |
| ---------------------- | ------------------------------------------------------------------ |
| `GOOGLE_CLIENT_ID` | `724520558909-bg5a7e4u24jmis8lgg41ucs0kv0nfp1v.apps.googleusercontent.com` |
| `GOOGLE_CLIENT_ID_APPLE` | `724520558909-v3kubsvmf3vda7fep8qaabenmdap53hs.apps.googleusercontent.com` |
---
## Mudanças Recentes (19/03/2026)
### ✅ Hardening de segurança — Google OAuth e JWT
**Arquivos modificados**: `src/adapters/inbound/auth_handler.rs`, `src/application/auth_service.rs`
#### Google OAuth — validação de `aud` e `email_verified`
**Problema**: a função `verify_google_id_token` recebia `_client_id` como parâmetro mas nunca o usava. Qualquer portador de um token Google válido — emitido para qualquer app — podia autenticar no MeowSpool.
**Correção** (`auth_handler.rs`):
```rust
// Valida audience: o token deve ter sido emitido para este app
let aud = payload["aud"].as_str().ok_or(AppError::Unauthorized)?;
if !client_id.is_empty() && aud != client_id {
tracing::warn!(aud, client_id, "Google id_token audience mismatch");
return Err(AppError::Unauthorized);
}
// Rejeita contas Google com e-mail não verificado
let email_verified = payload["email_verified"].as_str().unwrap_or("false");
if email_verified != "true" {
tracing::warn!("Google account email not verified");
return Err(AppError::Unauthorized);
}
```
- Parâmetro renomeado de `_client_id` para `client_id`
- Rejeições geram `tracing::warn!` para auditoria
#### JWT — algoritmo explícito
**Problema**: `Validation::default()` não fixava o algoritmo permitido, abrindo margem para ataques com algoritmos inesperados.
**Correção** (`auth_service.rs`): substituído `Validation::default()` por `Validation::new(Algorithm::HS256)` em ambos os pontos de decodificação:
```rust
// validate_access_token e decode_refresh_token:
let validation = Validation::new(Algorithm::HS256);
decode::<Claims>(token, &key, &validation)
```
`Algorithm` importado de `jsonwebtoken`.
---
## Mudanças Recentes (14/03/2026)
### ✅ Reenvio de e-mail de verificação