I have an idToken string that is returned by google-sign-in use in mobile app with flutter and firebase:
Code in flutter
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:google_sign_in/google_sign_in.dart';
class Authentication {
static GoogleSignIn googleSignIn;
static Future<User> signInWithGoogle(BuildContext context) async {
FirebaseAuth auth = FirebaseAuth.instance;
User user;
googleSignIn = GoogleSignIn();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
final UserCredential userCredential =
await auth.signInWithCredential(credential);
user = userCredential.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
// handle the error here
} else if (e.code == 'invalid-credential') {
// handle the error here
}
} catch (e) {
// handle the error here
}
print("Credential token: ${credential.token}");
print("Credential provider id: ${credential.providerId}");
print("AccessToken: ${googleSignInAuthentication.accessToken}");
print("ID Token: ${googleSignInAuthentication.idToken}");
print("AccessToken.length: ${googleSignInAuthentication.accessToken.length}");
print("IdToken.length: ${googleSignInAuthentication.idToken.length}");
}
return user;
}
static Future signOut() async {
await googleSignIn.signOut();
FirebaseAuth.instance.signOut();
}
}
ID token is returned.
And I use this code to decode it:
public JwtPayload PayloadInfo(string idToken)
{
var jwtToken = new JwtSecurityToken(idToken);
JwtPayload payload = jwtToken.Payload;
return payload;
}
It works fine in the console app but with the .net 5 web API it fail with error:
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
I research that my idToken is not in JWS type... and I don't know how to solve this.
Weirdly, the function PayloadInfo works fine in C# console app but in the web API, it doesn't.
Controller
[HttpPost("login-google")]
[MapToApiVersion("1.0")]
public async Task<IActionResult> GoogleLoginAsync(
[FromBody] ExternalAuthModel model)
{
if (ModelState.IsValid)
{
var result = await
_userService.GoogleExternalLoginAsync(model);
if (result.IsSuccess)
{
return Ok(result);
}
return BadRequest(result);
}
return BadRequest("Somethings going wrong...");
}
ExternalAuthModel
public class ExternalAuthModel
{
public string Provider { get; set; }
public string IdToken { get; set; }
}
GoogleExternalLoginAsync function in my Service
public async Task<UserManagerResponse> GoogleExternalLoginAsync(ExternalAuthModel model)
{
var payload = _jwtHandler.PayloadInfo(model.IdToken);
if (payload is null)
{
return new UserManagerResponse
{
Message = "Invalid google authentication.",
IsSuccess = false
};
}
var info = new UserLoginInfo(model.Provider, payload.Sub, model.Provider);
var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
if (user is null)
{
user = await _userManager.FindByEmailAsync(payload["email"].ToString());
await _userManager.CreateAsync(user);
if (!await _roleManager.RoleExistsAsync(UserRoles.User))
await _roleManager.CreateAsync(new IdentityRole(UserRoles.User));
await _userManager.AddToRoleAsync(user, UserRoles.User);
await _userManager.AddLoginAsync(user, info);
}
else
{
await _userManager.AddLoginAsync(user, info);
}
if (user is null)
{
return new UserManagerResponse
{
Message = "Invalid google authentication.",
IsSuccess = false
};
}
var token = await _jwtHandler.GenerateToken(user);
return new UserManagerResponse
{
Message = token[0],
IsSuccess = true,
ExpireDate = DateTime.Parse(token[1])
};
}
PayloadInfo function
public JwtPayload PayloadInfo(string idToken)
{
// Exception when excute this line... it says my idToken is not in
// JWS compact format....
var jwtToken = new JwtSecurityToken(idToken);
JwtPayload payload = jwtToken.Payload;
return payload;
}
Log...
2021-07-04T16:10:30.3810628+07:00 [ERR] An unhandled exception has occurred while executing the request. (48a46595)
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
at System.IdentityModel.Tokens.Jwt.JwtSecurityToken..ctor(String jwtEncodedString)
at FTask.AuthServices.Helpers.JwtHandler.PayloadInfo(String idToken) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Helpers\JwtHandler.cs:line 83
at FTask.AuthServices.Services.UserService.GoogleExternalLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Services\UserService.cs:line 163
at FTask.Api.Controllers.AuthController.GoogleLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.Api\Controllers\AuthController.cs:line 109
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
