Firebase Google Sign-In
s Overview
system authentication using Firebase Authentication with Backend API
for verifying and manage users.
Overall structure
System includes 4 parts:
1 2
Mobile App Google Sign-In
Initialize login User authentication
3 4
Firebase Auth Backend API
Issue ID Token Verify & create tokens
Main flow:
1. User press "Sign in with Google"
2. Mobile calls Google Sign-In SDK
3. Google reponses Google credentials
4. Mobile uses credentials sign in Firebase
5. Firebase gives Firebase ID Token (JWT)
6. Mobile sends ID Token lên Backend
7. Backend verify token using Firebase Admin SDK
8. Backend create/use user and issue access/refresh tokens
9. Mobile saves tokens and redirect to app
MOBILE APP (Flutter)
1. Dependencies
firebase_core: ^3.8.1
firebase_auth: ^5.3.3
google_sign_in: ^6.2.2
2. Firebase Configuration
Firebase Options (Auto-generated)
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyB...',
appId: '1:123456789:android:abc...',
messagingSenderId: '123456789',
projectId: 'moneya-5df03',
storageBucket: '[Link]',
);
Firebase Initialization
void main() async {
[Link]();
await [Link](
options: [Link],
);
runApp(MyApp());
}
3. Google Sign-In Flow (6 Steps)
Future<(User?, Failure?)> signInWithGoogle() async {
try {
// STEP 1: Khßi t¿o Google Sign In
final GoogleSignIn googleSignIn = GoogleSignIn();
await [Link]();
final GoogleSignInAccount? googleUser = await [Link]();
if (googleUser == null) {
return (null, const Failure('User cancelled'));
}
// STEP 2: Lây Google Authentication Details
final GoogleSignInAuthentication googleAuth = await [Link];
// STEP 3: T¿o Firebase Credential
final OAuthCredential credential = [Link](
accessToken: [Link],
idToken: [Link],
);
// STEP 4: ng nh¿p Firebase vßi Credential
final UserCredential userCredential = await [Link](credential);
// STEP 5: Lây Firebase ID Token ( JWT)
final String? idToken = await [Link]?.getIdToken(true);
if (idToken == null) {
return (null, const Failure('Failed to get Firebase ID token'));
}
// STEP 6: Gÿi Firebase ID Token lên Backend
final userModel = await _remoteDatasource.signInWithGoogle(idToken);
return ([Link](), null);
} catch (e) {
return (null, Failure([Link]()));
}
}
4. Backend Communication
Future signInWithGoogle(String idToken) async {
final response = await _dio.post(
'/auth/firebase-signin',
data: {'idToken': idToken},
);
final body = _extractResponseBody(response);
_checkResponseStatus(body);
final dataNode = _extractDataNode(body);
await _saveTokensFromResponse(dataNode);
return [Link](dataNode);
}
5. Token Management
await [Link](accessToken);
await [Link](refreshToken);
class TokenInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
final token = await [Link]();
if (token != null) {
[Link]['Authorization'] = 'Bearer $token';
}
[Link](options);
}
}
Î BACKEND (.NET)
1. Dependencies
dotnet add package FirebaseAdmin
dotnet add package [Link]
dotnet add package [Link]
dotnet add package [Link]
2. Firebase Admin SDK Setup
Configuration
{
"Firebase": {
"ProjectId": "moneya-5df03",
"CredentialsPath": "path/to/[Link]"
}
}
Initialization
if ([Link] == null) {
var credPath = [Link]["Firebase:CredentialsPath"];
var projectId = [Link]["Firebase:ProjectId"];
var credential = [Link](credPath);
[Link](new AppOptions {
Credential = credential,
ProjectId = projectId
});
}
3. Firebase Sign-In Endpoint
[HttpPost("firebase-signin")]
[AllowAnonymous]
public async Task FirebaseSignIn(
[FromBody] FirebaseLoginRequest request) {
if ([Link](request?.IdToken))
return BadRequest("Missing Firebase ID token.");
return await _signInService.FirebaseSignInAsync([Link]);
}
public class FirebaseLoginRequest {
public string IdToken { get; set; }
}
4. Token Verification & User Management
public async Task FirebaseSignInAsync(string idToken) {
await using var tx = await _dbContext.[Link]();
try {
// 1) VERIFY FIREBASE ID TOKEN
var decoded = await [Link]
.VerifyIdTokenAsync(idToken, checkRevoked: true);
var uid = [Link];
var email = [Link]("email", out var e) ? e?.ToString() : null;
var name = [Link]("name", out var n) ? n?.ToString() : null;
var picture = [Link]("picture", out var p) ? p?.ToString() : null;
if ([Link](email))
return BadRequest("Email not found in Firebase token.");
var emailLower = [Link]();
// 2) FIND OR CREATE USER
var login = await _signinRepository.GetAccountByEmail(emailLower);
if (login == null) {
var dummy = [Link]().ToString("N") + "!Aa1";
var req = new SignUpRequest {
Username = [Link](name) ? [Link]('@')[0] : name,
Email = emailLower,
Password = dummy,
ConfirmPassword = dummy
};
await _signupService.SignUpAsync(req);
login = await _signinRepository.GetAccountByEmail(emailLower);
}
if (login == null)
return InternalServerError("Cannot create or fetch login record.");
// 3) GET USER INFO
var user = await _signinRepository.GetUserByLoginIdAsync([Link]!);
if (user == null)
return NotFound("User not found after creating login.");
// 4) ISSUE ACCESS & REFRESH TOKENS
return await HandleSignInSuccess(user);
} catch (FirebaseAuthException ex) {
await [Link]();
return Unauthorized($"Invalid Firebase token: {[Link]}");
} catch (Exception ex) {
await [Link]();
return InternalServerError($"Firebase login failed: {[Link]}");
}
}
private async Task HandleSignInSuccess(UserDto user) {
var accessToken = _jwtService.GenerateAccessToken(user);
var refreshToken = _jwtService.GenerateRefreshToken(user);
await _tokenRepository.SaveRefreshToken([Link], refreshToken);
return Ok(new {
StatusCode = 200,
Message = "Sign in successful",
Data = new {
User = user,
AccessToken = accessToken,
RefreshToken = refreshToken
}
});
}
· Security Flow
Firebase ID Token (JWT) Structure
{
"header": {
"alg": "RS256",
"kid": "54513209...",
"typ": "JWT"
},
"payload": {
"name": "Lÿc Huÿnh Tân",
"picture": "[Link]
"iss": "[Link]
"aud": "moneya-5df03",
"auth_time": 1762666232,
"user_id": "DxjXJOoCHgNpCMq0BQ1cVwxA9tE3",
"sub": "DxjXJOoCHgNpCMq0BQ1cVwxA9tE3",
"iat": 1762666233,
"exp": 1762669833,
"email": "huynhtanluc2004@[Link]",
"email_verified": true,
"firebase": {
"identities": {
"[Link]": ["104719818299454460707"],
"email": ["huynhtanluc2004@[Link]"]
},
"sign_in_provider": "[Link]"
}
}
}
Token Verification Process
Backend verifies:
1. Token signature using Firebase public keys
2. Token not expired (exp claim)
3. Token issued for correct project (aud claim)
4. Token not revoked (optional: checkRevoked: true)
5. Email verified (email_verified claim)
r Data Flow Diagram
MOBILE APP:
1. User clicks "Sign in with Google"
2. GoogleSignIn().signOut() (clear cache)
3. GoogleSignIn().signIn() ³ Popup select account
4. User selects Google account
5. Get Google credentials (accessToken, idToken)
6. Create Firebase credential from Google tokens
7. [Link](credential)
8. Firebase returns UserCredential
9. Get Firebase ID Token: [Link](true)
10. POST /auth/firebase-signin Body: { "idToken": "eyJhbGci..." }
BACKEND API:
1. Get Firebase ID Token
2. [Link](idToken)
3. Firebase Admin SDK verify token with Firebase servers
4. Extract user info from token claims: email, name, picture, uid
5. Find user in database by email If not exists ³ Create new user
6. Generate JWT access token & refresh token
7. Save refresh token to database
8. Return response with user, accessToken, refreshToken
MOBILE APP:
1. Receive response from backend
2. Save accessToken to secure storage
3. Save refreshToken to secure storage
4. Save user info to local state/cache
5. Navigate to Home screen
6. Login successful!
UI Flow
Google Popup
Sign In Page ï Account 1
[Email Login]
ï Account 2
% OR % ï Add account
[ Ü Google]
Home Page
Loading Welcome, User!
Signing in...
Logged in
«
'
¸ Key Features Implemented
Mobile Backend
' Firebase Google Sign-In integration ' Firebase Admin SDK integration
' Auto sign-out tr±ßc khi sign-in (cho phép chßn ' Service account authentication
account) ' ID token verification with signature check
' Force refresh Firebase ID token ' Token revocation check (optional)
' Secure token storage ' Auto user creation for first-time login
' Auto token refresh interceptor ' JWT access/refresh token generation
' Clean Architecture pattern ' Transaction support for data consistency
' BLoC state management ' Comprehensive error handling
' Comprehensive error handling
Deployment Checklist
Mobile Backend
Add [Link] to android/app/ Download service account key from Firebase Console
Configure Firebase in Firebase Console Configure [Link] with Firebase credentials
Add SHA-1 fingerprint to Firebase Initialize FirebaseApp in [Link]
Enable Google Sign-In in Firebase Console Create /auth/firebase-signin endpoint
Test on real device (not emulator for Google Sign-In) Deploy to server (Render, Azure, AWS, etc.)
Update mobile app with correct backend URL
ð Common Issues & Solutions
Iòòu= 1: "Fav=0 µ v=âv]y ID µ=¨ òv`¨aĀuâ=" Iòòu= 2: Cµ¨¨=&Āvµ¨ Āv¢=µuĀ
Cause: Service account key is incorrect or does not Cause: Backend not running or URL incorrect
match Firebase project
Solution: Check backend is running: netstat -ano | findstr
Solution: Check project_id in service account key should :7288. Verify base URL in ApiConstants. Make sure
be moneya-5df03 firewall allows port
Iòòu= 3: 405 M=Ānµ0 NµĀ Aµw=0 Iòòu= 4: Luº¨ 3¨` ¨n Û vµ Āv nµ¨ &i
Cause: Endpoint does not exist or HTTP method is Cause: Google Sign-In caches the account
incorrect
Solution: Add await [Link]() before
Solution: Check the route in the controller has signIn()
[HttpPost("firebase-signin")]