Cotter
  • 🚀Getting Started
  • Features & Concepts
    • 💬Sign In with Email/Phone Number
    • 🔐Sign In with Device
      • How it works
    • 🧬Sign In with WebAuthn
  • 📌Quickstart Guides
    • All Guides & Tutorials
    • HTML – Sign in with Email/Phone
    • React – Sign in with Email/Phone
    • React – WebAuthn
    • ▲ Next.js
    • Angular
    • Webflow
    • Bubble.io
    • Python SDK for a CLI
    • React Native – Sign in with Device
    • iOS – Sign in with Device
    • Flutter – Sign in with Device
  • 📘SDK Reference
    • Web
      • Sign In with Email/Phone Number
        • Customize the Form
        • Checking the email or phone before sending a verification code
        • Sending Code or Link via WhatsApp
        • Styling
        • Older SDK
          • Customize the Form
      • Sign in with Social Login
        • Getting Access Tokens from Social Login Providers
        • Github Instructions
        • Google Instructions
      • Sign In with WebAuthn
        • Register WebAuthn for a logged-in user
      • Sign In with Device
        • Steps for Pop Up Authentication Prompt
        • Advanced Customization for Login Form
        • Advanced Customization for Pop Up Authentication Prompt
      • Getting Access Token and Logged-In User Info
      • Sending Successful Form Submission
      • FAQ & Troubleshooting
    • React Native
      • Installation
      • Sign In with Device
        • Add Email/Phone Verification
        • Authenticate from a Non-Trusted Device
        • Add a new Trusted Device
        • Remove Trusted Device
      • Sign In with Email/Phone Number
      • Getting Stored OAuth Tokens and User Information
      • FAQ
      • Older SDK Versions
        • Sign in with Email/Phone
        • Sending Code via WhatsApp
        • Sign In with Device
          • Authenticate from a Non-Trusted Device
          • Add a new Trusted Device
          • Customization
    • Flutter
      • Sign In with Device
        • Add Email/Phone Verification
        • Authenticate from a Non-Trusted Device
      • Sign in with Email/Phone Number
      • Getting the Logged-in User
      • Getting OAuth Tokens
      • Signing a User Out
    • iOS
      • Sign In with Email/Phone Number
      • Sign In with Device
        • Authenticate from a Non-Trusted Device
        • Push Notification
        • Check if Trusted Device is Enrolled
        • Add a New Trusted Device
        • Remove Trusted Device
      • Older Versions
        • Biometric/Pin
    • Android
      • Sign In with Device
        • Authenticate from a Non-Trusted Device
        • Check if Trusted Device is Enrolled
        • Add a new Trusted Device
        • Remove Trusted Device
        • Customization
      • Sign In with Email/Phone Number
      • Biometric/Pin
        • Advanced Methods
        • Customization
        • Setting Strings
        • Styling
      • Older SDK Version
        • Sign In with Device
          • Authenticate from a Non-Trusted Device
    • Python (for CLI)
    • API for Other Mobile Apps or CLI
      • Verify Email/Phone Number
        • Handling URL Scheme
    • Backend: Handling Response
  • 🛡️ Protecting Your Account
    • Only Allow Your Website/App to Use Your API Key
    • Rate Limit
    • Enable reCAPTCHA to Protect Against Automated Abuse
  • 🗝️ Getting Access Token
    • Cotter's OAuth 2.0 Tokens Specification
    • Getting the Tokens
      • Get Tokens during Authentication
      • Using the Refresh Token
    • Storing and Removing Tokens
    • Renewing Expired Tokens
    • Verifying JWT Tokens
    • Requesting Custom Fields on your JWT Token
    • Older API
      • Using HTTP Requests
      • Getting the Tokens
        • During Authentication
          • During Email/Phone Verification
        • During enrolling Trusted Devices
  • 🔌API Reference
    • User API
      • User Object
    • OAuth Tokens API
      • Verify JWT Token using API (serverless)
      • Requesting Custom Claims on your Access Token
      • Older API
    • OAuth Tokens from Social Login
    • Event Object
    • Reset PIN API
  • Older API
    • Validating Cotter's Identity Token
    • Validating Cotter's Event Response
Powered by GitBook
On this page
  1. Older API

Validating Cotter's Event Response

Cotter's Event Response includes the following information:

{
  "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

  • 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}

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

Example

// 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))
# 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)
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);
}
PreviousValidating Cotter's Identity Token

Last updated 5 years ago

Libraries for ed25519 algorithm are available in , , and other languages.

Javascript
Golang
Python