# Signed Identity

Signed Identity is a more secure way to provide contact identifiers. When the user logs in on your website or mobile app, your backend server will return a signed payload containing the identifiers for this user. This signed payload is called `SignedIdentity`. Take a look at the following sequence diagram:

<figure><img src="https://3210271997-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdnJZeZvhOMhDQA8SpjQM%2Fuploads%2FzJ9RTnCVhbXi9vx8J7SD%2FScreenshot%202024-06-18%20at%2011.16.41.png?alt=media&#x26;token=d0b495d4-1bfd-47fb-9a6b-8a6abcfcf816" alt="" width="375"><figcaption></figcaption></figure>

## Identify Contact with Signed Identity

After the signed identity is retrieved, your web or mobile application can use it to identify the contact as follows:

{% tabs %}
{% tab title="Android (Kotlin)" %}

```kotlin
// Call backend server for user login
val response = userLogin()

// and get signed identity
val signedIdentity = response.signedIdentity

bird.contact.identify( SignedIdentity(signedIdentity) )
```

{% endtab %}

{% tab title="iOS (Swift)" %}

<pre class="language-swift"><code class="lang-swift"><strong>// Coming soon...
</strong></code></pre>

{% endtab %}

{% tab title="Web (Js)" %}

```javascript
// Call your authenticated backend to get a signed identity
// Your backend must verify the user's session before issuing the JWT
const resp = await fetch('/api/bird-identity', {
  method: 'POST',
  credentials: 'include', // sends session cookies for authentication
});
const { signedIdentity } = await resp.json();

await Bird.contact.identify({
  strategy: 'SignedIdentityClaims',
  signedIdentity: signedIdentity,
});
```

{% endtab %}
{% endtabs %}

## Generate Signed Identity

The backend server can generate a signed identity for a user as follows:

* Get the signing key and issuer from the application settings in the Bird dashboard (Developer > Applications > (*your application)* > Overview tab).
* Sign the user identifiers payload using the signing key.

Here is a sample code to get you started:

{% tabs %}
{% tab title="Node.js" %}

```javascript
onst crypto = require('crypto');
const express = require('express');

const app = express();

// These come from your Bird dashboard:
// Developer > Applications > (your app) > Overview > Identity Signing Key
const issuer = process.env.BIRD_ISSUER;       // e.g. "mrn:v1:application:identity-claims-issuer:<workspaceId>/<appId>:1"
const signingKey = process.env.BIRD_SIGNING_KEY; // e.g. "d45013b0eb5355fe..."

function makeSignedIdentity(identifiers) {
    let header = JSON.stringify({
        "alg": "HS256",
        "typ": "JWT",
        "kid": issuer,
    });
    let payload = JSON.stringify({
        identifiers: identifiers,
    });

    let headerBase64 = Buffer.from(header).toString('base64url');
    let payloadBase64 = Buffer.from(payload).toString('base64url');
    let signature = crypto
        .createHmac('sha256', signingKey)
        .update(headerBase64 + "." + payloadBase64)
        .digest('base64url');

    return headerBase64 + "." + payloadBase64 + "." + signature;
}

// Endpoint that your frontend calls to get a signed identity
app.post('/api/bird-identity', async (req, res) => {
    // IMPORTANT: Authenticate the user BEFORE generating a signed identity.
    // Use your existing session/auth system (cookies, JWT, OAuth, etc.)
    // If this endpoint issues JWTs without authentication, any visitor
    // could impersonate any contact.
    const user = await getUserFromSession(req);
    if (!user) {
        return res.status(401).json({ error: 'Not authenticated' });
    }

    // Build identifiers from YOUR trusted user record.
    // Do NOT use identifiers sent from the client request body.
    let identifiers = [
        { key: "emailaddress", value: user.email },
    ];

    let signedIdentity = makeSignedIdentity(identifiers);

    res.json({ signedIdentity });
});

app.listen(3000);
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "strings"
)

// These come from your Bird dashboard:
// Developer > Applications > (your app) > Overview > Identity Signing Key
var issuer = os.Getenv("BIRD_ISSUER")         // e.g. "mrn:v1:application:identity-claims-issuer:<workspaceId>/<appId>:1"
var signingKey = os.Getenv("BIRD_SIGNING_KEY") // e.g. "d45013b0eb5355fe..."

type Identifier struct {
    Key   string `json:"key"`
    Value string `json:"value"`
}

func makeSignedIdentity(identifiers []Identifier) (string, error) {
    header, _ := json.Marshal(map[string]string{
        "alg": "HS256",
        "typ": "JWT",
        "kid": issuer,
    })

    payload, _ := json.Marshal(map[string]interface{}{
        "identifiers": identifiers,
    })

    headerBase64 := base64.RawURLEncoding.EncodeToString(header)
    payloadBase64 := base64.RawURLEncoding.EncodeToString(payload)

    dataToSign := headerBase64 + "." + payloadBase64
    h := hmac.New(sha256.New, []byte(signingKey))
    h.Write([]byte(dataToSign))
    signature := base64.RawURLEncoding.EncodeToString(h.Sum(nil))

    return fmt.Sprintf("%s.%s.%s", headerBase64, payloadBase64, signature), nil
}

// Endpoint that your frontend calls to get a signed identity
func birdIdentityHandler(w http.ResponseWriter, r *http.Request) {
    // IMPORTANT: Authenticate the user BEFORE generating a signed identity.
    // Use your existing session/auth system (cookies, JWT, OAuth, etc.)
    // If this endpoint issues JWTs without authentication, any visitor
    // could impersonate any contact.
    user, err := getUserFromSession(r)
    if err != nil || user == nil {
        http.Error(w, `{"error":"Not authenticated"}`, http.StatusUnauthorized)
        return
    }

    // Build identifiers from YOUR trusted user record.
    // Do NOT use identifiers sent from the client request body.
    identifiers := []Identifier{
        {Key: "emailaddress", Value: user.Email},
    }

    signedIdentity, err := makeSignedIdentity(identifiers)
    if err != nil {
        http.Error(w, `{"error":"Failed to generate identity"}`, http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(map[string]string{
        "signedIdentity": signedIdentity,
    })
}

func main() {
    http.HandleFunc("/api/bird-identity", birdIdentityHandler)
    http.ListenAndServe(":3000", nil)
}
```

{% endtab %}
{% endtabs %}
