Created
July 31, 2018 07:27
-
-
Save ShayMe21/afdcd0983f84a3fa0766a622b2292908 to your computer and use it in GitHub Desktop.
Xamarin with Auth0 and TouchID Authentication
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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