npm package: @klippa/nativescript-login
Description: The best way to do social logins in NativeScript, a plugin with modern SDKs to allow authentication to various providers with access to all SDK features
Author: Jeroen Bobbeldijk
Latest version: 3.1.1

# nativescript-login

[![NPM version][npm-image]][npm-url]
[![Downloads][downloads-image]][npm-url]
[![TotalDownloads][total-downloads-image]][npm-url]
[![Build Status][build-status]][build-url]

[build-status]:https://github.com/klippa-app/nativescript-login/workflows/Build%20CI/badge.svg
[build-url]:https://github.com/klippa-app/nativescript-login/actions
[npm-image]:http://img.shields.io/npm/v/@klippa/nativescript-login.svg
[npm-url]:https://npmjs.org/@klippa/nativescript-login
[downloads-image]:http://img.shields.io/npm/dm/@klippa/nativescript-login.svg
[total-downloads-image]:http://img.shields.io/npm/dt/@klippa/nativescript-login.svg?label=total%20downloads

:rocket: *The best way to do social logins in NativeScript* :rocket:

**A plugin with modern SDKs to allow authentication to various providers with access to all SDK features.**

## Features
* [Facebook Login](https://developers.facebook.com/docs/facebook-login/)
* [Google Sign In](https://developers.google.com/identity)
* [Sign In with Apple](https://developer.apple.com/sign-in-with-apple/) (iOS only)
* Access to all Login SDK features

## NativeScript Version Support
| NS Version | nativescript-login version | Install command | Docs |
| ---        | ---                       | ---             | --- |
| ^8.0.0 | ^3.0.0 | ns plugin add @klippa/nativescript-login@^3.0.0 | This page |
| ^7.0.0 | ^2.0.0 | ns plugin add @klippa/nativescript-login@^2.0.0 | [Here](https://github.com/klippa-app/nativescript-login/blob/ns-version/7/README.md) |
| ^6.0.0 | ^1.0.0 | tns plugin add @klippa/nativescript-login@^1.0.0 | [Here](https://github.com/klippa-app/nativescript-login/blob/ns-version/6/README.md) |

## Installation (NS 8)

```
ns plugin add @klippa/nativescript-login@^3.0.0
```

## Usage

### Facebook Login
#### Android integration

* Follow the `1. Select an App or Create a New App` step in the [manual](https://developers.facebook.com/docs/facebook-login/android)
* Edit/create your `App_Resources/Android/src/main/res/values/strings.xml` file and add the following, replace the `{{app-id}}`, `{{app-name}}`, `{{client-token}}` values:
```xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- If your strings.xml already existed, add the following <string> elements -->
    <string name="app_name">{{app-name}}</string>
    <string name="title_activity_kimera">{{app-name}}</string>
    <string name="facebook_app_id">{{app-id}}</string>
    <string name="fb_login_protocol_scheme">fb{{app-id}}</string>
    <string name="facebook_client_token">{{client-token}}</string>
</resources>
```

* Edit your `App_Resources/Android/src/main/AndroidManifest.xml` and add the following inside the `<application>` element.
```xml
<meta-data android:name="com.facebook.sdk.ApplicationId" 
        android:value="@string/facebook_app_id"/>

<activity android:name="com.facebook.FacebookActivity"
          android:configChanges=
                  "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
          android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="@string/fb_login_protocol_scheme" />
    </intent-filter>
</activity>
```

* Follow the `6. Provide the Development and Release Key Hashes for Your App` step in the [manual](https://developers.facebook.com/docs/facebook-login/ios)
* Logging in with your Facebook account should now work! The SDK takes care of the rest.

#### iOS integration

* Follow the `1. Select an App or Create a New App` step in the [manual](https://developers.facebook.com/docs/facebook-login/android)
* Enter your Bundle Identifier at the step `3. Register and Configure Your App with Facebook` -> `3a. Add your Bundle Identifier`
** Open `App_Resources/iOS/Info.plist` and add the following, replace `{{APP_ID}}` with your own app ID, `{{CLIENT_TOKEN}}` with your client token and `{{APP_NAME}}` with your app name:
 ```xml
<key>CFBundleURLTypes</key>
<array>
	<!-- If you already have a CFBundleURLTypes key, only add the dict section to the array -->
	<dict>
		<key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>fb{{APP_ID}}</string>
        </array>
    </dict>
</array>
<key>FacebookAppID</key>
<string>{{APP_ID}}</string>
<key>FacebookClientToken</key>
<string>{{CLIENT_TOKEN}}</string>
<key>FacebookDisplayName</key>
<string>{{APP_NAME}}</string>
<key>LSApplicationQueriesSchemes</key>
<array>
    <!-- If you already have a LSApplicationQueriesSchemes key, only add the strings to the array -->
    <string>fbapi</string>
    <string>fbapi20130214</string>
    <string>fbapi20130410</string>
    <string>fbapi20130702</string>
    <string>fbapi20131010</string>
    <string>fbapi20131219</string>
    <string>fbapi20140410</string>
    <string>fbapi20140116</string>
    <string>fbapi20150313</string>
    <string>fbapi20150629</string>
    <string>fbapi20160328</string>
    <string>fbauth</string>
    <string>fb-messenger-share-api</string>
    <string>fbauth2</string>
    <string>fbshareextension</string>
</array>
 ```

#### NativeScript integration

**Only required for iOS:**

Normal NativeScript:
Edit `app/app.ts`:

```typescript
import { wireInFacebookLogin } from "@klippa/nativescript-login";

// ... Other code/wirings

wireInFacebookLogin();

// ... Other code/wirings

app.run({ moduleName: "app-root" });
```

NativeScript Angular:
Edit `src/main.ts`:

```typescript

// Other imports.
import { wireInFacebookLogin } from "@klippa/nativescript-login";

// ... Other code/wirings

wireInFacebookLogin();

// ... Other code/wirings

runNativeScriptAngularApp({
  appModuleBootstrap: () => platformNativeScript().bootstrapModule(AppModule),
});
```

NativeScript Vue:
Edit `src/main.ts`:

```typescript

// Other imports.
import { wireInFacebookLogin } from "@klippa/nativescript-login";

// ... Other code/wirings

wireInFacebookLogin();

// ... Other code/wirings

new Vue({
  render: (h) => h('frame', [h(Home)]),
}).$start();
```

---

```typescript
import { startFacebookLogin, FacebookLoginOptions } from "@klippa/nativescript-login";

// First create an options object:

// The most basic sign in options.
const loginOptions: FacebookLoginOptions = {};

// Please note that result can also be a failure result.
// The actual result is in the object.
startFacebookLogin(loginOptions).then((result) => {
    console.log("Facebook login result: ", result);
}).catch((e) => {
    console.log("Error while logging in to Facebook: ", e);
});
```

#### Warning: Facebook's Automatically Logged Events
When you use the Facebook SDK, certain events in your app are automatically logged and collected for Facebook Analytics unless you disable automatic event logging.
You can disable it [on Android](https://developers.facebook.com/docs/app-events/getting-started-app-events-android#disable-auto-events) and [on iOS](https://developers.facebook.com/docs/app-events/getting-started-app-events-ios#disable-auto-events) by doing minor configuration changes.
If you are only using the Facebook SDK because of the login feature, I would advise to disable the "Automatically Logged Events" to prevent leaking information from your users to Facebook (even if there are not using Facebook).

### Google Sign In
#### Android integration

* Follow the `Configure a Google API Console project` step in the [manual](https://developers.google.com/identity/sign-in/android/start-integrating).
* Follow the `Get your backend server's OAuth 2.0 client ID` step in the [manual](https://developers.google.com/identity/sign-in/android/start-integrating) if you want to request a server auth code to request the user information server side. 
* Logging in with your Google account should now work! The SDK takes care of the rest.

#### iOS integration

* Follow the `Get an OAuth client ID` step in the [manual](https://developers.google.com/identity/sign-in/ios/start-integrating), note down the Client ID and download the credentials file.
* Open the credentials.plist and copy the value between `<string>` and `</string>` below `<key>REVERSED_CLIENT_ID</key>`.
* Open `App_Resources/iOS/Info.plist` and add the following, replace `{{REVERSED_CLIENT_ID}}` with the value you copied:
```xml
<key>CFBundleURLTypes</key>
<array>
    <!-- If you already have a CFBundleURLTypes key, only add the dict section to the array -->
    <dict>
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>{{REVERSED_CLIENT_ID}}</string>
        </array>
    </dict>
</array>
```

#### NativeScript integration

**Only required for iOS:**

Normal NativeScript:

Edit `app/app.ts`:

```typescript
import { wireInGoogleSignIn } from "@klippa/nativescript-login";

// ... Other code/wirings

wireInGoogleSignIn("{{CLIENT_ID}}");

// ... Other code/wirings

app.run({ moduleName: "app-root" });
```

NativeScript Angular:

Edit `src/main.ts`:

```typescript

// Other imports.
import { wireInGoogleSignIn } from "@klippa/nativescript-login";

// ... Other code/wirings

wireInGoogleSignIn("{{CLIENT_ID}}");

// ... Other code/wirings

runNativeScriptAngularApp({
  appModuleBootstrap: () => platformNativeScript().bootstrapModule(AppModule),
});
```

NativeScript Vue:
Edit `src/main.ts`:

```typescript

// Other imports.
import { wireInGoogleSignIn } from "@klippa/nativescript-login";

// ... Other code/wirings

wireInGoogleSignIn("{{CLIENT_ID}}");

// ... Other code/wirings

new Vue({
  render: (h) => h('frame', [h(Home)]),
}).$start();
```

Open the credentials.plist and copy the value between `<string>` and `</string>` below `<key>CLIENT_ID</key>`. Replace `{{CLIENT_ID}}` with the value you copied.

---

```typescript
import { GoogleSignInOptions, GoogleSignInType, startGoogleSignIn } from "@klippa/nativescript-login";

// First create an options object:

// The most basic sign in options.
const signInOptions: GoogleSignInOptions = {
    SignInType: GoogleSignInType.Local,
    RequestEmail: true
};

// Please note that result can also be a failure result.
// The actual result is in the object.
startGoogleSignIn(signInOptions).then((result) => {
    console.log("Google sign in result: ", result);
}).catch((e) => {
   console.log("Error while singing in to Google: ", e);
});
```

### Sign In with Apple

- Go to [the Apple developer website](https://developer.apple.com/account/resources/identifiers/list) and create a new app identifier with the "Sign In with Apple" Capability enabled. Make sure you sign your app with a provisioning profile using that app identifier.
- Open your app's `App_Resources/iOS` folder and [add this](https://github.com/klippa-app/nativescript-login/blob/master/demo/app/App_Resources/iOS/app.entitlements) (or append) to a file named `app.entitlements`.

#### Android integration (and iOS < 13)

**Sadly, Sign In with Apple does not support Android, due to the way they made the JS version, it's also not possible to create a version in a webview. You will always need a backend to handle it. I will write a how-to on this later.**

#### iOS integration (iOS >= 13)

To start the login:

```typescript
import { SignInWithAppleOptions, startSignInWithApple, SignInWithAppleScope, signInWithAppleAvailable } from "@klippa/nativescript-login";
import { Dialogs } from "@nativescript/core";

if (signInWithAppleAvailable()) {
    // First create an options object:
    const signInOptions: SignInWithAppleOptions = {
        Scopes: [SignInWithAppleScope.EMAIL, SignInWithAppleScope.FULLNAME]
    };

    // Please note that result can also be a failure result.
    // The actual result is in the object.
    startSignInWithApple(signInOptions).then((result) => {
        console.log("Sign In with Apple result: ", result);
    }).catch((e) => {
       console.log("Error while using Sign In with Apple: ", e);
    });
} else {
    Dialogs.alert("Sign In with Apple is not available for your device");
}
```

To get the current state:

```typescript
import { getSignInWithAppleState, signInWithAppleAvailable } from "@klippa/nativescript-login";
import { Dialogs } from "@nativescript/core";

if (signInWithAppleAvailable()) {
    // User ID must be the ID that was previously received from the sign in.
    const userID = "";

    // Please note that result can also be a failure result.
    // The actual result is in the object.
    getSignInWithAppleState(userID).then((result) => {
        console.log("Sign in with Apple State result: ", result);
    }).catch((e) => {
       console.log("Error getting Sign in with Apple State: ", e);
    });
} else {
    Dialogs.alert("Sign In with Apple is not available for your device");
}
```

## Other types of authentication

To keep the scope of this project simple and clean, and to keep the dependencies small, we only support login providers that have native SDK's.
If you want to support other ways of logging in, please check out these projects:

* [nativescript-oauth2](https://github.com/alexziskind1/nativescript-oauth2)
* [nativescript-inappbrowser](https://github.com/proyecto26/nativescript-inappbrowser)

## API

### Google

**GoogleSignInOptions**:

| Property | Description |
| ---  | ---   |
| SignInType | The type of sign in. `GoogleSignInType.LOCAL` is to use the information on the device, `GoogleSignInType.ServerAuthCode` for if you want to retrieve user information serverside.  |
| ServerClientId | The Client ID of the server you are requesting a `ServerAuthCode` or `IdToken`. For when using login type is `ServerAuthCode`, or when `RequestIdToken is true`.  |
| ForceCodeForRefreshToken | Used when type is ServerAuthCode. If true, the granted code can be exchanged for an access token and a refresh token. The first time you retrieve a code, a refresh_token will be granted automatically. Subsequent requests will require additional user consent. Use false by default; only use true if your server has suffered some failure and lost the user's refresh token. Only has effect on Android.  |
| HostedDomain | Specifies a hosted domain restriction. By setting this, sign in will be restricted to accounts of the user in the specified domain. Domain of the user to restrict (for example, "mycollege.edu"),  |
| AccountName | Specifies an account name on the device that should be used. If this is never called, the client will use the current default account for this application. The account name on the device that should be used to sign in. Only has effect on Android.  |
| RequestIdToken | Specifies that an ID token for authenticated users is requested. Requesting an ID token requires that the server client ID be specified. iOS always return the user ID Token.  |
| RequestId | Specifies that user ID is requested by your application. For iOS you can't control this, ID is always returned.  |
| RequestEmail | Specifies that email info is requested by your application. Note that we don't recommend keying user by email address since email address might change. Keying user by ID is the preferable approach. For iOS you can't control this, use RequestProfile if you want the email.  |
| RequestProfile | Specifies that user's profile info is requested by your application. Default: true. On iOS you have to either set RequestProfile or give custom scopes.  |
| ExtraScopes | A list of `GoogleSignInScope` values to specify OAuth 2.0 scopes for your application requests. Normally you will not need this.  |
| ForceAccountSelection | Whether you want to force account selection. If you enable this option we will logout the user for you in the app.  |

**GoogleSignInResult**:

| Property | Description |
| ---  | ---   |
| ResultType | The result, either `GoogleSignInResultType.FAILED` or `GoogleSignInResultType.SUCCESS`.  |
| ErrorCode | When result type is `GoogleSignInResultType.FAILED`, the error code of the request.  |
| ErrorMessage | When result type is `GoogleSignInResultType.FAILED`, the error message of the request.  |
| GrantedScopes | A list of granted scopes.  |
| RequestedScopes | A list of requested scopes. This is only filled in by the Android SDK. |
| GivenName | -  |
| Id | The ID of the user |
| IdToken | The ID token (JWT) to send to your backend  |
| DisplayName | - |
| FamilyName |  - |
| PhotoUrl | - |
| Email | - |
| ServerAuthCode | The Server Auth Code that your backend can use to retrieve user information.  |

---

### Facebook

**FacebookLoginOptions**:

| Property | Description |
| ---  | ---   |
| Scopes | The permissions to request. If you don't add this param, we will request public_profile and email for you.  |
| RequestProfileData | Whether to request profile data. If you don't enable this, you will only get an ID and a token. Perfect for server side handling. If you do enable this, we use the requested token on the Graph API to request the user profile. Not available when using LimitedLogin.  |
| ProfileDataFields | The fields to fetch when requesting the profile data. When not set, we get the following fields: id,name,first_name,last_name,picture.type(large),email. Some fields might return an object, like the picture field. Not available when using LimitedLogin. |
| ForceAccountSelection | Whether you want to force account selection. If you enable this option we will logout the user for you in the app.  |
| LimitedLogin | iOS only! Whether you want to use Limited Login. Facebook Login offers a [Limited Login mode](https://developers.facebook.com/docs/facebook-login/limited-login/). When you use the limited version of Facebook Login, the fact that a person used Facebook Login with the app will not be used to personalize or measure advertising effectiveness. You will not get an access token when you enable this. |

**FacebookLoginResult**:

| Property | Description |
| ---  | ---   |
| ResultType | The result, either `FacebookLoginResultType.FAILED`, `FacebookLoginResultType.CANCELED` `FacebookLoginResultType.SUCCESS`.  |
| ErrorCode | When result type is `FacebookLoginResultType.FAILED`, the error code of the request.  |
| ErrorMessage | When result type is `FacebookLoginResultType.FAILED`, the error message of the request.  |
| ProfileDataErrorCode | When result type is `FacebookLoginResultType.FAILED`, and `ErrorCode` is `2`, the error code of the profile request.  |
| ProfileDataErrorMessage | When result type is `FacebookLoginResultType.FAILED`, and `ErrorCode` is `2`, the error message of the profile request.  |
| ProfileDataUserErrorMessage | When result type is `FacebookLoginResultType.FAILED`, and `ErrorCode` is `2` the user error message of the profile request.  |
| DeniedScopes | A list of denied scopes to validate whether the user gave permission for all requested scopes. |
| GrantedScopes | A list of granted scopes. |
| Id | The ID of the user |
| AccessToken | The access token that your backend can use to retrieve user information. Not available when using `LimitedLogin`. |
| ProfileDataFields | An object of of the profile fields that were requested in `FacebookLoginOptions.ProfileDataFields` or the basic profile when using the `LimitedLogin` option on iOS.  |

---

### Apple

**SignInWithAppleOptions**:

| Property | Description |
| ---  | ---   |
| User | Not required. Not sure what this value does. The value that will be put in the user property of ASAuthorizationAppleIDRequest.  |
| Scopes | The extra scopes to request. Normally you will only get the user ID. Note: a user can deny you access to these scopes. Possible values: SignInWithAppleScope.EMAIL and SignInWithAppleScope.FULLNAME  |

**SignInWithAppleResult**:

| Property | Description |
| ---  | ---   |
| ResultType | The result, either `SignInWithAppleResultType.ERROR`, `SignInWithAppleResultType.SUCCESS`.  |
| ErrorCode | When result type is `SignInWithAppleResultType.ERROR`, the error code of the request.  |
| ErrorMessage | When result type is `SignInWithAppleResultType.ERROR`, the error message of the request.  |
| IdentityToken | A JSON Web Token (JWT) that securely communicates information about the user to your app. |
| AuthorizationCode | A short-lived token used by your app for proof of authorization when interacting with the app’s server counterpart. |
| State | An arbitrary string that your app provided to the request that generated the credential. |
| User | An identifier associated with the authenticated user. |
| Email | When you added the EMAIL scope. The contact information the user authorized your app to access, it's possible that this is a `@privaterelay.appleid.com` when the user did not share their personal email address. Only available when the user authorizes your app for the first time. However, it is always available in the JWT token in the IdentityToken field. |
| FullName | When you added the FULLNAME scope. The user’s name. Only available when the user authorizes your app for the first time. |
| NameComponents | When you added the FULLNAME scope. The user’s name, represented as name components (e.g., first name, suffix, nickname). Only available when the user authorizes your app for the first time. See `SignInWithAppleNameComponents`. |
| AuthorizedScopes | A list of authorized scopes to validate whether the user gave permission for all requested scopes. |
| RealUserStatus | A value that indicates whether the user appears to be a real person. |

**SignInWithAppleStateResult**:

| Property | Description |
| ---  | ---   |
| ResultType | The result, either `SignInWithAppleResultType.ERROR`, `SignInWithAppleResultType.SUCCESS`.  |
| ErrorCode | When result type is `SignInWithAppleResultType.ERROR`, the error code of the request.  |
| ErrorMessage | When result type is `SignInWithAppleResultType.ERROR`, the error message of the request.  |
| State | The state of the authorization, either `SignInWithAppleStateResultState.REVOKED`, `SignInWithAppleStateResultState.AUTHORIZED` or `SignInWithAppleStateResultState.NOTFOUND`.  |

**SignInWithAppleNameComponents**:

| Property | Description |
| ---  | ---   |
| GivenName | The user's given (first) name.  |
| MiddleName | The user's middle name.  |
| FamilyName | The user's family (last) name.  |
| NamePrefix | The user's name prefix (e.g., Dr., Ms.).  |
| NameSuffix | The user's name suffix (e.g., Ph.D., Jr.).  |
| Nickname | The user's nickname.  |
| PhoneticRepresentation | The user's name, as pronounced phonetically, represented as name components (e.g., first name, suffix, nickname).  |

## About Klippa

[Klippa](https://www.klippa.com/en) is a scale-up from [Groningen, The Netherlands](https://goo.gl/maps/CcCGaPTBz3u8noSd6) and was founded in 2015 by six Dutch IT specialists with the goal to digitize paper processes with modern technologies.

We help clients enhance the effectiveness of their organization by using machine learning and OCR. Since 2015 more than a 1000 happy clients have been served with a variety of the software solutions that Klippa offers. Our passion is to help our clients to digitize paper processes by using smart apps, accounts payable software and data extraction by using OCR.

## License

The MIT License (MIT)