In this article i will show you how authenticate against google with oauth and a mobile app.
When i was trying to get the authentication running, i did not find a good working example for a android phone and Xamarin. There are a lot of good post and blogs out in the internet, but somehow they uses deprecated libs a lot.
All the code i use here can be found on my github page
Table of Contents
Setup your data and environment
In this example i will use following libs
- Xamarin.Forms (5.0.0)
- Xamarin.Essentials(1.7.0)
- RestSharp (107.3.0)
- Google.Apis.Auth (1.57.0)
- IdentityModel (1.6)
- Google.Apis.AndroidManagement.v1(1.57.0) (only for a scope)
The following data needs to prepared in order to start the App
packagename
Something like –> ‚com.companyname.googleoauthexample‘. more info
The name is important for the authentication flow. You will need the name in different places
- android manifest
- google auth client id
- request data
- redirect activity
Service Scope
select a/the scope to which service you want to talk to
google auth client id
get a google auth client id something like ‚7yyyyyyyyyy-8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com‘ (how to create a id) .
When you have all the data we can start with the app .
The App : get started
Basically the app has 3 main parts
- authorization request code
- redirection activity
- get credential code
authorization request code
this will authenticate you with google and the requested service.
string redirectUri = "com.xxxx.yyyyyy:/oauth2redirect"; var client_id = "nnnnnnnnnnnnnnnnnnnnnnnnnnn.apps.googleusercontent.com"; var authUrl = CreateAuthorizationRequest(client_id, redirectUri, AndroidManagementService.Scope.Androidmanagement); var authResult = await WebAuthenticator.AuthenticateAsync( new Uri(authUrl), new Uri(redirectUri)); var code = authResult.Properties["code"];
public string CreateAuthorizationRequest(string clientId, string redirectURI, string scope) { // Create URI to authorization endpoint var authorizeRequest = new RequestUrl(GoogleAuthConsts.AuthorizationUrl); currentCSRFToken = Guid.NewGuid().ToString("N"); var dic = new Dictionary<string, string> { {"client_id", clientId}, {"response_type", "code"}, {"scope", scope}, {"redirect_uri", redirectURI}, {"prompt", "consent"}, {"state", currentCSRFToken} , // Add CSRF token to protect against cross-site request forgery attacks. {"token_uri", "https://accounts.google.com/o/oauth2/token" } }; var authorizeUri = authorizeRequest.Create(Parameters.FromObject(dic)); return authorizeUri; }
This call/code popup a new Authentication Window which guides the user thru the process. When the process is finished the Window needs to know where to send the result. On Android Xamarin this is done by adding a callback activity
Error :dissallowed_useragent
When executing the code on a emulator device i get the error dissallowed_useragent, however, if i execute this on my real device it will work. So be aware using emulated devices.
redirection activity
As mentioned above you need to tell the device where to send the authentication result. Just add a class to the android project
using Android.App; using Android.Content; using Android.Content.PM; namespace GoogleOAuthExample.Droid { [Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, DataScheme = "com.xxxx.yyyyyyr")] public class WebAuthenticationCallbackActivity : Xamarin.Essentials.WebAuthenticatorCallbackActivity { } }
get the access_token
when use the WebAuthentictor we do not get the access_token in the first place. We need to call google again. (If someone knows why this is so, please let me know in the comments)
var authResult = await WebAuthenticator.AuthenticateAsync(new Uri(authUrl), new Uri(redirectUri)); var code = authResult.Properties["code"]; var client = new RestClient(new Uri("https://oauth2.googleapis.com")); var request = new RestRequest("token", Method.Post); request.AddParameter("code", code); request.AddParameter("client_id", client_id); request.AddParameter("redirect_uri", redirectUri); request.AddParameter("grant_type", "authorization_code"); request.AddHeader("content-type", "application/x-www-form-urlencoded"); var response = await client.ExecuteAsync<MyAuthResult>(request);
[Serializable] public class MyAuthResult { public string access_token { get; set; } public int expires_in { get; set; } public string refresh_token { get; set; } public string scope { get; set; } public string token_type { get; set; } }
The return of the post call should look like this :
{
"access_token": "ya29.a0Aa4xrXO_FCrRmljQ4r-BnHi-AWUZ_jArZimTfAJ6XLUfueXE_OmVjqVSq5P8U4cHEzu2tgqXs4SJ18f6hvC3bV7DjMgkH44a_zcmIMIX6-ThKIcm1FHbXI...................",
"expires_in": 3599,
"refresh_token": "1//09--o7bUJZk0iCgYIARAAGAkSNwF-L9Ir15GxMlHBpwy62TC57iNkCMDsDO.............",
"scope": "https://www.googleapis.com/auth/androidmanagement",
"token_type": "Bearer"
}
With the access_token you should be able to authenticate to the google services you need
With this information you should be able to authenticate with xamarin forms against google. It worked on my real Xiaomi Mi 9 (Api 29). Checkout the code on my github page