# Validating Cotter's Event Response

Cotter's Event Response includes the following information:

```javascript
{
  "ID": 1361, // Event ID
  "CreatedAt": "2020-02-27T22:22:48.705212512Z",
  "UpdatedAt": "2020-02-27T22:22:48.705212512Z",
  "DeletedAt": null,
  "client_user_id": "1014", // your client's User ID
  "issuer": "afcabd98-745f-4b9e-98de-af968d9951d3", // your API Key
  "event": "<EVENT NAME>",// requested event (LOGIN, or TRANSACTION, etc)
  "ip": "192.168.232.2", 
  "location": "Unknown",
  "timestamp": "1582842167",
  "method": "TRUSTED_DEVICE", // auth method: TRUSTED_DEVICE (other choices are PIN / BIOMETRIC)
  "new": false, // Is this a new pending event. More explanation below about Non-Trusted Device
  "approved": true, // Is this event approved.
  "signature": "oonMGCAxp3..." // Signature to make sure this event comes from Cotter's server
}
```

First, make sure you check the following:

* Check if the `client_user_id` is correct
* Check if the `timestamp` is fairly recent
* Check if the `event` matches the event name that you expected
* Check that the `issuer` is the same as your `API_KEY_ID`&#x20;
* Check that `approved` is true

#### Verifying the Signature

The signature ensures that this token comes from Cotter's server:

* Signature algorithm: `ed25519`
* Cotter's Public Key: `qqOaiQGjGsxBMgI5rdAasaACRiJthOqadmefjY5mS/c=`
* Signed Message:

```
{event.client_user_id}{event.issuer}{event.event}{event.timestamp}{event.method}{event.new}{event.approved}
```

{% hint style="info" %}
Note that there is no space and no `{}` in the message. It's all just 1 long string. ex. `152163b39fb6eb-a1ff-4f7b-a205-d80f3c664cfdEVENTNAME1584659078TRUSTED_DEVICEfalsetrue`&#x20;
{% endhint %}

#### Example <a href="#example" id="example"></a>

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

```go
// https://golang.org/pkg/crypto/ed25519/
func Verify(publicKey string, signStr string, args ...string) (bool, error) {
    str := []byte(strings.Join(args, ""))
    fmt.Println(strings.Join(args, ""))
    pubKey, err := base64.StdEncoding.DecodeString(publicKey)
    if err != nil {
        return false, responses.NewError("Fail verifying signature decoding pubkey", err)
    }
    signature, err := base64.StdEncoding.DecodeString(signStr)
    if err != nil {
        return false, responses.NewError("Fail verifying signature decoding signature", err)
    }
    valid := ed25519.Verify(pubKey, str, signature)
    return valid, nil
}

// Usage
valid, err := Verify(CotterPublicKey, event.Signature, event.ClientUserID, event.Issuer.String(), event.Event, event.Timestamp, string(event.Method), strconv.FormatBool(event.New), strconv.FormatBool(event.Approved))
```

{% endtab %}

{% tab title="Python" %}

```python
# https://pynacl.readthedocs.io/en/stable/signing/
import binascii
import nacl.signing
import nacl.encoding

pub64 = "qqOaiQGjGsxBMgI5rdAasaACRiJthOqadmefjY5mS/c="
signatureB64 = event["signature"]
message = event["client_user_id"] + event["issuer"] + event["event"] + event["timestamp"] + event["method"] + event["new"] + event["approved"]

signb = binascii.a2b_base64(signatureB64)
msgb = str.encode(message)

verify_key = nacl.signing.VerifyKey(pub64, encoder=nacl.encoding.Base64Encoder)
verify_key.verify(msgb, signb)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
import { Buffer } from "buffer";
import { sign } from "tweetnacl";

validateCotterEvent(event) {
    var message = `${event.client_user_id}${event.issuer}${event.event}${event.timestamp}${event.method}${event.new}${event.approved}`;
    var pubKey = "qqOaiQGjGsxBMgI5rdAasaACRiJthOqadmefjY5mS/c=";
    var signature = event.signature;
    
    const messageUint8 = new Uint8Array(Buffer.from(message, "utf8"));
    const signatureUint8 = new Uint8Array(Buffer.from(signature, "base64"));
    const pubKeyUint8 = new Uint8Array(Buffer.from(pubKey, "base64"));
    
    return sign.detached.verify(messageUint8, signatureUint8, pubKeyUint8);
}
```

{% endtab %}
{% endtabs %}

Libraries for `ed25519` algorithm are available in [Javascript](https://tweetnacl.js.org/#/), [Golang](https://golang.org/pkg/crypto/ed25519/), [Python](https://pynacl.readthedocs.io/en/stable/signing/) and other languages.[<br>](https://docs.cotter.app/verify-email-and-phone-number/api-for-mobile-apps/handling-url-scheme)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cotter.app/older-api/validating-cotters-event-response.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
