# 5. Connections

Connection is a communication channel between two parties.
During the connection establishing process, both parts exchange their public keys.
This exchange results in both parties recording the other's public key, thereby forming a unique pairwise encryption channel.
That keys will be used for messages encryption during later communications between parties.
Mobile SDK can form an unlimited number of connections in this way.

There are two roles in the connection establishing process: **Inviter** and **Invitee**.

* The Inviter is the party that initiates the connection protocol with an **Invitation** message and transfer it in some usual way (SMS, QR, etc.). [Verity SDK](https://github.com/evernym/verity-sdk) can be used as an **Inviter**.
* The Invitee is the party that accepts the invitation to establish the connection. **Mobile SDK** represents the **Invitee** party. Bellow in this document we will explain which steps need to be taken in order to accept a connection invitation on the **Invitee** side using Mobile SDK.

> **NOTE:** library should be initialized before using credentials API. See [initialization documentation](3.Initialization.md)

To complete this section read through the following sections:

1. [Establishing connections](#establishing-connections)
1. [Reusing Existing Connections](#reusing-existing-connections)
1. [Deleting Connections](#deleting-connections)

## Establishing connections

Aries Connection and Out-of-Band protocols consist of several messages exchange:
* Inviter prepares `Connection Invitation` message and shares it with an Invitee some ual way (SMS, QR, etc.)
* Invitee sends `Connection Request` message to Inviter
* Inviter handles `Connection Request` message and sends `Connection Response` message to Invitee
* Invitee handles `Connection Response` message and sends `Connection Ack` message (if requested) to Inviter

### Steps overview

In order to accept a `Connection Invitation` an Invitee (client) need to take the following steps:

1. Check type of invitation: [aries connection](#connection-invitation-example) and [aries out-of-band](#out-of-band-invitation-example) formats are supported.
2. Ensure that connection has not been established yet.
3. If there is no existing connection:\
   3.1. Depending on the invitation type call corresponding method to create SDK state object.
   3.2. Await Connection is completed.
4. If there is an existing connection:\
    4.1. Reuse existing connection.

> **NOTE:** The library should be initialized before forming a connection. See [initialization documentation](3.Initialization.md)

### 0. Connection Application object

As we mentioned before in the [Storage](./2.Storage.md) document SDK does not save state objects, so the application must care about it.
It is up to the developer regarding what data to store in the application.  
On of the possible formats may match the following structure:
```
{
    "pwDid" - string, // connection pairwise DID - uniquely identifies pairwise connection
    "serialized" - string, // serialized representation of SDK Connection state object

    // metadata to show on the UI
    "name" - string, // inviter name
    "logo" - string, // (optional) inviter logo (optional - maybe missed)
    "goal" - string, //  A text defining the goal of the connection establishing (optional - maybe missed)
    
    // optionally
    "timestamp" - int // time of establishing of the connection (it can be shown on the UI and used for sorting) 
    "status" - string, // connection status (pending / completed)
    "invitation" - string // original invitation was used to establish the connection, 
                             It will simply check for already accepted invitations 
}
```
Later in this document, we will show how to get each of these fields. 

### 1. Identify the type of received invitation

### Aries Connection invitation

The value of `@type` field **must** end with `connections/1.0/invitation`.

To send this type of invitation from the Verity application, you need to use [this API call](https://app.swaggerhub.com/apis/evernym/verity-rest-api/1.0#/Relationship/relationship) with [this](https://app.swaggerhub.com/apis/evernym/verity-rest-api/1.0#/RelationshipInvitationRequest) body payload.

#### Connection Invitation Example

```
{
    // type of the message
    "@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
    // id of the message
    "@id": "467f6449-7d1f-4a9f-ada7-09d6444af083",
    // name of the Inviter
    "label": "Acme",
    // URL with the Inviter logo (Optional)
    "profileUrl": "https://s3.us-east-2.amazonaws.com/public-demo-artifacts/demo-icons/cbACME.png",
    // Endpoint of the Inviter Agnet
    "serviceEndpoint": "http://vas.evernym.com:80/agency/msg",
    // Public key of the Inviter to encrypt messages  
    "recipientKeys": [
        "9NR9NYh5z5HHu6nLHnQWXczUqRwrdoL4KBUWvo2fE6vj"
    ],
    // Keys defining the Inviter Agent (Optional)
    "routingKeys": [
        "9NR9NYh5z5HHu6nLHnQWXczUqRwrdoL4KBUWvo2fE6vj",
        "3mo3P6XzDzBvuktCgDQarACzzeV7zxrSExnicpuH7t83"
    ]
}
```

More information about Aries Connection invitation and related protocol you can find [here](https://github.com/hyperledger/aries-rfcs/tree/master/features/0160-connection-protocol). 

### Aries Out-of-band invitation

The value of `@type` field **must** end with `/out-of-band/1.0/invitation`.

To send this type of invitation from the Verity application **without a handshake protocol**, you need to use [this API call](https://app.swaggerhub.com/apis/evernym/verity-rest-api/1.0#/Relationship/relationship) with [this](https://app.swaggerhub.com/apis/evernym/verity-rest-api/1.0#/OutOfBandInvitationRequest) body payload.

This type of invitation can also be sent **with a handshake protocol** from the Verity application by using the out-of-band with a request attached. 
This is done by adding "by_invitation": tru to a body payload of the [Present Proof API call](https://app.swaggerhub.com/apis/evernym/verity-rest-api/1.0#/PresentProof/requestProof) or [Issue Credential API call](https://app.swaggerhub.com/apis/evernym/verity-rest-api/1.0#/IssueCredential/issueCredential).

#### Out-of-band Invitation Example:

```
{
    // type of the message
    "@type": "https://didcomm.org/out-of-band/1.0/invitation",
    // id of the message
    "@id": "9NR9NYh5z5HHu6nLHnQWXczUqRwrdoL4KBUWvo2fE6vj",
    // name of the Inviter
    "label": "Faber College",
    // invitation goal code defined by the Inviter (Optional)
    "goal_code": "issue-vc",
    // a text defining the goal of the connection establishing (Optional)
    "goal": "To issue a Faber College Graduate credential",
    // Protocols can be used to establish a connection
    "handshake_protocols": [
        "https://didcomm.org/didexchange/1.0",
        "https://didcomm.org/connections/1.0"
    ],
    // An additional message attached to the invitation (Optional)
    "request~attach": [
      {
          "@id": "request-0",
          "mime-type": "application/json",
          "data": {
              "json": "<json of protocol message>"
          }
      }
    ],
    // Service of the Inviter Agent
    "service": [
        {
            "id": "#inline",
            "type": "did-communication",
            // Endpoint of the Inviter Agnet
            "serviceEndpoint": "http://vas.evernym.com:80/agency/msg",
            // Public key of the Inviter to encrypt messages  
            "recipientKeys": [
                "9NR9NYh5z5HHu6nLHnQWXczUqRwrdoL4KBUWvo2fE6vj"
            ],
            // Keys defining the Inviter Agent (Optional)
            "routingKeys": [
                "9NR9NYh5z5HHu6nLHnQWXczUqRwrdoL4KBUWvo2fE6vj",
                "3mo3P6XzDzBvuktCgDQarACzzeV7zxrSExnicpuH7t83"
            ]
        },
    ]
}
```

More information about Aries Out-Of-Band invitation and related protocol you can find [here](https://github.com/hyperledger/aries-rfcs/tree/master/features/0434-outofband).

The following data can be taken from the **Invitation** to fill the application Connection object we defined before:
- `invite["label"]` - Name of the inviter (`name` field of  application Connection object)
- `invite["profileUrl"]` - URL with inviter logo (optional - maybe missed in the invitation) (`logo` field of  application Connection object)
- `invite["goal"]` - A text defining the goal of the connection establishing (optional - maybe missed in the invitation) (`goal` field of  application Connection object)

### URL invitation format

Both invitation types can also be represented in form of URL:

* Aries Connection invitation - https://\<domain>/\<path>?c_i=[Base-64 encoded invitation]
* Aries Out-Of-Band invitation - https://\<domain>/\<path>?oob=[Base-64 encoded invitation]
* Invitation without Base-64 encoded - https://\<domain>/\<path>

In this case, you need to decode Base-64 string first.
#### iOS
   ```objc
   [sdkApi resolveMessageByUrl:invite
                    completion:^(NSError *error, NSString *parsedInvite) {
        // ...
    }];
   ```
#### Android
   ```java
   int parsedInvite = UtilsApi.vcxResolveMessageByUrl(invite).get();
   ```
 The result value should match the formats we described above.
#### URL invitation format example:

```
http://vas.evernym.com:80/agency/msg? 

http://vas.evernym.com:80/agency/msg?oob=eyJAdHlwZSI6Imh0dHBzOi8vZGlkY29tbS5vcmcvb3V0LW9mLWJhbmQvMS4wL2ludml0YXRpb24iLCJAaWQiOiI2OTIxMmEzYS1kMDY4LTRmOWQtYTJkZC00NzQxYmNhODlhZjMiLCJsYWJlbCI6IkZhYmVyIENvbGxlZ2UiLCAiZ29hbF9jb2RlIjoiaXNzdWUtdmMiLCJnb2FsIjoiVG8gaXNzdWUgYSBGYWJlciBDb2xsZWdlIEdyYWR1YXRlIGNyZWRlbnRpYWwiLCJoYW5kc2hha2VfcHJvdG9jb2xzIjpbImh0dHBzOi8vZGlkY29tbS5vcmcvZGlkZXhjaGFuZ2UvMS4wIiwiaHR0cHM6Ly9kaWRjb21tLm9yZy9jb25uZWN0aW9ucy8xLjAiXSwic2VydmljZSI6WyJkaWQ6c292OkxqZ3BTVDJyanNveFllZ1FEUm03RUwiXX0

https://vty.im/cnf4m
```

### 2. Create Connection state object using received Invitation.

Successful execution will return a connection handle.
This handle points to created Connection state object and should be used for later operations (sending messages through the connection) related to this connection.

#### iOS

* For `aries connection` invitation:

   ```objc
   [appDelegate.sdkApi connectionCreateWithInvite: invitationId
           inviteDetails: inviteDetails
           completion:^(NSError *error, NSInteger connectionHandle) {
               // ...
           }];
   ```

* For `aries out-of-band` invitation:

   ```objc
   [appDelegate.sdkApi connectionCreateWithOutofbandInvite: invitationId
           invite: inviteDetails
           completion:^(NSError *error, NSInteger connectionHandle) {
               // ...
           }];
   ```

#### Android

* For `aries connection` invitation:

   ```java
   int connectionHandle = ConnectionApi.vcxCreateConnectionWithInvite(invitationId, invitationDetails).get();
   ```

* For `aries out-of-band` invitation:

   ```java
   int connectionHandle = ConnectionApi.vcxCreateConnectionWithOutofbandInvite(invitationId, invitationDetails).get();
   ```

### 3. Check whether connection has been already established.

The previous step only creates a Connection state object but not actually accept the invitation.
Before accepting a connection invitation you need to check that it has not been used yet.
In order to check does connection already exists, we need to retrieve invitations that were used during the creation of existing connections and compare them with the received invitation.

1. There are two ways of getting original invitation for existing connections:

   * Using SDK:\
       1.1 Deserialize connection state object
    
          #### iOS
           ```objC
           [appDelegate.sdkApi connectionDeserialize:serializedConnection
                   completion:^(NSError *error, NSInteger connectionHandle) {
                       // ...
                   }];
           ```
    
          #### Android
           ```java
           int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
           ```
       1.2 Get invitation 
    
          #### iOS
           ```objC
           [appDelegate.sdkApi getConnectionInviteDetails:connectionHandle
                                              abbreviated:FALSE
                                               completion:^(NSError *error, NSInteger connectionInvite) {
                                                  // ...
                                              }];
           ```
    
          #### Android
           ```java
           String connectionInvite = ConnectionApi.connectionInviteDetails(handle, abbreviated).get();
           ```

   * Using an original invitation stored in the application connection object.

1. Compare invitations - invitations match when one of the following fields is the same for both of them:

   * `@id` field (means exactly the same invitation)
   * `public_did` field (invitation from same Inviter)
   * `recipient_keys[0]` field (invitation from same Inviter)
    
1. If you find that connection already exists for the received invitation you would better reuse the existing connection rather than establish a new one.
You can read how to reuse existing connection in the [section](#reusing-existing-connections).
   
### 4. Accept connection invitation.

If there is no existing connection, and you want to accept the invitation to establish a connection you need to create Pairwise Cloud Agent and send `Connection Request` message.

* This Agent will be used for one particular connection, so a new Pairwise Cloud Agent will be created for every connection you establish.

* `Connection Request` message contains:
    * Public key of the Invitee which Inviter will be used to encrypt all following messages.
    * Cloud Agent public endpoint.
    * Pairwise Cloud Agent public keys which will be used to encrypt sending messages.

* All communication between Inviter <-> Invitee and Invite/Inviter <-> Pairwise Cloud Agent happens in encrypted way.

* The Invitee private keys to decrypt messages from Inviter or Cloud Agent are stored into Mobile SDK Wallet in encrypted form and cannot be read.

* Pairwise Cloud Agent receives messages in encrypted form, so only the Invitee can read the message content. 

1. Send `Connection Request` message

    #### iOS
    ```objc
    [appDelegate.sdkApi connectionConnect: connectionHandle
                           connectionType: connType
            completion:^(NSError *error, NSInteger inviteDetails) {
                // ...
            }];
    ```
    
    #### Android
    ```java
    ConnectionApi.vcxConnectionConnect(connectionHandle, connType).get();
    ```

1. Fetch Connection `pwDid`. This field will be unique among all established connections.
This field will be also needed during the handling of messages received from the Cloud Agent (in order to associate messages with serialized connections).

    #### iOS
    ```objC
    [appDelegate.sdkApi connectionGetPwDid:connectionHandle
                                completion:^(NSError *error, NSString *pwDid) {
        // ...
    }];
    ```
    
    #### Android
    ```java
    String pwDid = ConnectionApi.connectionGetPwDid(connectionHandle).get();
    ``` 

### 5. Serialize Connection object and store in the application storage.

Theoretical, processing of the `Connection Request` message on the Inviter side may take a while and User can just close the application before completion.\
It's better to store the connection state machine (received after sending `Connection Request`) into the applicaiton storage to avoid data loss.

> If you wish, you can skip storing for now and do it only after the connection will be completed (after the step 6).

1. Serialize Connection object
   #### iOS
    ```objC
    [appDelegate.sdkApi connectionSerialize:connectionHandle
            completion:^(NSError *error, NSString *serializedConnection)) {
                // ...
            }];
    ```

   #### Android
    ```java
        String serializedConnection = ConnectionApi.connectionSerialize(connectionHandle).get();
    ``` 

2. Save `serialized` sdk connection state object and `pwDid` into your application connection object. 

3. The `status` of the connection is considered as `pending` at this step. 

4. Every time in the future you want to perform some operations using the created connection you firstly need to fetch Connection object from the storage and deserialize SDK object from its serialized representation (receive a new handle).

### 6. Await Connection is completed.

The connection will be completed when `Connection Response` message is received back from the Inviter. This message contains public keys which will be used by the Inviter for messages exchange. Inviter may change original keys put into Invitation as it was transferred using some public way.

1. Fetch Connection record from the storage and deserialize pending Connection state object

   #### iOS
    ```objC
    [appDelegate.sdkApi connectionDeserialize:serializedConnection
            completion:^(NSError *error, NSInteger connectionHandle) {
                // ...
            }];
    ```

   #### Android
    ```java
    int existingConnectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
    ```

2. Await connection completion. There are two ways regarding how to await `Connection Response` message depending on the messages receiving strategy you use:

    1. Polling - call `connectionUpdateState` function in loop until returned state is not equal `4` (`Accepted`). 
       
       ### iOS
    
        ```objc
        while(1) {
            [appDelegate.sdkApi connectionUpdateState:connectionHandle
                completion:^(NSError *error, NSInteger state) {
                        if (state == 4){
                            break;
                        }
            }
        }
        ```
    
       ### Android
    
        ```java
        int state = -1;
        while(state != 4){
            state = ConnectionApi.vcxConnectionUpdateState(connectionHandle).get();
        }
        ```
       These functions do the following things internally:
        * Downloads all pending messages from the Cloud Agent related to the connection
        * Find matching `Connection Response` message
        * If message found -> updates state machine with it and update message status on the Cloud Agent as read.
    
    2. Push notifications - as push notification doesn't contain the type of received message we can download all messages and analyze them:
       * Use common `downloadPendingMessages` function to download messages.
       * Find matching `Connection Response` message. The following conditions must met:
            * value of `["decryptedPayload"]["@type"]` field must ends with `response`
            * value of `pairwiseDID` field must match to the `pwDid` received after sending `Connection Request`
    
       * Update Connection state object with received `Connection Response` message:
    
           #### iOS
        
            ```objc
                [appDelegate.sdkApi connectionUpdateStateWithMessage:connectionHandle
                                                             message:message
                                                          completion:^(NSError *error, NSInteger state) {
                    // ....
                }
            ```
        
           #### Android
        
            ```java
            int state = ConnectionApi.vcxConnectionUpdateStateWithMessage(connectionHandle, message).get();
            ```
    
        * Update status of the message as read. See [messages documentation](./4.MessagesFlow.md) for message update information.
          #### iOS
          ```objC
          [appDelegate.sdkApi updateMessages:messageStatus
                  pwdidsJson:handledMessage
                  completion:^(NSError *error) {
                      // ...
                  }];
          ```

          #### Android
            ```java
            UtilsApi.vcxUpdateMessages(messageStatus, handledMessage).get()  
            ```

### 7. Serialize Connection object and store in the application storage.

Once we get the connection completed (it means that internal representation of SDK connection state object changed) we need to update the corresponding record in the application storage (or add a new record if you skipped step 5) to contain the latest serialized connection state.

1. Serialize Connection object
   #### iOS
    ```objC
    [appDelegate.sdkApi connectionSerialize:connectionHandle
            completion:^(NSError *error, NSString *serializedConnection)) {
                // ...
            }];
    ```

   #### Android
    ```java
        String serializedConnection = ConnectionApi.connectionSerialize(connectionHandle).get();
    ``` 

2. Update `serialized` value from the corresponding record stored in the application storage.

3. The `status` of the connection is considered as `established` at this step.

4. Every time in the future you want to perform some operations using the created connection you firstly need to fetch Connection object from the storage and next deserialize SDK object from its serialized representation (receive a new handle).

## Reusing Existing Connections

With adding more and more connections, its getting hard for user to remember which connections already established. There is potential that some of the new connections user tries to establish already exists in list of connections (e.g. QR code was scanned multiple types). In this case we should not create new connection and try to reuse existing one.

### Aries Connection invitation

Aries Connection Invitations match when one of the following fields is the same for a new invitation and one of existing:

* `@id` field (means exactly the same invitation)
* `public_did` field (invitation from same Inviter)
* `recipient_keys[0]` field (invitation from same Inviter)

A regular Aries connection protocol does not contain reusing or redirection steps. 
If you detected that connection already exists you can optionally show an information message to User and just use the found connection instead of creating a new one.

### Aries Out-Of-Band Connection invitation

In contrast to `Aries Connection`,  Aries [Out-of-Band](https://github.com/hyperledger/aries-rfcs/tree/master/features/0434-outofband) protocol describes the protocol allowing as establishing new connections and as reusing of existing.
According to Out-Of-Band protocol when we detected a duplicate connection, we need to awake an existing connection and use it instead of establishing a new one. 

Aries Out-Of-Band Invitations match when one of the following fields is the same for a new invitation and one of existing:

* `public_did` field (invitation from same Inviter)
* `recipient_keys[0]` field (invitation from same Inviter)

> Note: If `@id` field matched it means that you have exactly the same invitations, but in this case, you more likely not need to follow `reusing` steps and instead simply show the information message to the User.

The steps need to be taken by the app also depends on the format of received Out-of-Band invitation.
If you want to get guidelines on how to handle all possible Out-of-Band invitation cases go to the [document](./Out-of-Band.md)

For this section we assume accomplishing the following facts:
1. Connection matching to the provided invitation is already exists (either `public_did` or `recipient_keys[0]` are the same).
1. Out-of-Band invitation contains `handshake_protocols`
1. Out-of-Band invitation does not `request~attach` or it's an empty array.

##### Steps

1. Deserialize existing Connection state object which matched the invitation

   #### iOS
    ```objC
    [appDelegate.sdkApi connectionDeserialize:serializedConnection
            completion:^(NSError *error, NSInteger connectionHandle) {
                // ...
            }];
    ```

   #### Android
    ```java
    int existingConnectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
    ```

1. Send Connection Reuse message. By sending this message you ensure that the connection is still alive and can be used. 

   #### iOS
    ```objC
    [appDelegate.sdkApi connectionSendReuse:existingConnectionHandle
            invite:newInvite
            withCompletion:^(NSError *error) {
                // ...
            }];
    ```

   #### Android
    ```java
     ConnectionApi.connectionSendReuse(existingConnectionHandle, newInvite).get();
    ```

1. Await for `handshake-reuse-accepted` message received back from the remote side.
   * Use common `downloadPendingMessages` function to download messages.
   * Find matching `Handshake Rese Accepted` message. The following conditions must met:
       * value of `["decryptedPayload"]["@type"]` field must ends with `handshake-reuse-accepted`
    * value of `["decryptedPayload"]["~thread"]["pthid"]` field must match to the value of `@id` field from Connection Invitation.

   * After receiving of `handshake-reuse-accepted` message, the connection is considered as `reused` and can be used instead of creating a new one.
     
   * Update status of the message as read. See [messages documentation](./4.MessagesFlow.md) for message update information.

## Deleting Connections

It may happen that after some time a User wants to delete connections that are no longer need to him.
In order to delete a connection you need to perform the next steps:

1. Delete a Pairwise Cloud Agent associated with the Connection, so that it cannot be used anymore for sending or receiving messages.
   
   1.1. Deserialize existing Connection state object
    
       #### iOS
        ```objC
        [appDelegate.sdkApi connectionDeserialize:serializedConnection
                completion:^(NSError *error, NSInteger connectionHandle) {
                    // ...
                }];
        ```
    
       #### Android
        ```java
        int connectionHandle = ConnectionApi.connectionDeserialize(serializedConnection).get();
        ```

    1.2. Delete Pairwise Cloud Agent associated with the Connection
    
       #### iOS
        ```objC
        [appDelegate.sdkApi deleteConnection:connectionHandle
                withCompletion:^(NSError *error) {
                    // ...
                }];
        ```
    
       #### Android
        ```java
         ConnectionApi.deleteConnection(connectionHandle).get();
        ```

1. Delete connection data from the application storage.

## Expected errors with establishing connection

### Connection already exists

It is expected use cases when user on mobile device tries to establish connection which already exists (user already connected before tries again). 
In that case, we don't need to reset connection (delete existing connection and create new connection with same pair). You can reuse existing connection.

You can find more details about this use case [here](#reusing-existing-connections).

## Next Step

Now your application is able to established connections with other parties.
You are ready to read how to [receive verifiable credentials](6.Credentials.md).
