AcquireTokenInteractive: What Do I do when a user abandons the login process? - oauth-2.0

I am writing a console app using some code I found on GitHub. The code below works fine.
If the token is cached, it is retrieved and the application continues. (AcquireTokenSilent)
If no token is found then I prompt the user for their credentials. They're taken to the company login site. They login, and the application continues. (AcquireTokenInteractive)
However, let's say the user simply changes their mind and abandons the login process by closing web the browser. Now, my code is just sitting there. All you see is a command window doing nothing.
It's clearly waiting for some response, that will never come since the Web Browser will no longer be communicating with my Console App.
How would I receive a message from the closing Web Browser, so my Console App knows to throw an exception or process the abandoned login somehow?
namespace PublicClientAuthentication
{
class AuthenticationProvider : IAuthenticationProvider
{
IPublicClientApplication _clientApp;
private string[] _scopes;
public AuthenticationProvider(IPublicClientApplication app, string[] scopes)
{
_clientApp = app;
_scopes = scopes;
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
AuthenticationResult authResult = null;
try
{
var accounts = await _clientApp.GetAccountsAsync();
authResult = await _clientApp.AcquireTokenSilent(_scopes.ToArray(), accounts.FirstOrDefault()).ExecuteAsync().ConfigureAwait(false);
}
catch (MsalUiRequiredException ex)
{
System.Diagnostics.Debug.WriteLine(ex);
authResult = await _clientApp.AcquireTokenInteractive(_scopes)
.WithPrompt(Microsoft.Identity.Client.Prompt.ForceLogin)
.ExecuteAsync().ConfigureAwait(false);
}
catch (MsalServiceException ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
catch (MsalClientException ex)
{
System.Diagnostics.Debug.WriteLine(ex);
authResult = await _clientApp.AcquireTokenInteractive(_scopes).ExecuteAsync();
}
catch (Exception e)
{
System.Diagnostics.Debug.Write(e);
}
request.Headers.Add("Authorization", authResult.CreateAuthorizationHeader());
}
}
}

Adding WithUseEmbeddedWebView did the trick.
This code works in the .NET Framework. It does not work with .NET Core
authResult = await _clientApp.AcquireTokenInteractive(_scopes)
.WithUseEmbeddedWebView(true)
.WithPrompt(Prompt.ForceLogin)
.ExecuteAsync().ConfigureAwait(false);

Related

Plugin.FirebaseAuth.FirebaseAuthException: An error occurred when accessing the keychain Xamarin.forms app

I'm using the latest stable package of Plugin.FirebaseAuth (4.1.0). But when I try to call the SignInWithEmailAndPasswordAsync(email, password) when using the iOS simulator. I get an exception?
Method:
public async Task<bool> SignIn(string email, string password)
{
try
{
var result = await CrossFirebaseAuth.Current.Instance.SignInWithEmailAndPasswordAsync(email, password);
var token = await result.User.GetIdTokenAsync(true);
Preferences.Set("MyFirebaseRefreshToken", token);
AccountManager.CurrentUserId = result.User.Uid;
return true;
}
catch (FirebaseAuthException ex)
{
Console.WriteLine(ex.Reason);
await App.Current.MainPage.DisplayAlert($"Alert", (ex.Reason.ToString()), "OK");
return false;
}
}`
Error:
If it only happens to ios, that's maybe because you didn't add the Team ID prefix before your App ID. Like this:
Auth.auth().useUserAccessGroup("XK********.com.matkonit.SharedItems")
You can refer to this page.
Ok So the issue turns out to be with the simulator for iOS.
The fix:
You'll need an apple developer account, and a provisioning profile. You'll also need a custom entitlements.plist

MS Graph - how to check for return code 204 after subscription is deleted?

Just new to ms graph and also to .net.
I'm trying to write a method that deletes a notification subscription. The code itself seems to work. But i need to know how to look up the actual return code from the upstream API instead of just sending back a 204.
Here's the code:
[Route("msgraphnotification/{subscriptionId}")]
[HttpDelete]
[AllowAnonymous]
public async Task<Int> delete(string subscriptionId)
{
try{
GraphServiceClient graphClient = await getAuthToken();
await graphClient.Subscriptions["{subscription-id}"]
.Request()
.DeleteAsync();
return 204; // this is what I want to fix.
}
catch(Exception ex){
Console.Write(ex);
return 404;
}
}
If you really need to know the response code you can send HTTP request with the .Net Microsoft Graph client library.
// Get the request URL for deleting a subscription
var requestUrl = client.Subscriptions["{subscription-id}"].Request().RequestUrl;
// Create the request message.
var hrm = new HttpRequestMessage(HttpMethod.Delete, requestUrl);
// Authenticate HttpRequestMessage
await client.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
var response = await client.HttpProvider.SendAsync(hrm);
// Get the status code.
if (!response.IsSuccessStatusCode)
{
throw new ServiceException(
new Error
{
Code = response.StatusCode.ToString(),
Message = await response.Content.ReadAsStringAsync()
});
}
else
{
var statusCode = (int)response.StatusCode;
}
...

Google Sign-In With Flutter: Error Code -4

I currently try to implement google_sign_in package in Flutter (https://pub.dartlang.org/packages/google_sign_in).
For this, I followed the example of their repository (https://github.com/flutter/plugins/blob/master/packages/google_sign_in/lib/google_sign_in.dart).
In that example in "initState" is a call signInSilently.
#override
void initState() {
super.initState();
_googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount account) {
setState(() {
_currentUser = account;
loggedIn = true;
});
});
loggedIn = false;
_googleSignIn.signInSilently();
}
I tried this code in iOS. On my first App Start, it worked well. But since I logged out I get an error here all the time I restart my app.It is the following PlatformException:
PlatformException(sign_in_required, com.google.GIDSignIn, The operation couldn’t be completed. (com.google.GIDSignIn error -4.))
I found in question Google Sign-In Error -4 that the error code is because of a missing Auth in Keychain.
The solution while swift programming is to call the method * hasAuthInKeychain* before the try to signInSilently. My problem is that the GoogleSignIn class in the flutter package has no function named like this.
Is there another call I need to run with this package to be sure I can try a silent log in? Or am I doing something wrong to get this message or is there even the possibility of catching this error?
Edit
I tried Marcel's solution, too. Somehow it is not catching the PlatfromException.
I do not know if this will help: signInSilently() is calling a method in which there is a the following call (google_sign_in.dart, line 217):
await channel.invokeMethod(method)
In platform_channel.dart there is a call
codec.decodeEnvelope(result);
The platform exception gets thrown in here.
if (errorCode is String && (errorMessage == null || errorMessage is String) && !buffer.hasRemaining)
throw PlatformException(code: errorCode, message: errorMessage, details: errorDetails);
else
throw const FormatException('Invalid envelope');
Edit 2
Since I just run my app and not started it in debug mode it somehow works again without throwing an exception. I do not know how this affects the code and why I got this exception. I can also run the code in debug mode again.
Since then I had the exception once again. Again I restarted android studio and runned the application once without debug mode.
You could just check if the sign in failed by handling the PlatformException like this:
void _setUpGoogleSignIn() async {
try {
final account = await _googleSignIn.signInSilently();
print("Successfully signed in as ${account.displayName}.");
} on PlatformException catch (e) {
// User not signed in yet. Do something appropriate.
print("The user is not signed in yet. Asking to sign in.");
_googleSignIn.signIn();
}
}
This is one way to catch the error and run _googleSignIn.signIn();
GoogleSignInAccount googleSignInAccount = await googleSignIn
.signInSilently(suppressErrors: false)
.catchError((dynamic error) async {
GoogleSignInAccount googleSignInAccount =
await _googleSignIn.signIn();
});
In my case, I did not want the user to see the login window automatically. In this case I changed from signIn to signOut. This way, I send the user to another view with an explanatory message and a login button.
GoogleSignInAccount googleSignInAccount = await googleSignIn
.signInSilently(suppressErrors: false)
.catchError((dynamic error) async {
GoogleSignInAccount googleSignInAccount = await _googleSignIn.signOut();
return googleSignInAccount;
});

AcquireTokenSilentAsync fails to authenticate user

I am trying to get the silent token request to initialize the ConfidentialClientApp object as in the 'Microsoft Graph SDK ASPNET Connect' project and outlined in Add sign-in with Microsoft to an ASP.NET web app
With my code mirroring the samples above, I expect that my call will return a successful result with an access to.
var result = await cca.AcquireTokenSilentAsync(graphScopes, cca.Users.First());
return result.AccessToken;
However, I get an error where it says the user needs to be authenticated. I am not sure what I am missing from the examples that make this work in them.
You can only acquire the token silently if there is already a cached token for that user that includes the scopes you're requesting (it can have more, but it needs to have at least what you've asked for).
This is why AcquireTokenSilentAsync should always be wrapped in a Try/Catch block. If it fails to find a matching token, you need to launch an interactive flow. Here is an example from the MSAL Wiki:
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenSilentAsync(scopes, app.Users.FirstOrDefault());
}
catch (MsalUiRequiredException ex)
{
// A MsalUiRequiredException happened on AcquireTokenSilentAsync.
// This indicates you need to call AcquireTokenAsync to acquire a token
System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
try
{
result = await app.AcquireTokenAsync(scopes);
}
catch (MsalException msalex)
{
ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
}
}
catch (Exception ex)
{
ResultText.Text = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
return;
}
if (result != null)
{
string accessToken = result.AccessToken;
// Use the token
}

How to handle incorrect credentials with google oauth2 Installed Application code flow

I'm implementing the authorization code flow for Installed Application.
Code is similar to snippet below:
public static void main(String[] args) {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport,
JSON_FACTORY,
IA_CLIENT,
IA_SECRET,
Collections.singleton(DriveScopes.DRIVE)).setDataStoreFactory(dataStoreFactory)
.build();
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
drive = new Drive.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
System.out.println(drive.about());
return;
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
System.exit(1);
}
Everything is working fine except in the case when I provide an invalid client_id. (I've the same issue if I use a json file and alter its content).
I get this get of error message from Google server:
401. That’s an error.
Error: invalid_client
The OAuth client was not found.
Request Details
client_id=573900000-hsoobsdsstem84tg8br4pmdsds.apps.googleusercontent.com
redirect_uri=http://localhost:40441/Callback
response_type=code
scope=https://www.googleapis.com/auth/drive
... and the callback server never receives any feedback. So, the application
is still running endlessly.
I've looked at the LocalServerReceiver class but could find any way to provide a
timeout or any potential solution.
What's the cleanest way to handle this case ?

Resources