Skip to content

Instantly share code, notes, and snippets.

@jftuga
Forked from ShayMe21/MyViewController.cs
Created January 28, 2021 20:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jftuga/f2f66da86fe39c17cfe9605095855a80 to your computer and use it in GitHub Desktop.
Save jftuga/f2f66da86fe39c17cfe9605095855a80 to your computer and use it in GitHub Desktop.
Xamarin with Auth0 and TouchID Authentication
// https://github.com/auth0-community/auth0-xamarin-oidc-samples/tree/master/Quickstart/01-Login/iOS
using System;
using UIKit;
using Auth0.OidcClient;
using System.Text;
using LocalAuthentication;
using Foundation;
using Xamarin.Auth;
using System.Linq;
namespace iOSSample
{
public partial class MyViewController : UIViewController
{
partial void LoginButton_TouchUpInside(UIButton sender)
{
Console.WriteLine("Partial method for LoginButton");
}
private Auth0Client _client;
public MyViewController() : base("MyViewController", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
Console.WriteLine("ViewDidLoad");
UserDetailsTextView.Text = String.Empty;
LoginButton.TouchUpInside += LoginButton_TouchUpInside;
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
/* Check whether a refresh tokens exists in KeyChain/KeyStore. */
private string doesRefreshTokenExists(){
var account = AccountStore.Create().FindAccountsForService("iOSSample").FirstOrDefault();
return (account != null) ? account.Properties["Refresh Token"] : null;
}
/*
* Store Refresh Token in KeyChain/KeyStore
* https://github.com/xamarin/recipes/tree/master/Recipes/xamarin-forms/General/store-credentials#storing-account-information
*/
private void saveRefreshToken(String refreshToken){
//
Account account = new Account
{
// Client ID
Username = "{{CLIENT_ID}}"
};
account.Properties.Add("Refresh Token", refreshToken);
AccountStore.Create().Save(account, "iOSSample");
}
/*
* Authenticate with TouchID if available https://docs.microsoft.com/en-us/xamarin/ios/platform/touchid
* @return boolean
*/
private bool authenticateWithTouchID(){
var context = new LAContext();
NSError AuthError;
var myReason = new NSString("Authenticate using TouchID.");
if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError))
{
var replyHandler = new LAContextReplyHandler((success, error) => {
this.InvokeOnMainThread(() => {
if (success)
{
Console.WriteLine("You logged in!");
//PerformSegue("AuthenticationSegue", this);
}
else
{
Console.WriteLine("Could not login!");
// Show fallback mechanism here
}
});
});
context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, myReason, replyHandler);
return true;
}
else
{
Console.WriteLine("Device does not support TouchID!");
return false;
}
}
/*
* Login Button Pressed Action
*
*/
private async void LoginButton_TouchUpInside(object sender, EventArgs e)
{
var sb = new StringBuilder();
var refreshToken = this.doesRefreshTokenExists();
if (!string.IsNullOrWhiteSpace(refreshToken)){
Console.WriteLine("Refresh Token found on Device: " + refreshToken);
if (authenticateWithTouchID()){
// https://github.com/IdentityModel/IdentityModel.OidcClient2/blob/dev/src/IdentityModel.OidcClient/Results/RefreshTokenResult.cs
var loginWithRefreshTokenResult = await _client.RefreshTokenAsync(refreshToken);
if (loginWithRefreshTokenResult.IsError){
sb.AppendLine("An error occurred during access token exchange with refresh token:");
sb.AppendLine(loginWithRefreshTokenResult.Error);
} else {
// Got refresh Token here, Do something with it
Console.WriteLine("Refresh token grant succeededed.");
sb.AppendLine($"Access Token: {loginWithRefreshTokenResult.AccessToken}");
}
}
} else {
Console.WriteLine("Refresh Token NOT found on Device: " + refreshToken);
loginAndGetRefreshToken();
}
UserDetailsTextView.Text = sb.ToString();
}
private async void loginAndGetRefreshToken(){
var Options = new Auth0ClientOptions
{
Domain = "{{AUTH0_DOMAIN}}",
ClientId = "{{CLIENT_ID}}",
Scope = "openid profile offline_access",
};
_client = new Auth0Client(Options);
var loginResult = await _client.LoginAsync();
var sb = new StringBuilder();
if (loginResult.IsError)
{
sb.AppendLine("An error occurred during login:");
sb.AppendLine(loginResult.Error);
}
else
{
sb.AppendLine($"ID Token: {loginResult.IdentityToken}");
sb.AppendLine($"Access Token: {loginResult.AccessToken}");
sb.AppendLine($"Refresh Token: {loginResult.RefreshToken}");
sb.AppendLine();
sb.AppendLine("-- Claims --");
foreach (var claim in loginResult.User.Claims)
{
sb.AppendLine($"{claim.Type} = {claim.Value}");
}
saveRefreshToken(loginResult.RefreshToken);
}
UserDetailsTextView.Text = sb.ToString();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment