Modern Authorization Code Flow + PKCE - the recommended OAuth 2.1 approach for mobile apps (2026).
File: pubspec.yaml
dependencies:
flutter_appauth: ^12.0.0 # OAuth 2.0 with PKCE supportFile: android/app/src/main/AndroidManifest.xml
Added redirect activity:
<activity
android:name="net.openid.appauth.RedirectUriReceiverActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="gitdoit"
android:host="oauth2redirect" />
</intent-filter>
</activity>File: ios/Runner/Info.plist
Added custom URL scheme:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>gitdoit</string>
</array>
</dict>
</array>File: lib/services/github_auth_service.dart
Modern authentication service:
- Uses Authorization Code Flow + PKCE
- No manual code entry
- One-tap login via browser
- Secure token storage
- Automatic PKCE code verifier generation
File: lib/screens/onboarding_screen.dart
Simplified login flow:
Future<void> _loginWithOAuth() async {
final token = await _githubAuth.signIn();
// Token received → navigate to dashboard
}1. User clicks "Login with GitHub"
↓
2. System browser opens (Chrome/Safari)
↓
3. User logs in to GitHub
↓
4. User authorizes GitDoIt app
↓
5. GitHub redirects to: gitdoit://oauth2redirect?code=AUTH_CODE
↓
6. App receives authorization code
↓
7. App exchanges code for access token (with PKCE)
↓
8. Token stored in FlutterSecureStorage
↓
9. User logged in! ✅
- Go to https://github.com/settings/developers
- Click "New OAuth App"
- Fill in:
Application name: GitDoIt Homepage URL: https://github.com/berlogabob/flutter-github-issues-todo Authorization callback URL: gitdoit://oauth2redirect - Click "Register application"
- Copy Client ID (e.g.,
Iv1.xxxxxxxxxxxx)
cp .env.default .env
nano .envAdd your Client ID:
GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxflutter run- Click "Login with GitHub"
- Browser opens GitHub login
- Log in and authorize
- Redirected back to app
- Logged in! ✅
| Feature | Device Flow (Old) | PKCE Flow (New) |
|---|---|---|
| User Experience | Enter 8-digit code | One-tap login |
| Steps | 5+ steps | 2 steps |
| Security | Basic | PKCE (more secure) |
| Browser | Manual copy/paste | Automatic redirect |
| Recommended | ❌ Deprecated | ✅ Recommended 2026 |
What it does:
- Prevents authorization code interception attacks
- Generates random
code_verifierper login - Creates
code_challengefrom verifier - GitHub validates challenge on token exchange
Why it's better:
- No client secret needed (safe for mobile apps)
- Protects against man-in-the-middle attacks
- Required by OAuth 2.1 for public clients
Format: gitdoit://oauth2redirect
Why custom scheme:
- Works on Android and iOS
- No need for HTTPS domain
- Instant app launch after authorization
Configuration:
- Android:
AndroidManifest.xmlintent-filter - iOS:
Info.plistCFBundleURLTypes - GitHub OAuth App: Authorization callback URL
Fix:
nano .env
# Add: GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxxCheck:
<!-- AndroidManifest.xml -->
<data android:scheme="gitdoit" android:host="oauth2redirect" />Make sure scheme is lowercase.
Check:
<!-- Info.plist -->
<key>CFBundleURLSchemes</key>
<array>
<string>gitdoit</string>
</array>Possible causes:
- User closed browser
- Network error
- Invalid Client ID
Check logs:
flutter run --verbose 2>&1 | grep "GitHubAuthService"- PKCE prevents code interception
- No client secret in app
- Tokens in FlutterSecureStorage
- HTTPS for all GitHub API calls
- Don't commit
.envto git - Don't log tokens
- Don't use HTTP (only HTTPS)
- Don't store tokens in plain text
- ✅ Create GitHub OAuth App
- ✅ Add Client ID to
.env - ✅ Configure redirect URI in GitHub
- ✅ Run
flutter run
- Test on physical Android device
- Test on physical iOS device
- Test token refresh (if implemented)
- Test logout and re-login
// Login
final token = await GitHubAuthService().signIn();
// Logout
await GitHubAuthService().signOut();
// Get token
final token = await GitHubAuthService().getAccessToken();
// Check if logged in
final isLoggedIn = await GitHubAuthService().isLoggedIn();What Changed:
- ✅ Replaced Device Flow with PKCE
- ✅ Added flutter_appauth package
- ✅ Configured Android/iOS redirect
- ✅ Created modern auth service
- ✅ Simplified login UX
Benefits:
- ✅ One-tap login (no code entry)
- ✅ More secure (PKCE)
- ✅ Better UX (native browser)
- ✅ Recommended by GitHub
Setup:
- Create GitHub OAuth App
- Add Client ID to .env
- Run app
- Login works! ✅
This is the modern, production-ready way to authenticate with GitHub in 2026! 🚀