OAuth is an authorization framework that enables the application to obtain limited access to user accounts on HTTP service on Facebook, Google, and Microsoft, etc. Nowadays, there is no need to create a registration logic. Alternatively, you can choose using identity provider login. In this case, a person signs up for the app using identity provider login, an account is created for them, and the authentication step is taken care of by the identity provider.
In this article, I will explain how to implement the below OAuth identity provider in Xamarin Forms and manage the authentication process in a Xamarin Forms application.
Register a Mobile App with Identity Provider
You can find my previous article for registering a mobile app with an identity provider from
here.
Step 1 - Create New Xamarin.Forms Project
Let's start by creating a new Xamarin Forms Project in Visual Studio.
Open Run - Type Devenev.Exe and enter - New Project (Ctrl+Shift+N) - select Blank Xaml App (Xamarin.Forms Portable) template.
It will automatically create multiple projects, like Portable, Android, iOS, and UWP but here, I will be targeting only Android. However, the implementation of iOS and UWP is similar.
Step 2 - Install OAuth Client Components
Xamarin.Auth is a cross-platform SDK for authenticating users and storing their accounts. It includes OAuth authenticators that provide support for consuming identity providers.
Let's add the Xamarin.Auth component for OAuth. We will have to add this in all platform-specific projects, separately.
Go to any project (DevEnVExeLogin.Droid) - Components - Right-click on "Get More Components".
If you are not logged in already, it will show the login page. So, log in there.
Next, search and double-click on Xamarin.Auth component and click on "Add to App".
Step 3 - Create Base Login Page (LoginPage.Xaml)
I have created quick and simple login screens . You can modify them as per your requirement.
Right-click on Portable Class Library - Add New Item - Select Xaml Page(Login Page).
LoginPage.Xaml
- <?xml version="1.0" encoding="utf-8" ?>
- <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:DevEnvExeLogin" x:Class="DevEnvExeLogin.LoginPage">
- <StackLayout>
- <Entry Placeholder="Username" />
- <Entry IsPassword="true" Placeholder="Password" />
- <Button Text="Login" HeightRequest="50" />
- <Button Text="Google" Clicked="LoginClick" Image="GOOGLE.png" HeightRequest="50" />
- <Button Text="FaceBook" Clicked="LoginClick" Image="FACEBOOK.png" HeightRequest="50" />
- <Button Text="Twitter" Clicked="LoginClick" Image="TWITTER.png" HeightRequest="50" />
- <Button Text="Github" Clicked="LoginClick" Image="GITHUB.png" HeightRequest="50" />
- <Button Text="Yahoo" Clicked="LoginClick" Image="YAHOO.png" HeightRequest="50" />
- <Button Text="DropBox" Clicked="LoginClick" Image="DROPBOX.png" HeightRequest="50" />
- <Button Text="LinkedIn" Clicked="LoginClick" Image="LINKEDIN.png" HeightRequest="50" />
- <Button Text="Flicker" Clicked="LoginClick" Image="FLICKER.png" HeightRequest="40" />
- <Button Text="Twitter" Clicked="LoginClick" Image="MICROSOFT.png" HeightRequest="40" /> </StackLayout>
- </ContentPage>
LoginPage.Xaml.CS
Add LoginClick event in login page code behind the file and sender object will return the button text name (eg: Facebook, Twitter, etc).
- using System;
- using Xamarin.Forms;
- namespace DevEnvExeLogin {
- public partial class LoginPage: ContentPage {
- public LoginPage() {
- InitializeComponent();
- }
- void LoginClick(object sender, EventArgs args) {
- Button btncontrol = (Button) sender;
- string providername = btncontrol.Text;
- if (OAuthConfig.User == null) {
- Navigation.PushModalAsync(new ProviderLoginPage(providername));
-
- }
- }
- }
- }
Step 4 - Create Identity Provider Login Page
As we will be having platform-specific LoginPage implementation of Xamarin.Auth, we don't need any specific implementation in the portable project.
We do need to add an empty ProviderLoginPage which will be resolved at runtime and substituted by actual implementation regarding this will explain in step 5.
Right Click Portable Project - Add New Item Select Xaml page (ProviderLoginPage.Xaml )
- using Xamarin.Forms;
- namespace DevEnvExeLogin {
- public partial class ProviderLoginPage: ContentPage {
-
- public string ProviderName {
- get;
- set;
- }
- public ProviderLoginPage(string _providername) {
- InitializeComponent();
- ProviderName = _providername;
- }
- }
- }
** In Xaml page, you need to make no changes.
Step 5: Create Platform Specific Login Renderer
We need to create platform-specific LoginRenderer Page. So, you have to create platform-specific Login page (loginRenderer.CS) to iOS, Android, and UWP projects.
We need to add LoginPageRenderer which will be used by Xamarin.Auth to display the webView for OAuth Login Page
Code Snippet Explanation
The below code is for Xamarin.Forms Dependency Service which maps ProviderLoginPage to LoginRenderer.
- [assembly: ExportRenderer(typeof(ProviderLoginPage), typeof(LoginRenderer))]
-
-
- Get Identity ProviderName from Providerloginpage
- var loginPage = Element as ProviderLoginPage;
- string providername = loginPage.ProviderName;
Create OAuthProviderSetting class from Portable Class Library with OAuth Implementation. It is explained in Step 6.
-
- OAuthProviderSetting oauth = new OAuthProviderSetting();
- var auth = oauth.LoginWithProvider(providername);
- Create Oauth event
- for provider login completed and canceled.
- auth.Completed += (sender, eventArgs) => {
- if (eventArgs.IsAuthenticated) {
- else {
-
- }
- };
If you want to get and save user info. You can create UserEntity from Portable Library and refer the below code.
- namespace DevEnvExeLogin {
- public class UserDetails {
- public string TwitterId {
- get;
- set;
- }
- public string Name {
- get;
- set;
- }
- public string ScreenName {
- get;
- set;
- }
- public string Token {
- get;
- set;
- }
- public string TokenSecret {
- get;
- set;
- }
- public bool IsAuthenticated {
- get {
- return !string.IsNullOrWhiteSpace(Token);
- }
- }
- }
- }
LoginRenderer.CS
- using Android.App;
- using Xamarin.Forms.Platform.Android;
- using DevEnvExeLogin;
- using Xamarin.Forms;
- using DevEnvExeLogin.Droid.PageRender;
- [assembly: ExportRenderer(typeof(ProviderLoginPage), typeof(LoginRenderer))]
- namespace DevEnvExeLogin.Droid.PageRender {
- public class LoginRenderer: PageRenderer {
- bool showLogin = true;
- protected override void OnElementChanged(ElementChangedEventArgs < Page > e) {
- base.OnElementChanged(e);
-
- var loginPage = Element as ProviderLoginPage;
- string providername = loginPage.ProviderName;
- var activity = this.Context as Activity;
- if (showLogin && OAuthConfig.User == null) {
- showLogin = false;
-
- OAuthProviderSetting oauth = new OAuthProviderSetting();
- var auth = oauth.LoginWithProvider(providername);
-
- auth.Completed += (sender, eventArgs) => {
- if (eventArgs.IsAuthenticated) {
- OAuthConfig.User = new UserDetails();
-
- OAuthConfig.User.Token = eventArgs.Account.Properties["oauth_token"];
- OAuthConfig.User.TokenSecret = eventArgs.Account.Properties["oauth_token_secret"];
- OAuthConfig.User.TwitterId = eventArgs.Account.Properties["user_id"];
- OAuthConfig.User.ScreenName = eventArgs.Account.Properties["screen_name"];
- OAuthConfig.SuccessfulLoginAction.Invoke();
- } else {
-
- }
- };
- activity.StartActivity(auth.GetUI(activity));
- }
- }
- }
- }
Step 6: OAuth Implementation
The OAuth2Authenticator class is responsible for managing the user interface and communicating with authentication services. It will support all the identity providers.
But, on Twitter, OAuth authentication will support only on OAuth1Authenticator. So, you can use the OAuth1Authenticator instead of the OAuth2Authenticator.
The OAuth2Authenticator and OAuth1Authenticator class require a number of parameters, as shown in the following list.
- Client ID – Identity provider-client ID. While registering the app, you will need a unique Client ID.
- Client Secret – identifies the client that is making the request. While registering the app, you will need a unique Client Secret
- Scope – identifies the API access being requested by the application, and the value informs the consent screen that is shown to the user.
- Authorize URL – identifies the URL where the authorization code will be obtained from.
- Redirect URL – identifies the URL where the response will be sent. The value of this parameter must match one of the values that appear on the Credentials page of the project.
- AccessToken URL — identifies the URL used to request access tokens after an authorization code is obtained.
Step 6.1: Access GOOGLE Account
- var googleauth = new OAuth2Authenticator(
-
- "ClientId",
- "ClientSecret",
-
- "https://www.googleapis.com/auth/userinfo.email",
- new Uri("https://accounts.google.com/o/oauth2/auth"),
- new Uri("http://www.devenvexe.com"),// Set this property to the location the user will be redirected too after successfully authenticating
- new Uri("https://accounts.google.com/o/oauth2/token")
- );
Step 6.2: Access FACEBOOK Account
- var OauthFacebook = new OAuth2Authenticator(
- clientId: "MyAppId",
- scope: "",
- authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"), // These values do not need changing
- redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html")// These values do not need changing
- );
Step 6.3: Access TWITTER Account
- OAuth1Authenticator auth = new OAuth1Authenticator(
- consumerKey: "*****",
- consumerSecret: "****",
- requestTokenUrl: new Uri("https://api.twitter.com/oauth/request_token"), // These values do not need changing
- authorizeUrl: new Uri("https://api.twitter.com/oauth/authorize"), // These values do not need changing
- accessTokenUrl: new Uri("https://api.twitter.com/oauth/access_token"), // These values do not need changing
- callbackUrl: new Uri("http://www.devenvexe.com") // Set this property to the location the user will be redirected too after successfully authenticating
Step 6.4 Access Microsoft Account
- var OauthMicrosoft = new OAuth2Authenticator(
- clientId: "MY ID",
- scope: "bingads.manage",
- authorizeUrl: new Uri("https://login.live.com/oauth20_authorize.srf?client_id=myid&scope=bingads.manage&response_type=token&redirect_uri=https://login.live.com/oauth20_desktop.srf"),
- redirectUrl: new Uri("https://adult-wicareerpathways-dev.azurewebsites.net/Account/ExternalLoginCallback")
- );
Step 6.5 Access LINKEDIN Account
- var authLinkediN = new OAuth2Authenticator(
- clientId: "**",
- clientSecret: "**",
- scope: "",
- authorizeUrl: new Uri("https://www.linkedin.com/uas/oauth2/authorization"),
- redirectUrl: new Uri("http://devenvexe.com/"),
- accessTokenUrl: new Uri("https://www.linkedin.com/uas/oauth2/accessToken")
Step 6.6 Access GITHUB Account
- auth = new OAuth2Authenticator(
-
- "ClientId",
- "ClientSecret",
-
- "",
- new Uri("https://github.com/login/oauth/authorize"),
- new Uri("http://www.devenvexe.com"),// Set this property to the location the user will be redirected too after successfully authenticating
- new Uri("https://github.com/login/oauth/access_token")
- );
Step 6.7 Access FLICKER Account
- auth = new OAuth2Authenticator(
-
- "ClientId",
- "ClientSecret",
-
- "",
- new Uri("https://www.flickr.com/services/oauth/request_token"),
- new Uri("http://www.devenvexe.com"),// Set this property to the location the user will be redirected too after successfully authenticating
- new Uri("http://www.flickr.com/services/oauth/access_token")
- );
Step 6.8 Access YAHOO Account
- auth = new OAuth2Authenticator(
-
- "ClientId",
- "ClientSecret",
-
- "",
- new Uri("https://api.login.yahoo.com/oauth2/request_auth"),
- new Uri("http://www.devenvexe.com"),// Set this property to the location the user will be redirected too after successfully authenticating
- new Uri("https://api.login.yahoo.com/oauth2/get_token")
- );
You can download the source code and replace the Client ID or AppID and Client secret.