Giter Site home page Giter Site logo

liminghao0922 / cordova-plugin-msal Goto Github PK

View Code? Open in Web Editor NEW

This project forked from wrobins/cordova-plugin-msal

0.0 1.0 0.0 11.86 MB

Use the newest Microsoft MSAL library in your Cordova-based project!

License: Apache License 2.0

Java 10.37% Objective-C 88.09% JavaScript 1.54%

cordova-plugin-msal's Introduction

Cordova MSAL Plugin

So you want to integrate your mobile app with Microsoft's authentication service?

Basic Assumptions and Requirements

This plugin implements Microsoft's MSAL plugin for Android and iOS. I'm assuming you're here because you've already read their documentation and understand how to configure Azure AD authentication for your organization and are simply looking for an existing Cordova wrapper to implement it on the mobile side.

How do I install it?

You can specify three variables during installation: the tenant ID and client ID of your Identity Platform, and, if you're building for Android, a base64 sha1 hash of your keystore file. The latter of which can be obtained like this:

keytool -exportcert -alias yourkeystorealias -keystore path/to/your/keystore/file.keystore | openssl sha1 -binary | openssl base64

If you aren't using AzureADMyOrg as one of your authorities, you can omit TENANT_ID, and if you're only building for iOS, you can omit KEY_HASH, but you really need to provide CLIENT_ID.

If you're using a CLI:

cordova plugin add cordova-plugin-msal --variable TENANT_ID=your-tenant-guid-here --variable CLIENT_ID=your-client-guid-here --variable KEY_HASH=S0m3K3yh4shH3re=

If you're using OutSystems

You should use my forge component. But if you want to implement a wrapper yourself, or if you're here because you're using that component and you want additional documentation, continue reading:

Be sure to grab a release tagged with OutSystems-*. I have a separate branch for OutSystems because as of this writing, MABS (MABS 6.x) does not support AndroidX features, which are now a standard part of the Android MSAL library. I had to do some finagling with a custom build of the library with AndroidX features stripped out to avoid getting an error trying to build it with MABS.

A side effect of this is the authorizationUserAgent option is locked on WEBVIEW, since the other options rely on AndroidX.

Here's the JSON you'll need to configure your plugin. If you only have one environment and build, you can put it in your extensibility configuration in your wrapper application. But you probably have debug/release builds in multiple envrionments with multiple Azure clients/tenants, so LifeTime is probably the best place to manage your extensibility configuration JSON. Open your wrapper application implementing this plugin in LifeTime and click the Settings link near the application's title with the gear icon. Select your environment in the dropdown near the application's title, and scroll down to the Advanced section. Under Extensibility Configurations, tick the Custom > radial and paste your JSON with that environment's variables there:

{
    "plugin": {
        "url": "https://github.com/wrobins/cordova-plugin-msal.git#OutSystems-v1.2.0",
        "variables": [
            {
                "name": "TENANT_ID",
                "value": "your-tenant-guid-here-optional"
            },
            {
                "name": "CLIENT_ID",
                "value": "your-client-guid-here-reuired"
            },
            {
                "name": "KEY_HASH",
                "value": "S0m3K3yh4shH3re="
            }
        ]
    }
}

How do I use it?

Invoke this plugin following the same logic as you would for any Cordova plugin. You probably want to make sure it has loaded correctly before using it:

let isAvailable = typeof(cordova.plugins.msalPlugin) !== "undefined";

Then, call msalInit() to configure how you want your MSAL instance to work.

window.cordova.plugins.msalPlugin.msalInit(function() {
    // Success logic goes here
},
function (err) {
    // err has your exception message
}, options);

The options parameter is an object that contains all of your MSAL configuration items, and is documented below. You can pass as much or as little of this object as you would like, or not even pass it at all. The full object, though, with all of the default options, looks like this:

{
    authorities: [
        {
            type: 'AAD',
            audience: 'AzureADandPersonalMicrosoftAccount',
            authorityUrl: '',
            cloudInstance: 'MSALAzurePublicCloudInstance',
            default: true
        }
    ],
    authorizationUserAgent: 'DEFAULT',
    multipleCloudsSupported: false,
    brokerRedirectUri: false,
    accountMode: 'SINGLE',
    scopes: ['User.Read']
}

Like I said before, this readme assumes basic knowledge of MSAL and you should look at Microsoft's documentation for how most of these attributes work, as they are named very similar both in this library and in all native platforms. But here is a basic refresher of what each option does and how to use it in this plugin.

Once again, you can omit any of these attributes in your options object and the default ones will be supplied to our native code, which should work for most developers. You can even not pass in this third argument at all, and a complete default options object will be used.

authorities

This tells MSAL where it should look to find the client's account and redirect them to login. You can specify one or more. Default: one authority object (see below)

type

Can be either 'AAD' or 'B2C'. Default: 'AAD'

audience

What kind of accounts are you allowing (personal, work/school, both)? Can be one of the following: 'AzureADandPersonalMicrosoftAccount' or 'AzureADMyOrg' or 'AzureADMultipleOrgs' or 'PersonalMicrosoftAccount'. If you use 'AzureADMyOrg' make sure you specified the TENANT_ID variable when you installed this plugin. Default: 'AzureADandPersonalMicrosoftAccount'

authorityUrl

If this authority type is 'B2C' this is required - specify the literal URL you would redirect your user to sign in (ex. 'https://login.microsoftonline.com/tfp/contoso.onmicrosoft.com/B2C_1_SISOPolicy/'). If type is 'AAD' then leave blank. Default: ''

cloudInstance

This specifies the locale of your organization's Azure instance. Can be one of the following: 'MSALAzurePublicCloudInstance', 'MSALAzureChinaCloudInstance', 'MSALAzureGermanyCloudInstance', or 'MSALAzureUsGovernmentCloudInstance'. Default: 'MSALAzurePublicCloudInstance'

default

Boolean supplied if your authorities array contains multiple objects. Tells MSAL to try this authority first when signing in a user. Default: true

authorizationUserAgent

This is for Android - tells MSAL which webview to use when redirecting a user to sign in interactively (stay inside the native app's webview or use the device's external browser). Can be one of the following: 'DEFAULT' 'BROWSER' or 'WEBVIEW'. Default: 'DEFAULT'. Note: in OutSystems, this option is locked on 'WEBVIEW' regardless of what you try to set here because anything else requires androidX features which MABS does not currently allow.

multipleCloudsSupported

If your organization supports multiple national clouds, set this to true. Otherwise, especially if you don't know what multiple national clouds means, leave this at false. Default: false

brokerRedirectUri

This is another Android option (boolean). Set to true if you want your application to have access to Microsoft accounts stored on the device's account broker, such as the built in broker or the Microsoft Authenticator app. This doesn't apply to iOS because by default MSAL already tries to use the account broker in Safari for this purpose. Default: false

accountMode

This is either 'SINGLE' or 'MULTIPLE' and controls the behavior of signing in and out. In single mode, MSAL only uses one account at a time, and signs in the user silently with that account if you call signInSilent(). In multiple account mode, you can support multiple accounts in your app, but you need to manage MSAL's list of those accounts (see below) and pass in which account you want to sign in and out of unless you're doing interactive sign-in. Default: 'SINGLE'

scopes

This is a text array and represents the information MSAL requests from the Graph API during its operation. In most cases you won't need to change this, and only do so if you really know what you're doing. Default: ['User.Read']

Ok, you have your plugin initialized with your organization's configuration. Here's how you sign users in and out:

Single Client

Check to see if the user has an account cached with your app:

window.cordova.plugins.msalPlugin.signInSilent(
    function(msg) {
        // msg is your JWT for the account we found.
    }, 
    function(err) {
        // err probably says "No accounts found" but maybe other debugging info
        // Don't show this to the user; just use it for debugging.
        // Here's where you either call the next prompt or wait for the user
    }
);

If you don't have an account, then either prompt immediately to sign in interactively (see below) or, if your app has guest access, do nothing and show your user an interface with options for signing in or continuing as a guest, wait for them to pick one. (Or don't do either. This plugin won't do you any good but it's your app.) If they choose to sign in, then start that flow with:

window.cordova.plugins.msalPlugin.signInInteractive(
    function(msg) {
        // msg is your JWT for the account the user just signed into
        // Also never use a preposition to end a sentence with
    }, 
    function(err) {
        // Usually if we get an error it just means the user cancelled the
        // signin process and closed the popup window. Handle this however
        // you want, depending again if you want guest access or not.
    }
);

Signing the user out is as simple as calling:

window.cordova.plugins.msalPlugin.signOut(
    function(msg) {
        // msg is just the "OK" plugin result
    }, 
    function(err) {
        // An error here usually either means you accidentally tried to
        // sign out someone who wasn't signed in, or there was a problem
        // communicating with the server.
    }
);

Multiple Clients

Operation is very similar to single account mode, but with one extra method to get the accounts you need: getAccounts(). It returns an array of objects {id: string, username: string} to represent accounts found in your app. Use it to see if you need to sign in a user interactively or manually. Your signInSilent() and signOut() methods will take an account id as an argument to pick which account you're working with.

Again, your logic might look more separate if you want to have guest access to your app, but this code without guest access should give you an idea of how this plugin works:

window.cordova.plugins.msalPlugin.getAccounts(
    function(accounts) {
        if (accounts.length === 0) {
            window.cordova.plugins.msalPlugin.signInInteractive(
                function(jwt) {
                    validateMyJWT(jwt);
                    doMySigninBusinessLogic();
                },
                function(err) {
                     myAwesomeErrorHandler.handlerError(err);
                }
            );
        } else {
            myAwesomeInterface.showAccountsList(accounts).waitForUserInput().then(pickedAccount => {
                if (pickedAccount) {
                    window.cordova.plugins.msalPlugin.signInSilent(
                        function(jwt) {
                            validateMyJWT(jwt);
                            doMySigninBusinessLogic();
                        },
                        function(err) {
                            myAwesomeErrorHandler.handlerError(err);
                        },
                        pickedAccount.id
                    );
                } else {
                    window.cordova.plugins.msalPlugin.signInInteractive(
                        function(jwt) {
                            validateMyJWT(jwt);
                            doMySigninBusinessLogic();
                        },
                        function(err) {
                            myAwesomeErrorHandler.handlerError(err);
                        }
                    );
                }
            });
        }
    },
    function(err) {
        myAwesomeErrorHandler.handlerError(err);
    }
);

To sign out a user, same thing:

window.cordova.plugins.msalPlugin.signOut(
    function() {
        myAfterSignoutBusinessLogic();
    }, 
    function(err) {
        myAwesomeErrorHandler.handlerError(err);
    },
    accountId
);

Validating the JWT

Once you get a successful sign-in, the plugin just returns the JWT for that account. You can validate it against Graph:

GET https://graph.microsoft.com/v1.0/me
'Authorization': 'Bearer myaccountJWT'

You'll get an object back something like:

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
  "businessPhones": [
    "+12345678910"
  ],
  "displayName": "Robins, Walter",
  "givenName": "Walter",
  "jobTitle": "Developer",
  "mail": null,
  "mobilePhone": null,
  "officeLocation": null,
  "preferredLanguage": null,
  "surname": "Robins",
  "userPrincipalName": "[email protected]",
  "id": "myaccount-guid-1234"
}

You can use that in your business logic to manage your accounts locally.

Advanced Login Configuration

Normally, you don't need to pass anything into signInInteractive() other than your callbacks; it just works. But there might be cases where you need some more control over signing someone in. You can pass a configuration object to signInInteractive() with as few or as many of the following attributes (they're all optional):

loginHint

If you want to bypass the username selection step, you can provide a username here (string) to pre-populate it and have the user only be asked for a password if need be.

prompt

This string tells MSAL how you want the login experience to be in terms of authentication and consent when they are redirected to Microsoft to sign in. It can be one of four (4) values; by default it is 'WHEN_REQUIRED' which actually is like a null value which tells MSAL not to send a prompt parameter at all and accept all default behavior. Other possible values are:

'SELECT_ACCOUNT'

Show a list of possible usernames from which the user can select to sign in

'LOGIN'

Normally if a user has had a recent session with Microsoft, even if their local token is cleared from your app and they need to sign in interactively again, they may be allowed back in without entering their password again. Setting prompt to 'LOGIN' will always force a user to be prompted for their password when signing in interactively no matter what.

'CONSENT'

Any consent prompts that the user accepted giving your app access to their account the first time they signed in to your app will be given, even if they accepted before.

authorizationQueryStringParameters

This is an array of objects of type {param: string, value: string}, empty by default. There are lots of extra query string parameters that can be passed with MSAL signin requests, and if you know you need to add this you probably already know what you want to put here.

otherScopesToAuthorize

This is an array of strings just like the scopes array you may have provided when you first called msalInit (or maybe you just left it at ['User.Read']). The different here is that the vanilla scopes array only tells MSAL, programatically, which API scopes it's allowed to call when getting data. Users are not asked to consent to those scopes until something tries to use them, which can result in annoying prompts in the middle of using your app. If you provide these extra scopes here as well, the user will be asked to accept all of them at once when signing in and won't get bugged later, regardless of whether those scopes are actually used or not.

Here's an example usage:

window.cordova.plugins.msalPlugin.signInInteractive(mycbfunction(msg), myerrorfunction(errmsg), {
        prompt: 'LOGIN',
        authorizationQueryStringParameters: [{param: 'domain_hint', value: 'my-tenant-guid'}];
    }
);

Troubleshooting

This plugin uses androidx features. If you get an error complaining about conflicting dependencies, you might need to add a couple of plugins to provide androidx compatibility, but your results may vary depending on if you are building locally or with a cloud-based utility.

cordova plugin add cordova-plugin-androidx
cordova plugin add cordova-plugin-androidx-adapter

cordova-plugin-msal's People

Contributors

hugoplatell avatar wrobins avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.