-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1910 from AzureAD/dev-react-native-poc
Merge MSAL React Native Proof of Concept Library and Sample
- Loading branch information
Showing
80 changed files
with
19,676 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# OSX | ||
# | ||
.DS_Store | ||
|
||
# node.js | ||
# | ||
node_modules/ | ||
npm-debug.log | ||
yarn-error.log | ||
|
||
# Android/IntelliJ | ||
# | ||
build/ | ||
.idea | ||
.gradle | ||
local.properties | ||
*.iml | ||
|
||
# BUCK | ||
buck-out/ | ||
\.buckd/ | ||
*.keystore |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
registry=https://npm.pkg.github.com/AzureAD |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# MSAL React Native Proof of Concept (Android) | ||
**Note: With this library being a proof of concept, it is not recommended to be used for React Native applications intended for production.** | ||
|
||
MSAL for React Native is a proof of concept that allows React Native applications to authenticate users with Microsoft work and school accounts (AAD) as well as acquire access tokens from the Microsoft identity platform endpoint in order to access secured web APIs. Currently, this library is only available for the Android platform. | ||
## Getting started | ||
|
||
### Installation | ||
|
||
`$ npm install @azuread/msal-react-native-android-poc` | ||
|
||
### Register your application in the Azure Portal | ||
Under Authentication -> Platform configurations, click "Add a platform" and select Android. | ||
To generate the base64 signature of your application: | ||
* MacOS: `keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64` | ||
* Windows: `keytool -exportcert -alias androiddebugkey -keystore %HOMEPATH%.android\debug.keystore | openssl sha1 -binary | openssl base64` | ||
|
||
For more information and help, refer to this [MSAL FAQ](https://github.com/AzureAD/microsoft-authentication-library-for-android/wiki/MSAL-FAQ). | ||
|
||
### Configuring in app | ||
Follow steps 1 through 3 in the [Using MSAL](https://github.com/AzureAD/microsoft-authentication-library-for-android#using-msal) section of MSAL for Android's README with these modifications/reminders: | ||
* In step 2, please name the config file `auth_config_single_account.json` and put it in `res/raw`. You can pretty much copy and paste the MSAL configuration generated for you in Azure Portal and refer to the [configuration file documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-configuration). | ||
* In step 3, remember that for `android:path` you want to paste the base64 signature hash you generated in the console and not the url encoded version. | ||
|
||
## Usage | ||
Import MSAL for React Native as `MSAL`: | ||
```javascript | ||
import MSAL from '@azuread/msal-react-native-android-poc'; | ||
``` | ||
Importing will automatically create a `SingleAccountPublicClientApplication` with the configurations provided in `auth_config_single_account.json`. | ||
All of the MSAL methods return a promise. | ||
You can use `MSAL` to sign in a user with [scopes](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#scopes-and-permissions) (a string of scopes separated by " "): | ||
```javascript | ||
try { | ||
await MSAL.signIn(scopesValue); | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
``` | ||
Most of the methods return a map, and in the case of `signIn`, a map containing the variables of an `IAccount` object is returned. | ||
We can access the username of the currently signed in user and log it to console (for example): | ||
```javascript | ||
try | ||
const account = await MSAL.signIn(scopesValue); | ||
console.log("Username: " + account.username) | ||
} catch (error) { | ||
console.log(error); | ||
} | ||
``` | ||
Since a user is now signed in, we can try to acquire an access token silently and make a call to Microsoft Graph API: | ||
```javascript | ||
try { | ||
const result = await MSAL.acquireTokenSilent(scopesValue); | ||
//api call to MSGraph | ||
const response = await fetch ( | ||
"https://graph.microsoft.com/v1.0/me", { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${result.accessToken}` | ||
} | ||
} | ||
); | ||
|
||
... //do something with response here | ||
|
||
} catch (error) { | ||
console.log(error); | ||
} | ||
``` | ||
Please see msal-react-native-android-poc-sample in the sample folder for an example app that demonstrates the MSAL methods. | ||
|
||
For a complete listing of each method's return value and map keys, see the Methods(link to Methods) section. | ||
|
||
## What to expect from this library | ||
Because this library is a proof of concept, it is scoped to specific features and does not implement all the capabilities of an official MSAL for React Native library. | ||
|
||
This proof of concept is scoped to consider: | ||
* Compatibility with the Android platform | ||
* Authenticating users with work and school Azure AD accounts (AAD) | ||
* Single-account mode | ||
|
||
This proof of concept does not implement: | ||
* Compatibility with iOS | ||
* To allow compatibility with iOS, an [Objective-C native module](https://reactnative.dev/docs/native-modules-ios) must be created that wraps the [MSAL for iOS and macOS](https://github.com/AzureAD/microsoft-authentication-library-for-objc#:~:text=The%20MSAL%20library%20for%20iOS%20and%20macOS%20gives,for%20those%20using%20our%20hosted%20identity%20management%20service.). | ||
* B2C or ADFS | ||
* For implementing B2C, refer to the Microsoft docs on using [MSAL for Android with B2C](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-android-b2c). Since the returned value from acquiring tokens is an [`IAuthenticationResult`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.identity.client.authenticationresult?view=azure-dotnet), the results of the wrapped B2C methods can be handled in the same manner as the existing AAD methods. | ||
* Multiple-account mode | ||
* This could be as simple as adding an instance of [MultipleAccountPublicClientApplication](https://docs.microsoft.com/en-us/java/api/com.microsoft.identity.client.multipleaccountpublicclientapplication?view=azure-java-stable) to the existing native module file and wrapping its corresponding methods. | ||
|
||
## Methods | ||
This library's methods wrap MSAL for Android's corresponding `singleAccountPublicClientApplication` methods. All methods return a promise that, in most cases, resolves to a map and returns an exception if rejected. Please see the Microsoft Docs for [`singleAccountPublicClientApplication`](https://docs.microsoft.com/en-us/java/api/com.microsoft.identity.client.singleaccountpublicclientapplication?view=azure-java-stable) for more general information regarding MSAL methods. | ||
Method | Description | | ||
-------------------------------------- | ----------- | | ||
signIn(String scopesValue) | Directs a user to sign in with an AAD account. scopesValue is a String containing scopes separated by spaces (" "). Returns a map with the `authority`, `id`, `tenantId`, `username`, and `idToken` of the account. See the Microsoft docs on [IAccount](https://docs.microsoft.com/en-us/java/api/com.microsoft.identity.client.iaccount?view=azure-java-stable) for more details of the map's keys. | | ||
signOut() | Signs out the account currently signed in. If successful, `true` is returned, and if not, an exception is returned. | | ||
getAccount() | Retrieves the account currently signed in. If no account is signed in, null is returned. Otherwise, a map is returned with the `authority`, `id`, `tenantId`, `username`, and `idToken` of the account. See the Microsoft docs on [IAccount](https://docs.microsoft.com/en-us/java/api/com.microsoft.identity.client.iaccount?view=azure-java-stable) for more details of the map's keys. | | ||
isSharedDevice() | Returns a boolean that corresponds to whether the current device is shared or not. | | ||
acquireToken(String scopesValue) | Attempts to obtain an access token interactively. scopesValue is a String containing scopes separated by spaces (" "). Returns a map containing `accessToken`, `authenticationScheme`, `authorizationHeader`, `expiresOn` (string), `scope` (string), `tenantId`, and `account` (map with keys as described in "signIn"). An exception is returned otherwise. See MS docs on [IAuthenticationResult](https://docs.microsoft.com/en-us/java/api/com.microsoft.identity.client.iauthenticationresult?view=azure-java-stable) for more details. | | ||
acquireTokenSilent(String scopesValue) | Attempts to obtain a token silently. scopesValue is a String containing scopes separated by spaces (" "). Returns a map containing `accessToken`, `authenticationScheme`, `authorizationHeader`, `expiresOn` (string), `scope` (string), `tenantId`, and `account` (map with keys as described in "signIn"). An exception is returned otherwise. See MS docs on [IAuthenticationResult](https://docs.microsoft.com/en-us/java/api/com.microsoft.identity.client.iauthenticationresult?view=azure-java-stable) for more details. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<classpath> | ||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/> | ||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/> | ||
<classpathentry kind="output" path="bin/default"/> | ||
</classpath> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<projectDescription> | ||
<name>android</name> | ||
<comment>Project android created by Buildship.</comment> | ||
<projects> | ||
</projects> | ||
<buildSpec> | ||
<buildCommand> | ||
<name>org.eclipse.jdt.core.javabuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
<buildCommand> | ||
<name>org.eclipse.buildship.core.gradleprojectbuilder</name> | ||
<arguments> | ||
</arguments> | ||
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>org.eclipse.jdt.core.javanature</nature> | ||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature> | ||
</natures> | ||
</projectDescription> |
2 changes: 2 additions & 0 deletions
2
lib/msal-react-native-android-poc/android/.settings/org.eclipse.buildship.core.prefs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
connection.project.dir= | ||
eclipse.preferences.version=1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// android/build.gradle | ||
|
||
// based on: | ||
// | ||
// * https://github.com/facebook/react-native/blob/0.60-stable/template/android/build.gradle | ||
// original location: | ||
// - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/build.gradle | ||
// | ||
// * https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle | ||
// original location: | ||
// - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle | ||
|
||
def DEFAULT_COMPILE_SDK_VERSION = 28 | ||
def DEFAULT_BUILD_TOOLS_VERSION = '28.0.3' | ||
def DEFAULT_MIN_SDK_VERSION = 16 | ||
def DEFAULT_TARGET_SDK_VERSION = 28 | ||
|
||
def safeExtGet(prop, fallback) { | ||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback | ||
} | ||
|
||
apply plugin: 'com.android.library' | ||
apply plugin: 'maven' | ||
|
||
buildscript { | ||
// The Android Gradle plugin is only required when opening the android folder stand-alone. | ||
// This avoids unnecessary downloads and potential conflicts when the library is included as a | ||
// module dependency in an application project. | ||
// ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies | ||
if (project == rootProject) { | ||
repositories { | ||
google() | ||
jcenter() | ||
} | ||
dependencies { | ||
classpath 'com.android.tools.build:gradle:3.4.1' | ||
} | ||
} | ||
} | ||
|
||
apply plugin: 'com.android.library' | ||
apply plugin: 'maven' | ||
|
||
android { | ||
compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION) | ||
buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION) | ||
defaultConfig { | ||
minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION) | ||
targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION) | ||
versionCode 1 | ||
versionName "1.0" | ||
} | ||
lintOptions { | ||
abortOnError false | ||
} | ||
} | ||
|
||
repositories { | ||
// ref: https://www.baeldung.com/maven-local-repository | ||
mavenLocal() | ||
maven { | ||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm | ||
url "$rootDir/../node_modules/react-native/android" | ||
} | ||
maven { | ||
// Android JSC is installed from npm | ||
url "$rootDir/../node_modules/jsc-android/dist" | ||
} | ||
maven { | ||
url 'https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed%40Local/maven/v1' | ||
} | ||
google() | ||
jcenter() | ||
} | ||
|
||
dependencies { | ||
//noinspection GradleDynamicVersion | ||
implementation 'com.facebook.react:react-native:+' // From node_modules | ||
implementation 'com.microsoft.identity.client:msal:1.5.+' | ||
} | ||
|
||
def configureReactNativePom(def pom) { | ||
def packageJson = new groovy.json.JsonSlurper().parseText(file('../package.json').text) | ||
|
||
pom.project { | ||
name packageJson.title | ||
artifactId packageJson.name | ||
version = packageJson.version | ||
group = "com.reactlibrary" | ||
description packageJson.description | ||
url packageJson.repository.baseUrl | ||
|
||
licenses { | ||
license { | ||
name packageJson.license | ||
url packageJson.repository.baseUrl + '/blob/master/' + packageJson.licenseFilename | ||
distribution 'repo' | ||
} | ||
} | ||
} | ||
} | ||
|
||
afterEvaluate { project -> | ||
// some Gradle build hooks ref: | ||
// https://www.oreilly.com/library/view/gradle-beyond-the/9781449373801/ch03.html | ||
task androidJavadoc(type: Javadoc) { | ||
source = android.sourceSets.main.java.srcDirs | ||
classpath += files(android.bootClasspath) | ||
classpath += files(project.getConfigurations().getByName('compile').asList()) | ||
include '**/*.java' | ||
} | ||
|
||
task androidJavadocJar(type: Jar, dependsOn: androidJavadoc) { | ||
classifier = 'javadoc' | ||
from androidJavadoc.destinationDir | ||
} | ||
|
||
task androidSourcesJar(type: Jar) { | ||
classifier = 'sources' | ||
from android.sourceSets.main.java.srcDirs | ||
include '**/*.java' | ||
} | ||
|
||
android.libraryVariants.all { variant -> | ||
def name = variant.name.capitalize() | ||
def javaCompileTask = variant.javaCompileProvider.get() | ||
|
||
task "jar${name}"(type: Jar, dependsOn: javaCompileTask) { | ||
from javaCompileTask.destinationDir | ||
} | ||
} | ||
|
||
artifacts { | ||
archives androidSourcesJar | ||
archives androidJavadocJar | ||
} | ||
|
||
task installArchives(type: Upload) { | ||
configuration = configurations.archives | ||
repositories.mavenDeployer { | ||
// Deploy to react-native-event-bridge/maven, ready to publish to npm | ||
repository url: "file://${projectDir}/../android/maven" | ||
configureReactNativePom pom | ||
} | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
lib/msal-react-native-android-poc/android/src/main/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
package="com.reactlibrary"> | ||
|
||
</manifest> |
24 changes: 24 additions & 0 deletions
24
lib/msal-react-native-android-poc/android/src/main/java/com/reactlibrary/Constants.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
//Constants class which will be imported by MSALModule | ||
package com.reactlibrary; | ||
|
||
public final class Constants { | ||
|
||
private Constants() {} | ||
|
||
public static final String[] DEFAULT_SCOPES = {"User.Read"}; | ||
|
||
public static final String MODULE_NAME = "MSAL"; | ||
|
||
public static final String KEY_ACCOUNT = "account"; | ||
public static final String KEY_ACCESS_TOKEN = "accessToken"; | ||
public static final String KEY_AUTHENTICATION_SCHEME = "authenticationScheme"; | ||
public static final String KEY_AUTHORIZATION_HEADER = "authorizationHeader"; | ||
public static final String KEY_EXPIRES_ON = "expiresOn"; | ||
public static final String KEY_SCOPE = "scope"; | ||
public static final String KEY_TENANT_ID = "tenantId"; | ||
|
||
public static final String KEY_AUTHORITY = "authority"; | ||
public static final String KEY_ID = "id"; | ||
public static final String KEY_USERNAME = "username"; | ||
public static final String KEY_ID_TOKEN = "idToken"; | ||
} |
Oops, something went wrong.