# Verify Email/Phone Number

> **Concepts:** Learn about how [**Sign in with Email/Phone Number**](https://docs.cotter.app/features/verify-email-phone) works.

### Overview

Verifying **email and phone number** in your mobile app using our Authentication API consists of the following steps:

1. Open a WebView within your app with shared cookies
2. Direct users to Cotter's Auth page
3. Redirect back to your app with an authorization code
4. Call Cotter API with the authorization code
5. Get back the user's email or phone number, and whether or not it's verified

Here's an example on opening the in-app Browser from iOS and Android

* **Android**: Use the [Trusted Web Activity](https://developers.google.com/web/updates/2019/02/using-twa)
* **iOS:** Use the [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/authenticating_a_user_through_a_web_service)

### What you're building

![Authentication API for Android and iOS](https://blobscdn.gitbook.com/v0/b/gitbook-28427.appspot.com/o/assets%2F-M0QGDMRD8y_Kd-BpOvT%2F-M0QUEFxHD9nbe2hsnLf%2F-M0QabDr--EjvJZ95y6m%2Fimage.png?alt=media\&token=601a7625-9a3c-4022-a6e5-9a843bf1af9e)

### Authorization Flow

For mobile apps, we're going to use the [OAuth 2.0 Authorization Code Flow with Proof Key for Code Exchange (PKCE)](https://tools.ietf.org/html/rfc7636). This flow is recommended for Mobile Apps because:

* Mobile apps can't securely store the Secret Key. This is because decompiling the App will reveal the Secret Key, and there's only one secret key so it'll be the same for all users.
* Sending tokens to Custom URL schemes (ex. YourApp\://) will potentially expose the tokens to malicious apps.

## Steps

1. [Create a `code_verifier`](#step-1-create-a-code-verifier) and a `code_challenge`
2. [Request Authorization from Cotter](#step-2-request-authorization-from-cotter): Redirect user to Cotter to verify their email/phone and receive an `authorization_code` back to your app.
3. [Request Tokens and Identity](#step-3-request-tokens-and-identity): Send your `authorization_code` and `code_verifier` to Cotter server and get back a `token` and the user's email or phone number.
4. [Include Token to your server](#step-4-include-the-token-to-your-server): The token contains the user's verified email/phone number and a signature. Include this to your signup/login request to your backend

### Step 1: Create a Code Verifier

A `code_verifier` is a cryptographically-random key that will be sent to Cotter along with the `authorization_code` on Step 3. Read more about what are [code challenge and verifier](#what-is-state-and-code-challenge).

{% tabs %}
{% tab title="JavaScript" %}

```javascript
function dec2hex(dec) {
  return ('0' + dec.toString(16)).substr(-2)
}

function generateRandomString() {
  var array = new Uint32Array(56/2);
  window.crypto.getRandomValues(array);
  return Array.from(array, dec2hex).join('');
}

var verifier = generateRandomString();
```

{% endtab %}

{% tab title="Python" %}

```python
import os
import base64
verifier_bytes = os.urandom(32)
code_verifier = base64.urlsafe_b64encode(verifier_bytes).rstrip(b'=')
```

{% endtab %}

{% tab title="Java" %}

```java
// import android.util.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
```

{% endtab %}

{% tab title="Swift 3" %}

```swift
var buffer = [UInt8](repeating: 0, count: 32)
_ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)
let verifier = Data(bytes: buffer).base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "\_")
    .replacingOccurrences(of: "=", with: "")
    .trimmingCharacters(in: .whitespaces)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
NSMutableData *data = [NSMutableData dataWithLength:32];
int result __attribute__((unused)) = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
NSString *verifier = [[[[data base64EncodedStringWithOptions:0]
                        stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
                        stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
                        stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```

{% endtab %}
{% endtabs %}

### Step 1-b: Create a Code Challenge from Code Verifier

A `code_challenge` is the hashed version of your `code_verifier`. We will send this hash on step 2 when you're requesting an authentication from Cotter.&#x20;

{% tabs %}
{% tab title="JavaScript" %}

```javascript
function sha256(plain) { // returns promise ArrayBuffer
  const encoder = new TextEncoder();
  const data = encoder.encode(plain);
  return window.crypto.subtle.digest('SHA-256', data);
}

function base64urlencode(a) {
      var str = "";
      var bytes = new Uint8Array(a);
      var len = bytes.byteLength;
      for (var i = 0; i < len; i++) {
        str += String.fromCharCode(bytes[i]);
      }
      return btoa(str)
        .replace(/\+/g, "-")
        .replace(/\//g, "_")
        .replace(/=+$/, "");
    }

async function challenge_from_verifier(v) {
  hashed = await sha256(v);
  base64encoded = base64urlencode(hashed);
  return base64encoded;
}

var challenge = await challenge_from_verifier(verifier);
```

{% endtab %}

{% tab title="Python" %}

```python
import hashlib
import base64
challenge_bytes = hashlib.sha256(code_verifier).digest()
code_challenge = base64.urlsafe_b64encode(challenge_bytes).rstrip(b'=')
```

{% endtab %}

{% tab title="Java" %}

```java
// import android.util.Base64;
byte[] codeVerifierBytes = codeVerifier.getBytes("US-ASCII");
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(codeVerifierBytes);
byte[] codeChallengeBytes = md.digest();
String codeChallenge = Base64.encodeToString(codeChallengeBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
```

{% endtab %}

{% tab title="Swift 3" %}

```swift
// Dependency: Apple Common Crypto library
// http://opensource.apple.com//source/CommonCrypto
guard let data = verifier.data(using: .utf8) else { return nil }
var buffer = [UInt8](repeating: 0,  count: Int(CC_SHA256_DIGEST_LENGTH))
data.withUnsafeBytes {
    _ = CC_SHA256($0, CC_LONG(data.count), &buffer)
}
let hash = Data(bytes: buffer)
let challenge = hash.base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "\_")
    .replacingOccurrences(of: "=", with: "")
    .trimmingCharacters(in: .whitespaces)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// Dependency: Apple Common Crypto library
// http://opensource.apple.com//source/CommonCrypto
u_int8_t buffer[CC_SHA256_DIGEST_LENGTH * sizeof(u_int8_t)];
memset(buffer, 0x0, CC_SHA256_DIGEST_LENGTH);
NSData *data = [verifier dataUsingEncoding:NSUTF8StringEncoding];
CC_SHA256([data bytes], (CC_LONG)[data length], buffer);
NSData *hash = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
NSString *challenge = [[[[hash base64EncodedStringWithOptions:0]
                         stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
                         stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
                         stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```

{% endtab %}
{% endtabs %}

The `code_challenge` is sent first so that later in step 3, Cotter's server can verify that `hash(code_verifier)` is the same as `code_challenge` and that you are indeed made the original request.

#### Checking your code challenge and verifier

To check if your `code_challenge` and `code_verifier` are correctly generated and formatted, try comparing it with codes generated here <https://example-app.com/pkce>

### Step 2: Request Authorization from Cotter

Open Cotter's Auth URL from a WebView from your app.

```http
https://js.cotter.app/app?
    api_key=<api_key_id>
    &redirect_url=yourapp://
    &type=PHONE
    &code_challenge=<code_challenge>
    &state=<state>
```

| Query Parameter  | Type   | Description                                                                                                                                                                                                                                                                                                                                                                          |
| ---------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `api_key`        | string | Your `API_KEY_ID`                                                                                                                                                                                                                                                                                                                                                                    |
| `redirect_url`   | string | <p>Your app's URL scheme where Cotter Auth will redirect back your users to your app</p><p><strong>Example:</strong> <code>com.example.app:redirect\_uri\_path</code> or <code>[http://127.0.0.1:port](https://docs.cotter.app/sdk-reference/api-for-other-mobile-apps/http:/127.0.0.1:port)</code></p>                                                                              |
| `type`           | string | `EMAIL` or `PHONE`                                                                                                                                                                                                                                                                                                                                                                   |
| `code_challenge` | string | The `code_challenge` you created in [Step 1](#step-1-b-create-a-code-challenge-from-code-verifier)                                                                                                                                                                                                                                                                                   |
| `state`          | string | A random string that you generate from your application before opening to Cotter's Auth (ex. `abcXYZ456`). This is not the same as your `code_verifier`. You need to check if the `state` included by Cotter in the `redirect_url` is the same as the initial `state` that you set to make sure the request is for you. Learn more about [state](#what-is-state-and-code-challenge). |

{% hint style="warning" %}
Make sure the scheme of your `redirect_url` (the front part before `://`) doesn't have an underscore or other special characters. To test it out, enter your `redirect_url` here: <https://jsfiddle.net/omd02jn5/>
{% endhint %}

Here's an example on opening the in-app Browser from iOS and Android

* **Android**: Use the [Trusted Web Activity](https://developers.google.com/web/updates/2019/02/using-twa)
* **iOS:** Use the [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/authenticating_a_user_through_a_web_service)

{% tabs %}
{% tab title="iOS" %}

```swift
// Using ASWebAuthenticationSession
// https://developer.apple.com/documentation/authenticationservices/authenticating_a_user_through_a_web_service

guard let authURL = URL(string: "https://js.cotter.app/app?api_key=<api_key_id>&redirect_url=yourapp://&type=PHONE&code_challenge=<code_challenge>&state=<state>") else { return }
let scheme = "yourapp://"


self.authSession = ASWebAuthenticationSession(url: authURL, callbackURLScheme: scheme)
{ callbackURL, error in
    // Handle the callback.
}
if #available(iOS 13.0, *) {
    self.authSession?.presentationContextProvider = self
} else {
    // Fallback on earlier versions
}
self.authSession?.start()
```

{% endtab %}

{% tab title="Android" %}

```java
// Dependencies: Trusted Web Activity
// https://developers.google.com/web/updates/2019/02/using-twa

//build.gradle (Module:app)
android {
        ...
    compileOptions {
       sourceCompatibility JavaVersion.VERSION_1_8
       targetCompatibility JavaVersion.VERSION_1_8
    }
}
dependencies {
    implementation 'com.google.androidbrowserhelper:androidbrowserhelper:1.0.0'
}

// MainActivity.java
import com.google.androidbrowserhelper.trusted.TwaLauncher;

public class MainActivity extends AppCompatActivity {
    ...
    static Uri LAUNCH_URI = Uri.parse("https://js.cotter.app/app?api_key=<api_key_id>&redirect_url=yourapp://&type=PHONE&code_challenge=<code_challenge>&state=<state>");
    
    public void login(View view) {
        new TwaLauncher(this).launch(LAUNCH_URI);
    }
}
```

{% endtab %}

{% tab title="CLI" %}

1. Open the user's browser with the URL above, also display it so the user can click it if opening the browser doesn't work.
2. Listen to the localhost port that you specified in the redirect URL
3. When the browser redirect back to you with the response below, handle the request and use the code, state, and challenge\_id to continue to Step 3.
   {% endtab %}
   {% endtabs %}

### Response

After the user's email or phone is verified, Cotter will redirect back to your app using `redirect_url` that you specified in step 2.

```http
yourapp://?
    code=<authorization_code>
    &state=<state>
    &challenge_id=<challenge_id>
```

{% hint style="info" %}
You should check that the `state` is the same as the initial state you passed in to the URL [here](#step-2-request-authorization-from-cotter).
{% endhint %}

#### Check out how to [Handle the URL Scheme](https://docs.cotter.app/sdk-reference/api-for-other-mobile-apps/api-for-mobile-apps/handling-url-scheme).

###

### Step 3: Request Tokens and Identity

In this step, you'll use your `code_verifier` , `authorization_code` and the `challenge_id` to request `tokens` and the user's email or phone number from Cotter's server.

{% hint style="info" %}
Your `authorization_token` is valid for 5 minutes, and can only be used once.
{% endhint %}

```
curl -XPOST \
-H 'Content-type: application/json' \
-H 'API_KEY_ID: <api_key_id>' \
-d '{
  "code_verifier": "<code_verifier>",
  "authorization_code": "<authorization_code>",
  "challenge_id": <challenge_id>,
  "redirect_url": "<redirect_url>"
}' 'https://www.cotter.app/api/v0/verify/get_identity?oauth_token=true'
```

## Request Tokens

<mark style="color:green;">`POST`</mark> `https://www.cotter.app/api/v0/verify/get_identity`

Request for tokens and user's email or phone number verification state (successfully verified or not).&#x20;

#### Query Parameters

| Name         | Type    | Description                                                                      |
| ------------ | ------- | -------------------------------------------------------------------------------- |
| oauth\_token | boolean | If `true`, will return OAuth Tokens (read "Handling Authentication with Cotter") |

#### Headers

| Name         | Type   | Description        |
| ------------ | ------ | ------------------ |
| API\_KEY\_ID | string | Your `API_KEY_ID`  |
| Content-Type | string | `application/json` |

#### Request Body

| Name                | Type    | Description                                                |
| ------------------- | ------- | ---------------------------------------------------------- |
| code\_verifier      | string  | Your `code_verifier` created in Step 1                     |
| authorization\_code | string  | The `authorization_code` received in Step 2                |
| challenge\_id       | integer | The `challenge_id` received in Step 2                      |
| redirect\_url       | string  | This MUST match the `redirect_url` you specified in Step 2 |

{% tabs %}
{% tab title="200 You'll receive the full information about the user from the object identifier and a token which contains a signature that you need to verify." %}

```
{
  "identifier": {
    "ID": "f4286df9-a923-429c-bc33-5089ffed5f68",
    "created_at": "2020-07-21T22:53:21.211367Z",
    "updated_at": "2020-07-21T22:53:21.211367Z",
    "deleted_at": "0001-01-01T00:00:00Z",
    "identifier": "putri@cotter.app", // User's email
    "identifier_type": "EMAIL",
    "device_type": "BROWSER",
    "device_name": "Mozilla/5.0 (Linux; Android 9; Android SDK built for x86 Build/PSR1.180720.075) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
    "expiry": "2020-08-20T22:53:21.19705Z",
    "timestamp": "2020-07-21T22:53:21.19705Z"
  },
  "oauth_token": {
    "access_token": "eyJhbGciOiJFUz...", // Validate this access token
    "id_token": "eyJhbGciOiJFUzI1...",
    "refresh_token": "27944:lb31DY5pG229n...",
    "expires_in": 3600,
    "token_type": "Bearer",
    "auth_method": "OTP"
  },
  "token": {...},
  "user": {
    "ID": "643a42c7-316a-4abe-b27e-f4d0f903bfea", // Cotter uesr ID
    "identifier": "putri@cotter.app",
    ...
  }
}
```

{% endtab %}

{% tab title="500 Challenge Expired means that either the authorization\_token is expired (you have 5 minutes to use the token), or you already used the token once." %}

```
{
  "msg": "Challenge Expired"
}
```

{% endtab %}
{% endtabs %}

### Step 4: Include the Token to your Server

Now that the email or phone number is verified, you can continue your Sign Up or Login process by submitting the email or phone number to your server, either now or after the user enters more information.

{% hint style="success" %}
You should include this `oauth_tokens` into your call to your backend for **Login** or **Registration**. Your backend should then verify that the access token is valid.
{% endhint %}

## Validating Cotter's Access Token&#x20;

Check out how to verify the OAuth Tokens from Cotter here:

{% content-ref url="../../getting-access-token/verifying-jwt-tokens" %}
[verifying-jwt-tokens](https://docs.cotter.app/getting-access-token/verifying-jwt-tokens)
{% endcontent-ref %}

## 🎉 You're done!

## Securing your Project

Since you'll be using your API Key from a front-end website or mobile app, your `API_KEY_ID` is exposed to anyone inspecting your code. Here are some ways to prevent abuse:

* [Only allow your website/app to use your API Key](https://docs.cotter.app/protecting-your-account/only-allow-your-website-app-to-use-your-api-key)
* [Rate Limit the number of authentication requests](https://docs.cotter.app/protecting-your-account/rate-limit)
* [Enable reCAPTCHA to prevent automated abuse](https://docs.cotter.app/protecting-your-account/enable-recaptcha-to-protect-against-automated-abuse)

## What are State and Code Challenge?

#### State:

Your app generates `state=XYZ` in the beginning of the auth flow. You should expect that Cotter's response on [Step 2](#response) when Cotter redirect back to your `redirect_url`, the state is the same (`state == XYZ`). This makes sure that the redirect was in response to your initial authentication request.

#### code\_challenge / verifier:&#x20;

This is needed for installed apps / SPA because they cannot store the Api Secret Key securely, so the `code_challenge` and `code_verifier` is for Cotter to make sure that the original App that requested authentication on [Step 2](#step-2-request-authorization-from-cotter) is the same as the one that asked for access token on [Step 3](#step-3-request-tokens-and-identity).
