feat(mobile): Implement Keycloak WebView authentication with HTTP callback
- Replace flutter_appauth with custom WebView implementation to resolve deep link issues - Add KeycloakWebViewAuthService with integrated WebView for seamless authentication - Configure Android manifest for HTTP cleartext traffic support - Add network security config for development environment (192.168.1.11) - Update Keycloak client to use HTTP callback endpoint (http://192.168.1.11:8080/auth/callback) - Remove obsolete keycloak_auth_service.dart and temporary scripts - Clean up dependencies and regenerate injection configuration - Tested successfully on multiple Android devices (Xiaomi 2201116TG, SM A725F) BREAKING CHANGE: Authentication flow now uses WebView instead of external browser - Users will see Keycloak login page within the app instead of browser redirect - Resolves ERR_CLEARTEXT_NOT_PERMITTED and deep link state management issues - Maintains full OIDC compliance with PKCE flow and secure token storage Technical improvements: - WebView with custom navigation delegate for callback handling - Automatic token extraction and user info parsing from JWT - Proper error handling and user feedback - Consistent authentication state management across app lifecycle
This commit is contained in:
149
keycloak-mobile-client-config.md
Normal file
149
keycloak-mobile-client-config.md
Normal file
@@ -0,0 +1,149 @@
|
||||
# Configuration Client Mobile Keycloak pour UnionFlow
|
||||
|
||||
## Objectif
|
||||
Configurer un client Keycloak spécifique pour l'application mobile UnionFlow avec authentification OIDC.
|
||||
|
||||
## Étapes de Configuration
|
||||
|
||||
### 1. Créer le Client Mobile
|
||||
1. Accéder à Keycloak Admin Console: http://localhost:8180/admin
|
||||
2. Sélectionner le realm **unionflow**
|
||||
3. Aller dans **Clients** → **Create client**
|
||||
|
||||
### 2. Configuration de Base
|
||||
- **Client type**: OpenID Connect
|
||||
- **Client ID**: `unionflow-mobile`
|
||||
- **Name**: `UnionFlow Mobile App`
|
||||
- **Description**: `Application mobile UnionFlow avec authentification OIDC`
|
||||
|
||||
### 3. Configuration Capability
|
||||
- **Client authentication**: OFF (Public client pour mobile)
|
||||
- **Authorization**: OFF (pas besoin pour l'app mobile)
|
||||
- **Standard flow**: ON (Authorization Code Flow)
|
||||
- **Direct access grants**: OFF (pas recommandé pour mobile)
|
||||
- **Implicit flow**: OFF (deprecated)
|
||||
- **Service accounts roles**: OFF
|
||||
|
||||
### 4. Configuration Login Settings
|
||||
- **Root URL**: `com.unionflow.mobile://`
|
||||
- **Home URL**: `com.unionflow.mobile://home`
|
||||
- **Valid redirect URIs**:
|
||||
- `com.unionflow.mobile://login-callback`
|
||||
- `com.unionflow.mobile://login-callback/*`
|
||||
- **Valid post logout redirect URIs**:
|
||||
- `com.unionflow.mobile://logout-callback`
|
||||
- `com.unionflow.mobile://logout-callback/*`
|
||||
- **Web origins**: `+` (pour permettre CORS depuis l'app)
|
||||
|
||||
### 5. Configuration Advanced Settings
|
||||
- **Access Token Lifespan**: 15 minutes
|
||||
- **Client Session Idle**: 30 minutes
|
||||
- **Client Session Max**: 12 hours
|
||||
- **Proof Key for Code Exchange Code Challenge Method**: S256 (PKCE pour sécurité mobile)
|
||||
|
||||
### 6. Configuration des Scopes
|
||||
Dans **Client scopes**, s'assurer que les scopes suivants sont assignés:
|
||||
- **openid** (Default)
|
||||
- **profile** (Default)
|
||||
- **email** (Default)
|
||||
- **roles** (Default)
|
||||
|
||||
### 7. Configuration des Mappers
|
||||
Ajouter des mappers personnalisés si nécessaire:
|
||||
|
||||
#### Mapper: audience
|
||||
- **Name**: audience
|
||||
- **Mapper Type**: Audience
|
||||
- **Included Client Audience**: unionflow-server
|
||||
- **Add to access token**: ON
|
||||
|
||||
#### Mapper: roles
|
||||
- **Name**: client-roles
|
||||
- **Mapper Type**: User Client Role
|
||||
- **Client ID**: unionflow-server
|
||||
- **Token Claim Name**: resource_access.unionflow-server.roles
|
||||
- **Add to access token**: ON
|
||||
|
||||
### 8. Test de Configuration
|
||||
|
||||
#### Test 1: Authorization URL
|
||||
```
|
||||
http://localhost:8180/realms/unionflow/protocol/openid-connect/auth?client_id=unionflow-mobile&redirect_uri=com.unionflow.mobile://login-callback&response_type=code&scope=openid%20profile%20email%20roles&code_challenge=CHALLENGE&code_challenge_method=S256
|
||||
```
|
||||
|
||||
#### Test 2: Token Exchange
|
||||
```bash
|
||||
curl -X POST "http://localhost:8180/realms/unionflow/protocol/openid-connect/token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-d "grant_type=authorization_code&client_id=unionflow-mobile&code=AUTHORIZATION_CODE&redirect_uri=com.unionflow.mobile://login-callback&code_verifier=VERIFIER"
|
||||
```
|
||||
|
||||
### 9. Configuration Android (android/app/src/main/AndroidManifest.xml)
|
||||
```xml
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme">
|
||||
|
||||
<!-- Intent filter pour les redirections OAuth -->
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="com.unionflow.mobile" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Intent filter standard -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
```
|
||||
|
||||
### 10. Configuration iOS (ios/Runner/Info.plist)
|
||||
```xml
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>com.unionflow.mobile</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>com.unionflow.mobile</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
```
|
||||
|
||||
### 11. Validation de la Configuration
|
||||
|
||||
#### Vérifications à effectuer:
|
||||
1. ✅ Client créé avec le bon type (Public)
|
||||
2. ✅ Redirect URIs configurées correctement
|
||||
3. ✅ PKCE activé (S256)
|
||||
4. ✅ Scopes appropriés assignés
|
||||
5. ✅ Mappers de rôles configurés
|
||||
6. ✅ Configuration mobile (Android/iOS) ajoutée
|
||||
|
||||
#### Tests fonctionnels:
|
||||
1. **Test d'autorisation**: L'app peut ouvrir le navigateur pour l'auth
|
||||
2. **Test de callback**: L'app reçoit le code d'autorisation
|
||||
3. **Test de token**: L'app peut échanger le code contre des tokens
|
||||
4. **Test d'API**: L'app peut appeler les APIs backend avec le token
|
||||
|
||||
### 12. Sécurité Mobile
|
||||
|
||||
#### Bonnes pratiques implémentées:
|
||||
- **PKCE**: Protection contre l'interception du code d'autorisation
|
||||
- **Client Public**: Pas de secret stocké dans l'app
|
||||
- **Deep Links sécurisés**: Schéma d'URL spécifique à l'app
|
||||
- **Token sécurisé**: Stockage dans FlutterSecureStorage
|
||||
- **Refresh automatique**: Gestion transparente de l'expiration
|
||||
|
||||
## Résultat Attendu
|
||||
- ✅ Authentification OIDC fonctionnelle depuis l'app mobile
|
||||
- ✅ Tokens JWT valides pour les appels API backend
|
||||
- ✅ Gestion automatique du refresh des tokens
|
||||
- ✅ Déconnexion propre avec invalidation côté Keycloak
|
||||
Reference in New Issue
Block a user