authenticate function

Future<Map> authenticate(
  1. Uri issuerUri,
  2. List<String> scopes,
  3. BuildContext context
)

The authentication function

Implementation

Future<Map> authenticate(
  Uri issuerUri,
  List<String> scopes,
  BuildContext context,
) async {
  /// Platform type parameter
  String platformType;

  /// Re-direct URIs
  String redirUrl;
  List redirUriList;

  /// Authentication method
  String authMethod;

  /// Authentication response
  Credential authResponse;

  /// Output data from the authentication
  Map authData;

  /// Check the platform
  if (currPlatform.isWeb()) {
    platformType = 'web';
  } else if (currPlatform.isAppOS()) {
    platformType = 'mobile';
  } else {
    platformType = 'desktop';
  }

  /// Get issuer metatada
  Issuer issuer = await Issuer.discover(issuerUri);

  /// Get end point URIs
  String regEndpoint = issuer.metadata['registration_endpoint'];
  String tokenEndpoint = issuer.metadata['token_endpoint'];
  var authMethods = issuer.metadata['token_endpoint_auth_methods_supported'];

  if (authMethods is String) {
    authMethod = authMethods;
  } else {
    if (authMethods.contains('client_secret_basic')) {
      authMethod = 'client_secret_basic';
    } else {
      authMethod = authMethods[1];
    }
  }

  if (platformType == 'web') {
    redirUrl = authManager.getWebUrl();
    redirUriList = [redirUrl];
  } else {
    redirUrl = 'http://localhost:$_port/';
    redirUriList = ['http://localhost:$_port/'];
  }

  /// Dynamic registration of the client (our app)
  var regResponse =
      await clientDynamicReg(regEndpoint, redirUriList, authMethod, scopes);

  /// Decode the registration details
  var regResJson = jsonDecode(regResponse);

  /// Generating the RSA key pair
  Map rsaResults = await genRsaKeyPair();
  var rsaKeyPair = rsaResults['rsa'];
  var publicKeyJwk = rsaResults['pubKeyJwk'];

  ///Generate DPoP token using the RSA private key
  String dPopToken =
      genDpopToken(tokenEndpoint, rsaKeyPair, publicKeyJwk, 'POST');

  final String clientId = regResJson['client_id'];
  final String clientSecret = regResJson['client_secret'];

  var client = Client(issuer, clientId, clientSecret: clientSecret);

  if (platformType != 'web') {
    /// Create a function to open a browser with an url
    Future<void> urlLauncher(String url) async {
      if (!await launchUrl(Uri.parse(url))) {
        throw Exception('Could not launch $url');
      }
    }

    /// create an authenticator
    var authenticator = oidc_mobile.Authenticator(
      client,
      scopes: scopes,
      port: _port,
      urlLancher: urlLauncher,
      redirectUri: Uri.parse(redirUrl),
      popToken: dPopToken,
      prompt: 'consent',
      redirectMessage:
          'Authentication process completed. You can now close this window!',
    );

    /// starts the authentication + authorisation process
    authResponse = await authenticator.authorize();

    /// close the webview when finished
    /// closing web view function does not work in Windows applications
    if (platformType == 'mobile') {
      //closeWebView();
      closeInAppWebView();
    }
  } else {
    ///create an authenticator
    var authenticator =
        authManager.createAuthenticator(client, scopes, dPopToken);

    var oidc = authManager.getOidcWeb();

    if (!context.mounted) return {};

    var callbackUri = await oidc.authorizeInteractive(
      context: context,
      title: 'authProcess',
      authorizationUrl: authenticator.flow.authenticationUri.toString(),
      redirectUrl: redirUrl,
      popupWidth: 700,
      popupHeight: 500,
    );

    var regResponse = Uri.parse(callbackUri).queryParameters;
    authResponse = await authenticator.flow.callback(regResponse);
  }

  /// Check if user cancelled the interaction or there was another unexpected
  /// error authenticating to the server
  if ((authResponse.response as Map).containsKey('error')) {
    authData = authResponse.response as Map;
  } else {
    /// The following function call first check if the existing access token
    /// is expired or not.
    /// If its not expired then returns the token data as a token object
    /// If expired then run the refresh token and get a new token and
    /// returns the new token data as a token object

    var tokenResponse = await authResponse.getTokenResponse();
    String? accessToken = tokenResponse.accessToken;

    /// Generate the logout URL
    final logoutUrl = authResponse.generateLogoutUrl().toString();

    /// Store authentication data
    authData = {
      'client': client,
      'rsaInfo': rsaResults,
      'authResponse': authResponse,
      'tokenResponse': tokenResponse,
      'accessToken': accessToken,
      'idToken': tokenResponse.idToken,
      'refreshToken': tokenResponse.refreshToken,
      'expiresIn': tokenResponse.expiresIn,
      'logoutUrl': logoutUrl,
    };
  }

  return authData;
}