Google SignIn returns Current user as null - xamarin.ios

I am using google login for my Xamarin iOS app, however after successfully entering the username and password in the safari browser prompt that appears, It returns properties CurrentUser as null.
My Code:
Google.SignIn.SignIn.SharedInstance.Delegate = this;
Google.SignIn.SignIn.SharedInstance.UIDelegate = this;
Google.SignIn.SignIn.SharedInstance.SignInUser();
Google.SignIn.SignIn.SharedInstance.SignedIn += SharedInstance_SignedIn;
private void SharedInstance_SignedIn(object sender, SignInDelegateEventArgs e)
{
var signin = (Google.SignIn.SignIn)sender;
//Here if i debug signin variable, its property CurrentUser comes as null
}
I am using
Xamarin.IOS.Google.Signin: v4.0.1.1
Am I missing some setting that needs to be enabled in the Google api console?

Sender indicate the class that raised the event.
To get User ,you can use e.User Or Google.SignIn.SignIn.SharedInstance.CurrentUser
here explatins the function of method SignIn
The Sign-In SDK automatically acquires access tokens, but the access tokens will be refreshed only when you call SignIn or SignInSilently methods.

Related

Flutter app: How to implement a proper logout function?

I have a flutter App using Azure B2C authentication. To achieve this I use the flutter appAuth package. The login process works fine but appAuth does not provide a logout functionality. After logging in I get an access token. Until now my logout was to delete this access token.
The problem is, that Azure require a web app session lifetime of at least 15 minutes in the SignIn user flow. This means: If a user logs in and out within 15 minutes, he will automatically be logged in again. This makes a login with another user impossible.
I hope to fix this behavior with a real logout instead of only deleting the access tokens. In found the following line of code in the Azure Active Directory documentation. But I cannot manage to get it running. Any suggestions for a logout function?
GET https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/logout?post_logout_redirect_uri=https%3A%2F%2Fjwt.ms%2F
I followed the below source to implement the below log out function using app auth written by David White.
Future<void> _logOut() async {
try {
//for some reason the API works differently on iOS and Android
Map<String, String> additionalParameters;
if (Platform.isAndroid) {
//works on Android but will miss p parameter when redirected back to authorize on iOS
additionalParameters = {
"id_token_hint": _idToken,
"post_logout_redirect_uri": _redirectUrl
};
} else if (Platform.isIOS) {
// with p parameter when redirected back to authorize on iOS
additionalParameters = {
"id_token_hint": _idToken,
"post_logout_redirect_uri": _redirectUrl,
'p': '<tenantID>'
};
}
await appAuth.authorizeAndExchangeCode(
AuthorizationTokenRequest(
_clientId,
_redirectUrl,
promptValues: ['login'],
discoveryUrl: _discoveryURL,
additionalParameters: additionalParameters,
scopes: _scopes,
),
);
} catch (e) {
print(e);
}
setState(() {
_jwt = null;
});
}
source: https://www.detroitdave.dev/2020/04/simple-azure-b2c-flutter.html

How to pull phone's primary email id from flutter for auto-filling a registration form?

Without Making User Sign-in with Google as the below link suggests
How to access logged in email id from google accounts of a phone using flutter.
Here it shows how to access primary mail id from android.
You got to let him log in with his account first.
1 - make your user sign in using the Google Sign in package
https://pub.dartlang.org/packages/google_sign_in
2 - you can sign the returned user to your backend or a firebase backend simply with this (won't explain the whole process here)
3 - you can access all google api (some access scope can be required, scopes have to be provided on step 1)
here is the flutter google api to access all google method
https://pub.dartlang.org/packages/googleapis
You can do this in flutter via custom platform-channels .Please be careful and up-front to the user when dealing with account, profile, and contact data.
This requires both the following permissions:
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
you can use simple_permissions plugin to request/check the access
Open the file MainActivity.java located in the android java folder in the Project.
add the following code to get the emails from the device in the oncreate method
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodCallHandler() {
#Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getEmailList")) {
final List<String> list = new ArrayList<>();
AccountManager manager = AccountManager.get(getApplicationContext());
Account[] accounts = manager.getAccountsByType("com.google");
List<String> possibleEmails = new ArrayList<String>();
for (Account account : accounts) {
possibleEmails.add(account.name);
System.out.print(account.name);
}
/*Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(getApplicationContext()).getAccounts();
for (Account account : accounts) {
if (emailPattern.matcher(account.name).matches()) {
primaryEmail = account.name;
}
}*/
result.success(possibleEmails);
}
}
}
);
and you can call the method from your flutter code via the methodchannel
static const platform = const MethodChannel('samples.flutter.io/email');
var emailist = await platform.invokeMethod('getEmailList');
full sample project

Get Azure AD Graph Token if already Authenticated

I'm pretty new to Azure AD Graph and the authentication process. I was able to incorporate a single-sign on using the Azure AD Graph client as found in this example using a .NET MVC application: https://github.com/Azure-Samples/active-directory-dotnet-graphapi-web
My dilemma is that even though I've authenticated my session, it's still requesting that I login again to perform the actions found in the controller below:
public ActionResult Test()
{
if (Request.QueryString["reauth"] == "True")
{
//Send an OpenID Connect sign -in request to get a new set of tokens.
// If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
// The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
HttpContext.GetOwinContext()
.Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
// Access the Azure Active Directory Graph Client
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
// Obtain the current user's AD objectId
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
// Query and obtain the current user object from the Azure AD Graph Client
User user = (User)client.Users.
Where(u => u.ObjectId
.Equals(userObjectID, StringComparison.CurrentCultureIgnoreCase)).
ExecuteSingleAsync().
Result;
// Get the employee Id from Azure AD (via a directory extension)
IReadOnlyDictionary<string, object> extendedProperty = user.GetExtendedProperties();
object extendedProp = extendedProperty["extension_ExtensionId_employeeID"];
// Hash the employee Id
var empId = PasswordHash.ArgonHashString(extendedProp.ToString(), PasswordHash.StrengthArgon.Moderate);
// Send to the view for testing only
ViewBag.EmployeeName = user.DisplayName;
ViewBag.EmployeeEmail = user.Mail;
ViewBag.EmployeeId = empId;
return View();
}
The error I get is a:
Server Error in '/' Application
Authorization Required
With the following lines of code in the yellow box:
Line 22: if (token == null || token.IsEmpty())
Line 23: {
Line 24: throw new Exception("Authorization Required.");
Line 25: }
Line 26: return token;
Since I'm fairly new to the authentication piece, I need a little guidance on how-to obtain the current session token so I don't get this error.
I'm using the Azure AD Graph because I'm obtaining a specific directory extension in Azure that I wasn't able to obtain through Microsoft Graph (for right now and based on my current deadline).
Any advice will be helpful.
If the token is null , user needs to re-authorize . As shown in code sample , you could use try catch statement to handle the exception :
try
{
}
catch (Exception e)
{
//
// The user needs to re-authorize. Show them a message to that effect.
//
ViewBag.ErrorMessage = "AuthorizationRequired";
return View(userList);
}
Show message to user(for example , Index.cshtml in Users view folder) :
#if (ViewBag.ErrorMessage == "AuthorizationRequired")
{
<p>You have to sign-in to see Users. Click #Html.ActionLink("here", "Index", "Users", new { reauth = true }, null) to sign-in.</p>
}
If you want to directly send an OpenID Connect sign-in request to get a new set of tokens instead show error message to user , you can use :
catch (Exception e)
{
....
HttpContext.GetOwinContext()
.Authentication.Challenge(new AuthenticationProperties {RedirectUri = "/"},
OpenIdConnectAuthenticationDefaults.AuthenticationType);
.....
}
If the user still has a valid session with Azure AD, they will not be prompted for their credentials.The OpenID Connect middleware will return to current controller after the sign-in response has been handled.

Identity 2.0 After Login go to Infinite Loop asp.net mvc 5

I have added email confirmation process like below:
var code = await _users.GenerateEmailConfirmationTokenAsync(model.UserName);
var callbackUrl = Url.Action(
"ConfirmEmail", "Account",
new { username = model.UserName, code = code },
protocol: Request.Url.Scheme);
then confirm email with below code:
public async Task ConfirmationEmailAsync(CmsUser user, string token)
{
var provider = new DpapiDataProtectionProvider(WebConfigurationManager.AppSettings["AppName"].ToString());
_manager.UserTokenProvider = new DataProtectorTokenProvider<CmsUser>(
provider.Create("EmailConfirmation"));
await _manager.ConfirmEmailAsync(user.Id, token);
}
after that I will login it will go to infinite loop.
http://localhost:3214/account/login?ReturnUrl=%2Faccount%2Flogin%3FReturnUrl%3D%252Faccount%252Flogin%253FReturnUrl%253D%25252Faccount%25252Flogin%25253FReturnUrl%25253D%2525252Faccount%2525252Flogin%2525253FReturnUrl%2525253D%252525252Faccount%252525252Flogin%252525253FReturnUrl%252525253D%25252525252Faccount%25252525252Flogin%25252525253FReturnUrl%25252525253D%2525252525252Faccount%2525252525252Flogin%2525252525253FReturnUrl%2525252525253D%252525252525252Faccount%252525252525252Flogin%25252525252525...
Here, I have calling below method:
public async Task<string> GenerateEmailConfirmationTokenAsync(CmsUser user)
{
var provider = new DpapiDataProtectionProvider(WebConfigurationManager.AppSettings["AppName"].ToString());
_manager.UserTokenProvider = new DataProtectorTokenProvider<CmsUser>(
provider.Create("EmailConfirmation"));
return await _manager.GenerateEmailConfirmationTokenAsync(user.Id);
}
The problem is not about your Generate EMail action. It is about your authentication.
Probably, your Login action in Account controller is requiring authorization. For instance, you can have AuthorizeAttribute on an action or a controller. Maybe, it's a global filter or something's wrong with Web.config.
Anyway, that's what actually happens:
User tries to access your Generate EMail method
He is unauthorized. Then, he is redirected to Account / Login method.
This method requires authorization. Goto 2.
You need to review your authentication, debug it and find the basic problem before you continue implementing your EMail confirmation.

How to control the login flow in ADAL AuthenticationContext?

Using the ADAL library for getting a token for WAAD i would like to know how I can get more control over the login flow.
var ac = new AuthenticationContext("https://login.windows.net/" + ActiveDirectoryTenantId);
AuthenticationInfo = ac.AcquireToken(
resource: "https://management.core.windows.net/",
clientId: "1950a258-227b-4e31-a9cf-717495945fc2",
redirectUri: new Uri("urn:ietf:wg:oauth:2.0:oob"));
The user is prompted to login. For me it's via Live Id, for my customer's computer it's via an organizational account, and there is no way to switch between them. It seems to be controlled by how/what current sessions the computer might have running already logged into azure.
Can I do anything in the AcquireToken call to control this?
It would be best if I could trigger the normal flow when people log into Azure where they get to select if its a live id or a organizational login.
I have tried this:
ac.AcquireToken("https://management.core.windows.net/",
"1950a258-227b-4e31-a9cf-717495945fc2",
new Uri("urn:ietf:wg:oauth:2.0:oob"), PromptBehavior.Always,"wtrealm=urn:federation:MicrosoftOnline");
with no luck.
I found some magic tricks that seems to give some more control.
// ID for site to pass to enable EBD (email-based differentiation)
// This gets passed in the call to get the azure branding on the
// login window. Also adding popup flag to handle overly large login windows.
internal const string EnableEbdMagicCookie = "site_id=501358&display=popup";
private void ClearCookies()
{
NativeMethods.InternetSetOption(IntPtr.Zero, NativeMethods.INTERNET_OPTION_END_BROWSER_SESSION, IntPtr.Zero, 0);
}
private static class NativeMethods
{
internal const int INTERNET_OPTION_END_BROWSER_SESSION = 42;
[DllImport("wininet.dll", SetLastError = true)]
internal static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer,
int lpdwBufferLength);
}

Resources