avatarsimbu

Summary

The article discusses the implementation of Flutter_Data and MSAL authentication in a Flutter application.

Abstract

The article provides a step-by-step guide on how to authenticate API requests made by Flutter Data using MSAL authentication in a Flutter application. The author uses a previously secured Digests API hosted in Azure as an example. The article explains how to update the sign-in methods in the AuthenticationService implementations in the DigestablePrologue package to attempt to log in silently first and then log in interactively if that fails. The author also provides code snippets for creating an adapter that adds the access token to each request to the API.

Opinions

  • The author believes that MSAL provides a default implementation of the cache that can be used out-of-the-box without any additional configuration.
  • The author encountered an issue where each time the application started and requested the list of recipes from the server, the recipe retrieved was added to the local Hive DB causing duplicates to be displayed.
  • The author notes that this issue was caused because they were not returning an id from the server for the records from the server, so it could not identify the duplicates.
  • The author recommends trying out the AI service they recommend, which provides the same performance and functions as ChatGPT Plus(GPT-4) but is more cost-effective.
Join Medium to view all my articles.

Flutter — Flutter_Data & MSAL Authentication

In previous articles we looked offline first with Flutter_Data and how to secure your API with Microsoft’s Identity Platform.

Now its time to authenticate the API requests made by Flutter Data.

Secured request to get the list of recipes

We are going to use the secured Digests API that we hosted previously in Azure:

https://<Your Azure API Domain>/digests/recipes

Response:

[
    {
        "id": 1,
        "title": "How to boil an egg",
        "recipeLink": "https://www.theguardian.com/lifeandstyle/2014/nov/11/how-to-boil-an-egg-the-heston-blumenthal-way",
        "author": "Heston Blumenthal",
        "duration": "00:10:30",
        "thumbnail": "https://i.guim.co.uk/img/static/sys-images/Guardian/Pix/pictures/2014/11/5/1415205733799/4bfbd71a-6cd0-4494-833f-eaaed20a15b3-1020x612.jpeg?width=620&quality=45&auto=format&fit=max&dpr=2&s=ca3a95d7e761d267eff1b79b58cc4849"
    }
]

To support authentication on API requests I updated the sign in methods in AuthenticationService implementations in DigestablePrologue package to attempt to login in silently first and to then login interactively if that fails:

userAdModel =
          await pca.acquireTokenSilent(scopes: authScopes).catchError((e) {
        return null;
      });
      userAdModel ??= await pca.acquireToken(scopes: authScopes);

It provides the access token from cache if it has not expired, or, silently attempts to acquire a new token when it has expired using the refresh token provided when the user last logged in.

MSAL provides a default implementation of the cache, which you can use out-of-the-box without any additional configuration. However, you can also customise the cache behaviour to meet your needs.

The final part was to create an adapter that adds the access token to each request to the API.

import 'dart:async';

import 'package:digestable_prologue/security/service/msal_authentication_service.dart'
    if (dart.library.js) 'package:digestable_prologue/security/service/msal_js_authentication_service.dart';
import 'package:flutter_data/flutter_data.dart';

mixin JsonServerAdapter<T extends DataModel<T>> on RemoteAdapter<T> {
  @override
  Future<Map<String, String>> get defaultHeaders async {
    var msalService = getAuthenticationService();
    var authResult = await msalService.signIn();
    var bearerToken = authResult.accessToken;

    // Return a map containing the bearer token in the Authorization header
    return {'Authorization': 'Bearer $bearerToken'};
  }

  @override
  String get baseUrl => "https://your-apim.azure-api.net/digests";
}

And use the adapter in the Recipe data model.

@JsonSerializable()
@DataRepository([JsonServerAdapter])
class Recipe extends DataModel<Recipe> 
{
  ...
}

I hit one issue, each time I started the application and it requested the list of recipes from the server the recipe retrieved was add to the the local hive DB causing duplicates to be displayed.

This was caused because I was not returning an id from the server for the records from the server so it could not identify the duplicates, once added it sync’d the records returned only display the single recipe.

Flutter
Programming
Security
Mobile
API
Recommended from ReadMedium