Ciao,
I have ASP.NET Web Application (.NET Framework) based on Visual Studio 2019 template with custom authentication with individual user accounts.
public void ConfigureAuth(IAppBuilder app) { // Configure the db context and user manager to use a single instance per request app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create); // Enable the application to use a cookie to store information for the signed in user // and to use a cookie to temporarily store information about a user logging in with a third party login provider app.UseCookieAuthentication(new CookieAuthenticationOptions()); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); // Configure the application for OAuth based flow PublicClientId = "self"; OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/Token"), Provider = new ApplicationOAuthProvider(PublicClientId), AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(10), // In production mode set AllowInsecureHttp = false AllowInsecureHttp = false }; // Enable the application to use bearer tokens to authenticate users app.UseOAuthBearerTokens(OAuthOptions); }
It works with Postman. I am able to obtain a token and access controller marked as [Authorize]
I am struggling with authentication of MobileServiceClient that I use for offline sync. Client is initialized in this way:
client = new MobileServiceClient(App.BackendUrl, new NativeMessageHandler());
public async Task LoginAsync(string username, string password) { try { var token = await GetAuthenticationToken(username, password); MobileServiceUser user = new MobileServiceUser(token.userName); user.MobileServiceAuthenticationToken = token.Access_Token; client.CurrentUser = user; } catch (InvalidGrantException) { throw; } catch (MobileServiceInvalidOperationException ex) { throw; } catch (Exception ex) { Crashes.TrackError(ex); Debug.WriteLine(ex); throw; } } private async Task<AuthenticationToken> GetAuthenticationToken(string username, string password) { var keyValues = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>("username", username), new KeyValuePair<string, string>("password", password), new KeyValuePair<string, string>("grant_type", "password") }; HttpContent httpContent = new FormUrlEncodedContent(keyValues); httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded"); try { var response = await client.InvokeApiAsync("/token", httpContent, HttpMethod.Post, null, null); return JsonConvert.DeserializeObject<AuthenticationToken>(await response.Content.ReadAsStringAsync()); } catch (MobileServiceInvalidOperationException exception) { if (string.Equals(exception.Message, "invalid_grant")) throw new InvalidGrantException("invalid credentials", exception); else throw; } }
Here some code for testing:
public async Task InitializeAsync()
{
if (client?.SyncContext?.IsInitialized ?? false)
return;
// Create a reference to the local sqlite store
const string path = "syncstore.db";
var store = new MobileServiceSQLiteStore(path); // Define the database schema store.DefineTable<Brand>(); brandTable = new AzureCloudTable<Brand>(client, null); // Actually create the store and update the schema try { await client.SyncContext.InitializeAsync(store); } catch (Exception ex) { Crashes.TrackError(ex); Debug.WriteLine(ex); } } async Task Test(string username, string password) { await LoginAsync("Simulator8", " "); await InitializeAsync(); //Test pull try { await brandTable.PullAsync(); } catch (Exception ex) { } }
Test throws exception:
- ex {Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: The request could not be completed. (Unauthorized)
at Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient.ThrowInvalidResponse (System.Net.Http.HttpRequestMessage request, System.Net.Http.HttpResponseMessage response) [0x001d2] in :0
at Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient.SendRequestAsync (System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Boolean ensureResponseContent, System.Threading.CancellationToken cancellationToken) [0x00121] in :0
at Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient.RequestAsync (System.Boolean UseHandlers, System.Net.Http.HttpMethod method, System.String uriPathAndQuery, Microsoft.WindowsAzure.MobileServices.MobileServiceUser user, System.String content, System.Boolean ensureResponseContent, System.Collections.Generic.IDictionary2[TKey,TValue] requestHeaders, System.Threading.CancellationToken cancellationToken) [0x000f0] in <d385e67aff524dc7bd2d27425b9e81ae>:0 at Microsoft.WindowsAzure.MobileServices.MobileServiceTable.ReadAsync (System.String uriString, Microsoft.WindowsAzure.MobileServices.MobileServiceFeatures features) [0x0009c] in <d385e67aff524dc7bd2d27425b9e81ae>:0 at Microsoft.WindowsAzure.MobileServices.MobileServiceTable.ReadAsync (System.String query, System.Collections.Generic.IDictionary
2[TKey,TValue] parameters, Microsoft.WindowsAzure.MobileServices.MobileServiceFeatures features) [0x00136] in :0
at Microsoft.WindowsAzure.MobileServices.Sync.PullAction.ProcessTableAsync () [0x00134] in :0
at Microsoft.WindowsAzure.MobileServices.Sync.TableAction.ExecuteAsync () [0x00251] in :0
at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext.ExecuteSyncAction (Microsoft.WindowsAzure.MobileServices.Sync.SyncAction action) [0x00090] in :0
at Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext.PullAsync (System.String tableName, Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceTableKind tableKind, System.String queryId, System.String query, Microsoft.WindowsAzure.MobileServices.MobileServiceRemoteTableOptions options, System.Collections.Generic.IDictionary2[TKey,TValue] parameters, System.Collections.Generic.IEnumerable
1[T] relatedTables, Microsoft.WindowsAzure.MobileServices.MobileServiceObjectReader reader, System.Threading.CancellationToken cancellationToken, Microsoft.WindowsAzure.MobileServices.Sync.PullOptions pullOptions) [0x00361] in :0
- If I try token that I receive in token.Access_Token in Postman it works
- If I try sync with controller without [Authorize] it works.
This is the message from Azure Log stream:
Username is correct. But if I don't call GetAuthenticationToken from LoginAsync and pass token manually to the user.MobileServiceAuthenticationToken then the result is:
So it seems that setting a user doesn't have any effect.
Any ideas why I can't authenticate my MobileServiceClient?