Ariadne Signature Profile v0

Ariadne Identity Related Specifications

Ariadne Signature Profile v0

Table of contents

Ariadne Signature Profile Specification

Authors:
  Yarmo Mackenbach <yarmo@keyoxide.org> (https://yarmo.eu/)
Contributors:
  André Jaenisch (https://jaenis.ch/)
  Dario Vladović <d.vladimyr@gmail.com>
Version: 0
Published: 2023-06-08
Last updated: 2023-09-13

Abstract

This specification describes a method to create simple Ariadne Identity Profiles using basic cryptography. It also describes a method to exchange such profiles between clients and servers using HTTP and JWS.

Status

This version of the specification is active.

1. Introduction

Ariadne Identity Profiles are a technique to claim and prove online identities. The process is roughly as follows:

  • Alice creates a cryptographically-secured document (CSD), usually a key or a signature,
  • Alice links her CSD to an online account she has created on a website, usually through a URL,
  • Alice links her online account to her CSD, usually by mentioning the CSD's identifier or fingerprint,
  • Bob receives Alice's CSD and opens it,
  • Bob sees the URL to her online account and visits it,
  • Bob sees the identifier of her CSD mentioned by the online account,
  • Bob concludes that the same person created the CSD and the online account.

Alice has tied her online account on a website to her CSD, and vice versa. This is called bidirectional linking and forms the basis of online identity verification. Once Alice links two or more accounts to her CSD and back, she has created an online identity or persona.

Since the creation of Keyoxide — the platform that did not invent this method but rather formalized it and make it more broadly accessible — in 2020, the only method to create an Ariadne Identity Profile was using OpenPGP. The principal benefit was the existing ecosystem of OpenPGP-compatible libraries and key exchange protocols. This made it trivial to automate Bob's half of the process — receive a CSD, read it, verify the identities.

However, there was and still is a lack of programming libraries able to write OpenPGP keys including the lesser-known functionality of notations. This has made it near-impossible to create beginner-friendly tools to help with Alice's half of the process — create a CSD, fill it with identity claims and send it to dedicated servers. Until now, Keyoxide/Ariadne Identity Profiles are manually created and maintained almost exclusively through the use of the gpg command line tool.

This specification describes an alternative method to create Ariadne Identity Profiles without needing OpenPGP at all, exclusively relying on basic cryptographic standards for which there are libraries in nearly every programming language. The goal of this alternative method is to open the world of online identity verification to a much broader audience through the creation of user-friendly tools and interfaces.

This version of the specification will be concise and likely too simplistic at times. Revisions will fix that at later stages. This version exists to map out how the process should work and see what parts create issues or bottlenecks. This version of the specification will not follow most usual notational conventions except for the ones specified below.

This version of the specification will also be strict and allow only certain configurations and choices to limit the surface for error. Future versions may relax those restrictions where such freedom is deemed beneficial.

Contributions to this document are always appreciated.

1.1. Notational Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

2. Ariadne Signature Profiles

Ariadne Signature Profiles (ASP) are Ariadne Identity Profiles (AIP) stored as a cryptographic signature.

An AIP is the description of an online identity and MUST contain a list of identity claims — links to online accounts and other "virtual property" that can be verified.

AIPs MUST also contain a name, be it real or fake.

AIPs MAY also contain a description or a biography, an avatar and/or other personal information such as a birthday. Always be sensible with personally-identifiable information as this may de-anonymize a profile despite using a fake name.

Like passports and other proofs of identification in the real world, AIPs must have a unique quality to prevent impersonation — if we could all simply claim each other's accounts, there would be no such thing as "identity". AIPs rely on cryptography for this uniqueness. After all, cryptographic keys are uniquely generated (under normal conditions) and impractical to reverse-engineer. As long as the person who creates a cryptographic key manages to keep the private key secret, this person holds something that is unique in this world.

An ASP MUST be signed by a cryptographic key to be a valid profile. The resulting signature protects the integrity of the profile — prevent bad actors from changing elements of the profile — and provides a source of authenticity — prevent bad actors from claiming other people's accounts.

ASPs uses JSON Web Signatures or JWS ([JWS]) as the means to encode, secure and transport the profile.

ASPs MUST use one of the following combinations of signature algorithm and curve:

  • algorithm: "EdDSA", curve: "Ed25519" ([RFC8037])
  • algorithm: "ES256", curve: "P-256"

ASPs MUST include the public key inside the JWS in JWK [JWK] format.

2.1. Profile JWS

To create an ASP, a JWS must be generated.

The JWS MUST be serialized using Compact Serialization as defined in section 3.1 of [RFC7515].

2.1.1. Profile JWS header

The "typ" header MUST be set to "JWT".

The "alg" header MUST be set to any of the algorithms defined in 2. (see [IANA-JOSE]).

The "jwk" header MUST be set to the profile's public key in JWK format.

The "kid" header MUST be set to the profile's key's fingerprint, see 2.2.

2.1.2. Profile JWS payload

The JWS payload MUST be JSON-formatted.

The JWS payload MUST contain the following claims:

  • "http://ariadne.id/version": see 2.1.2.1.
  • "http://ariadne.id/type": see 2.1.2.2.
  • "http://ariadne.id/name": see 2.1.2.3.
  • "http://ariadne.id/claims": see 2.1.2.4.

The JWS payload MAY contain the following claims:

  • "http://ariadne.id/description": see 2.1.2.5.
  • "http://ariadne.id/avatar_url": see 2.1.2.6.
  • "http://ariadne.id/email": see 2.1.2.7.
  • "http://ariadne.id/color": see 2.1.2.8.
  • "exp": see 2.1.2.9.

The JWS payload MAY also contain other claims not defined in this document.

2.1.2.1. version

The full claim MUST be written as:

http://ariadne.id/version

The associated value MUST be a number.

This claim tells the client how to interpret the different payload claims.

To comply with this version of the specification, this property's value MUST be "0".

This claim is REQUIRED.

2.1.2.2. type

The full claim MUST be written as:

http://ariadne.id/type

The associated value MUST be a string.

This claim tells the client how to process the incoming JWS.

This claim's value MUST be "profile".

This claim is REQUIRED.

2.1.2.3. name

The full claim MUST be written as:

http://ariadne.id/name

The associated value MUST be a string and can contain any arbitrary sequence of characters.

This claim gives the profile a human-readable name or other method of identifying the profile. The name can be real or fake.

This JSON property is REQUIRED.

2.1.2.4. claims

The full claim MUST be written as:

http://ariadne.id/claims

The associated value MUST be a JSON array of strings where each element of the array is a URL.

This claim contains the actual identity claims associated with the profile. Each identity claim is a URI or URL pointing to an online account or other form of "virtual property". Not all platforms and services are supported and some require very specific claim formatting. A registry on how all identity claims should be formed, parsed and processed is still being worked on. In the meantime, the source code for the [DOIP-JS] and [DOIP-RS] libraries serve as source of truth.

This JSON property is REQUIRED.

2.1.2.5. description

The full claim MUST be written as:

http://ariadne.id/description

The associated value MUST be a string and can contain any arbitrary sequence of characters.

This claim enables the profile to tell a little bit more about the person who created it or the intended audience of the profile.

This claim is OPTIONAL.

2.1.2.6. avatar_url

The full claim MUST be written as:

http://ariadne.id/description

The associated value MUST be a URL pointing at a publicly accessible rasterized image or vectorized image.

This claim tells the client to fetch an image and display it as the profile's avatar.

Note that this image may be linked to the profile by the provider hosting the image and this could de-anonymize the profile.

This claim is OPTIONAL.

2.1.2.7. email

The full claim MUST be written as:

http://ariadne.id/email

The associated value MUST be an email address.

This claim tells the client that an email address is associated with this profile. The presence of this property constitutes in no way a verified claim for this email address and clients MUST display the email address distinctly from the claims and without markers of verification, including check marks or crosses.

Clients are RECOMMENDED to hide the email address if one or more identity claims failed verification.

Clients MAY use the email address to fetch additional information about a profile, including querying for avatars from libravatar.org, querying for OpenPGP keys from servers like keys.openpgp.org or querying for OpenPGP keys

Clients MUST NOT use or display additional information obtained through the email address if one or more identity claims failed verification.

This claim is OPTIONAL.

2.1.2.8. color

The full claim MUST be written as:

http://ariadne.id/color

The associated value MUST be a string representation of a hex color code formatted as follows:

COLOR_CODE = "#" HEXADECIMAL_CHAR * 6

This claim tells the client what primary color to use for the profile's visual theming. Values for this claim use the sRGB colorspace.

This claim is OPTIONAL.

2.1.2.9. exp

The full claim MUST be written as:

exp

See https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4

This claim is OPTIONAL.

2.2. ASP fingerprint

The fingerprint (or thumbprint) for an ASP follows the method defined in [RFC7638] for computing JWK thumbprints and is obtained as follows:

  • construct a JSON object with the "crv", "kty", "x" and "y" (when present) properties in that specific order obtained from the signing key,
  • stringify the JSON object,
  • hash the string using SHA512,
  • take the first 16 bytes of the resulting hash,
  • encode them using BASE32 (no padding).

The resulting string is the fingerprint for the ASP and will be used as proof to verify the identity claims.

The fingerprint is not case-sensitive and MAY be displayed in lowercase or uppercase. Non-public-facing operations SHOULD use uppercase fingerprints.

While public keys with the P-256 curve have both public "x" and "y" parameters, public keys with the Ed25519 curbe only have the "x" parameter. See section 6.2 of [RFC7518] for more information on the various JWK parameters for Elliptic Curve keys.

The BASE64 and BASE32 encoding schemes mentioned above are the ones described in section 4 and section 6 respectively of [RFC4648].

3. Ariadne Signature Profile Exchange Protocol

OpenPGP-based AIPs worked well because the profiles were stored inside public keys and these were distributed using dedicated servers.

ASPs use EcDSA/EDDSA keys and basic cryptographic signatures, meaning it's not possible to use OpenPGP's vast infrastructure to distribute ASPs. This section describes a simple client-server protocol and a server-client protocol to facilitate the distribution of ASPs.

Both "client-server" and "server-client" interactions are initiated by clients, the name simply reflects the direction of travel of the profiles.

Servers compatible with the ASPE protocol MUST accept and handle HTTP OPTIONS requests. If a server chooses to implement "client-server" interactions, they MUST accept and handle HTTP POST requests. If a server chooses to implement "server-client" interactions, they MUST accept and handle HTTP GET requests and SHOULD accept and handle HTTP HEAD requests. Servers MUST reject all other HTTP methods and return a 405 METHOD NOT ALLOWED response.

3.1. ASPE URI

Every ASP uploaded to an ASPE-compatible server and publicly accessible from an ASPE-compatible server MUST be identifiable by an ASPE URI.

ASPE URIs are constructed as follows:

URI = "aspe" ":" domain ":" identifier

The domain is the domain name of the ASPE-compatible server. The construction of the domain name follows specification from section 2.3.1 of [RFC1035].

The identifier MUST be the profile's key's fingerprint, see 2.2.

3.2. Request JWS

A JWS must be generated for some of these interactions. The cryptographic key that signs this "request JWS" (described in this section) must be the same as the key used to sign the "profile JWS" (described in 2.1.).

The JWS MUST be serialized using Compact Serialization as defined in section 3.1 of [RFC7515].

3.2.1. Request JWS header

The "typ" header MUST be set to "JWT".

The "alg" header MUST be set to the profile's key's algorithm as defined in 2.

The "jwk" header MUST be set to the profile's public key in JWK format.

The "kid" header MUST be set to the profile's key's fingerprint, see 2.2.

3.2.2. Request JWS payload

The JWS payload MUST be JSON-formatted.

The JWS payload MUST contain the following claims:

  • "http://ariadne.id/version": see 3.2.2.1.
  • "http://ariadne.id/type": see 3.2.2.2.
  • "http://ariadne.id/action": see 3.2.2.3.
  • "iat": see 3.2.2.4.

Depending on the "action" of the JWS, its payload MAY contain the following claims:

  • "http://ariadne.id/profile_jws": see 3.2.2.5.
  • "http://ariadne.id/aspe_uri": see 3.2.2.6.
3.2.2.1. version

The full claim MUST be written as:

http://ariadne.id/version

The associated value MUST be a number.

This claim tells the server how to interpret the different payload claims.

To comply with this version of the specification, this property's value MUST be "0".

This claim is REQUIRED.

3.2.2.2. type

The full claim MUST be written as:

http://ariadne.id/type

The associated value MUST be a string.

This claim tells the server how to process the incoming JWS.

This claim's value MUST be "request".

This claim is REQUIRED.

3.2.2.3. action

The full claim MUST be written as:

http://ariadne.id/action

The associated value MUST be a string.

This claim tells the server what the user is asking it to do.

This claim's value MUST be any of the following values:

  • "create": upload a new ASP to the server. The payload property "http://ariadne.id/profile_jws" becomes REQUIRED.
  • "update": upload a new ASP to replace an existing ASP on the server. The payload properties "http://ariadne.id/profile_jws" and "http://ariadne.id/aspe_uri" become REQUIRED.
  • "delete": delete an existing ASP on the server. The payload property "http://ariadne.id/aspe_uri" becomes REQUIRED.

This claim is REQUIRED.

3.2.2.4. iat

The full claim MUST be written as:

iat

See https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6

The server MUST reject requests with iat values that are too old as a security measure against replay attacks. The server MUST reject requests with iat values that are too far ahead in the future to be considered a reasonable mistake. What constitutes reasonable limits for iat values is subjective and must strike a balance between being restrictive enough for security and permissive enough to account for poor connectivity and suboptimal network infrastructure that clients may have to deal with.

It is RECOMMENDED to allow iat values that are at most 60 minutes old, as well as iat values that are at most 60 minutes ahead in the future. Implementations MAY adjust these values.

This claim is REQUIRED.

3.2.2.5. profile_jws

The full claim MUST be written as:

http://ariadne.id/profile_jws

The associated value MUST be a Compact-Serialized profile JWS.

This claim provides the server with a new profile JWS to store in its database.

This claim is OPTIONAL.

3.3. Client-Server

Client-server interactions include all the interactions initiated by people creating and maintaining their own profile. Client-server interactions are HTTP POST requests made to an HTTP endpoint, the URL to which is constructed as follows:

POST URL = "https://" domain "/.well-known/aspe/post/"

The domain is the domain of the ASPE-compatible server.

The HTTP POST requests have a JWS as body. Note that this "request JWS" is not the "profile JWS" described in 2.1. containing the actual profile, meaning some of the client-server interactions may involve nested JWSs.

Servers MUST reject request JWSs that were not issued within 60 seconds of the moment of processing — determined by the request JWS's "iat" header — and return a 400 BAD REQUEST response.

3.3.1. Uploading a new profile

To upload a new ASP, an HTTP POST request is sent to the POST URL described in 3.3. This request MUST have a Compact-Serialized "request JWS" as body. This request MUST set its "Content-Type" header to "application/asp+jwt; charset=UTF-8".

The request JWS MUST have the "http://ariadne.id/action" payload property set to "create".

The request JWS MUST include the "http://ariadne.id/profile_jws" payload property and set it to valid Compact-Serialized profile JWS.

If the JWS was badly constructed, the server MUST ignore the request and return a 400 BAD REQUEST response.

Upon success, the server MUST return a 201 CREATED response.

3.3.2. Updating an existing profile

To upload a new ASP and replace an existing one, an HTTP POST request is sent to the POST URL described in 3.3. This request MUST have a Compact-Serialized "request JWS" as body. This request MUST set its "Content-Type" header to "application/asp+jwt; charset=UTF-8".

The request JWS MUST have the "http://ariadne.id/action" payload property set to "update".

The request JWS MUST include the "http://ariadne.id/profile_jws" payload property and set it to a valid Compact-Serialized profile JWS.

The request JWS MUST include the "http://ariadne.id/aspe_uri" payload property and set it to the ASPE URI of the existing ASP that is to be replaced.

If the request/profile JWS was signed by a different key than the one used for the existing ASP, the server MUST ignore the request and return a 400 BAD REQUEST response.

If the JWS was badly constructed, the server MUST ignore the request and return a 400 BAD REQUEST response.

Upon success, the server MUST return a 200 OK response.

3.3.3. Deleting an existing profile

To remove an existing ASP, an HTTP POST request is sent to the POST URL described in 3.3. This request MUST have a Compact-Serialized "request JWS" as body. This request MUST set its "Content-Type" header to "application/asp+jwt; charset=UTF-8".

The request JWS MUST have the "http://ariadne.id/action" payload property set to "delete".

The request JWS MUST include the "http://ariadne.id/aspe_uri" payload property and set it to the ASPE URI of the existing ASP that is to be deleted.

If the request JWS was signed by a different key than the one used for the existing ASP, the server MUST ignore the request and return a 400 BAD REQUEST response.

If the JWS was badly constructed, the server MUST ignore the request and return a 400 BAD REQUEST response.

Upon success, the server MUST return a 200 OK response.

3.4. Server-client

Server-client interactions include all the interactions initiated by people wanting to view and verify other people's profiles. Server-client interactions are HTTP GET requests made to an HTTP endpoint, the URL to which is constructed as follows:

GET URL = "https://" domain "/.well-known/aspe/id/" id

The domain is the domain of the ASPE-compatible server. The id is the unique identifier assigned by the server to each ASP uploaded to it.

3.4.1. Fetching a profile

To fetch an ASP, an HTTP GET request is sent to the GET URL described in 3.3. with the unique identifier assigned to the ASP by the server.

If no ASP was found using that identifier, the server MUST return a 404 NOT FOUND response.

If the ASP has expired — determined by the profile JWS's "iat" header — the server MUST return a 404 NOT FOUND response.

Upon success, the server MUST return a 200 OK response with the Compact-Serialized profile JWS as body. This response MUST have its "Content-Type" header set to "application/asp+jwt; charset=UTF-8".

3.5. API endpoints

3.5.1. /post

The /.well-known/aspe/post API endpoint enables people to upload and manage their profiles on the server. Supporting this API endpoint is OPTIONAL.

See 3.3. Client-Server

3.5.2. /id/:id

The /.well-known/aspe/id/:id API endpoint enables people to obtain profiles stored on the server. Supporting this API endpoint is REQUIRED.

See 3.4. Server-Client

3.5.3. /version

The /.well-known/aspe/version API endpoint informs clients about the software that the server is running. Supporting this API endpoint is REQUIRED.

This API endpoint MUST only accept and handle HTTP GET, HEAD and OPTIONS requests. Servers MUST reject all other HTTP methods and return a 405 METHOD NOT ALLOWED response.

If the HTTP request has the Accept header set to "text/html" or "text/plain", the server MUST respond with a plain text response constructed as follows:

VERSION PLAIN RESPONSE = name "/" version

The name is the canonical name of the server software. The version is the version of the server software.

If not, the server MUST assume a JSON object is requested and MUST respond with a JSON object constructed with the following properties:

  • "name": the canonical name of the server software (REQUIRED, type: string)
  • "version": the version of the server software (REQUIRED, type: string)
  • "repository": the url of the source code repository of the server software (OPTIONAL, type: string)
  • "homepage": the url of the homepage of the server software (OPTIONAL, type: string)

4. Security considerations

4.1. Server implementations

Due to the open nature of both the profile JWS format and the ASPE interface, server implementations compatible with the ASPE interface and able to host ASPs must also implement adequate measures to protect themselves against abuse.

Server implementations should limit the body size of incoming ASPE requests to a value that is sensible for plaintext documents that are a collection of small strings and URIs. If implemented, servers must reject ASPE requests with a body size larger than this limit and return a 413 CONTENT TOO LARGE response.

Server implementations should rate limit incoming ASPE requests and this limit may be global or per IP address that requests are coming from. If implemented, servers must reject ASPE requests when the rate limit has been reached and return a 429 TOO MANY REQUESTS response.

4.2. Secret key encryption for clients

Clients that implement the ASPE protocol so they can upload and manage profiles on behalf of a user are most likely to require the user to input their secret key at some point. These clients are also likely to generate those secret keys for their users and subsequently allow the user to store it, or even store it on behalf of the user. Clients are strongly recommended to allow users to encrypt their secret keys with a password before exporting it. If clients store secret keys on the filesystem, they should never do so without encrypting them first using user-provided passwords, unless the filesystem is known by the client to already provide adequate security measures.

References

[DOIP-JS] https://codeberg.org/keyoxide/doipjs

[DOIP-RS] https://codeberg.org/keyoxide/doip-rs

[IANA-JOSE] https://www.iana.org/assignments/jose/jose.xhtml

[JWS] https://www.rfc-editor.org/rfc/rfc7515

[JWK] https://www.rfc-editor.org/rfc/rfc7517

[RFC1035] https://www.rfc-editor.org/rfc/rfc1035

[RFC3986] https://www.rfc-editor.org/rfc/rfc3986

[RFC4648] https://www.rfc-editor.org/rfc/rfc4648

[RFC7515] https://www.rfc-editor.org/rfc/rfc7515

[RFC7518] https://www.rfc-editor.org/rfc/rfc7518

[RFC7638] https://www.rfc-editor.org/rfc/rfc7638

[RFC8037] https://www.rfc-editor.org/rfc/rfc8037

Appendix A. Examples

A.1. Creating a new profile

Assuming we have created a new Ed25519 key for which the private key in PEM format is:

    -----BEGIN PRIVATE KEY-----
    MC4CAQAwBQYDK2VwBCIEIP3BQro3yMfwuf0HUTP9yz2H9BS4AIozIqEYUFPzwsMx
    -----END PRIVATE KEY-----

and in BASE64-encoded DER format is:

    MC4CAQAwBQYDK2VwBCIEIP3BQro3yMfwuf0HUTP9yz2H9BS4AIozIqEYUFPzwsMx

and in JWK format is:

    {
        "kty": "OKP",
        "use": "sig",
        "crv": "Ed25519",
        "d": "_cFCujfIx_C5_QdRM_3LPYf0FLgAijMioRhQU_PCwzE",
        "x": "__poSQwNedopfLKP3ZgM6FXz9LIJszDZh5wKcoQF71U"
    }

This key would have the following fingerprint:

    QPRGVPJNWDXH4ESK2RYDTZJLTE

We now need to create a "profile JWS" that contains the profile data and a "request JWS" to upload the profile JWS to an ASPE-compatible server.

Profile JWS header:

    {
        "typ": "JWT",
        "kid": "QPRGVPJNWDXH4ESK2RYDTZJLTE",
        "jwk": {
            "kty": "OKP",
            "use": "sig",
            "crv": "Ed25519",
            "x": "__poSQwNedopfLKP3ZgM6FXz9LIJszDZh5wKcoQF71U"
        },
        "alg": "EdDSA"
    }

Profile JWS payload:

    {
        "http://ariadne.id/version": 0,
        "http://ariadne.id/type": "profile",
        "http://ariadne.id/name": "test",
        "http://ariadne.id/claims": [
            "https://domain.tld/user/test",
            "https://another.tld/test"
        ]
    }

Compact-serialized profile JWS:

eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicHJvZmlsZSIsImh0dHA6Ly9hcmlhZG5lLmlkL25hbWUiOiJ0ZXN0IiwiaHR0cDovL2FyaWFkbmUuaWQvY2xhaW1zIjpbImh0dHBzOi8vZG9tYWluLnRsZC91c2VyL3Rlc3QiLCJodHRwczovL2Fub3RoZXIudGxkL3Rlc3QiXX0.yiBJbaB2oyprfRzYcmP-iz3C-5PGwV1Yc5iDSLW_2JFKVPKH3BKL2mUHE62VvyH1EiXDfWjpGae7jT1bM8PSAQ

Request JWS header:

    {
        "typ": "JWT",
        "kid": "QPRGVPJNWDXH4ESK2RYDTZJLTE",
        "jwk": {
            "kty": "OKP",
            "use": "sig",
            "crv": "Ed25519",
            "x": "__poSQwNedopfLKP3ZgM6FXz9LIJszDZh5wKcoQF71U"
        },
        "alg": "EdDSA"
    }

Request JWS payload:

    {
        "http://ariadne.id/version": 0,
        "http://ariadne.id/type": "request",
        "http://ariadne.id/action": "create",
        "iat": 1688371823,
        "http://ariadne.id/profile_jws": "eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicHJvZmlsZSIsImh0dHA6Ly9hcmlhZG5lLmlkL25hbWUiOiJ0ZXN0IiwiaHR0cDovL2FyaWFkbmUuaWQvY2xhaW1zIjpbImh0dHBzOi8vZG9tYWluLnRsZC91c2VyL3Rlc3QiLCJodHRwczovL2Fub3RoZXIudGxkL3Rlc3QiXX0.yiBJbaB2oyprfRzYcmP-iz3C-5PGwV1Yc5iDSLW_2JFKVPKH3BKL2mUHE62VvyH1EiXDfWjpGae7jT1bM8PSAQ"
    }

Compact-serialized request JWS:

eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicmVxdWVzdCIsImh0dHA6Ly9hcmlhZG5lLmlkL2FjdGlvbiI6ImNyZWF0ZSIsImlhdCI6MTY4ODM3MTgyMywiaHR0cDovL2FyaWFkbmUuaWQvcHJvZmlsZV9qd3MiOiJleUowZVhBaU9pSktWMVFpTENKcmFXUWlPaUpSVUZKSFZsQktUbGRFV0VnMFJWTkxNbEpaUkZSYVNreFVSU0lzSW1wM2F5STZleUpyZEhraU9pSlBTMUFpTENKMWMyVWlPaUp6YVdjaUxDSmpjbllpT2lKRlpESTFOVEU1SWl3aWVDSTZJbDlmY0c5VFVYZE9aV1J2Y0daTVMxQXpXbWROTmtaWWVqbE1TVXB6ZWtSYWFEVjNTMk52VVVZM01WVWlmU3dpWVd4bklqb2lSV1JFVTBFaWZRLmV5Sm9kSFJ3T2k4dllYSnBZV1J1WlM1cFpDOTJaWEp6YVc5dUlqb3dMQ0pvZEhSd09pOHZZWEpwWVdSdVpTNXBaQzkwZVhCbElqb2ljSEp2Wm1sc1pTSXNJbWgwZEhBNkx5OWhjbWxoWkc1bExtbGtMMjVoYldVaU9pSjBaWE4wSWl3aWFIUjBjRG92TDJGeWFXRmtibVV1YVdRdlkyeGhhVzF6SWpwYkltaDBkSEJ6T2k4dlpHOXRZV2x1TG5Sc1pDOTFjMlZ5TDNSbGMzUWlMQ0pvZEhSd2N6b3ZMMkZ1YjNSb1pYSXVkR3hrTDNSbGMzUWlYWDAueWlCSmJhQjJveXByZlJ6WWNtUC1pejNDLTVQR3dWMVljNWlEU0xXXzJKRktWUEtIM0JLTDJtVUhFNjJWdnlIMUVpWERmV2pwR2FlN2pUMWJNOFBTQVEifQ.T2BF__Ph7SsM9n9ZsyB9-_nuvJbYZW9OPE1xp18k5rAdyQG36_muuDt-HeQE4gtDhIk6kBEOpaSenH5teXd_Dw

A.2. Updating a profile

Assuming we are using the same Ed25519 key as in A.1.

We now need to create an updated "profile JWS" that contains the profile data and a "request JWS" to upload the profile JWS to an ASPE-compatible server.

Profile JWS header:

    {
        "typ": "JWT",
        "kid": "QPRGVPJNWDXH4ESK2RYDTZJLTE",
        "jwk": {
            "kty": "OKP",
            "use": "sig",
            "crv": "Ed25519",
            "x": "__poSQwNedopfLKP3ZgM6FXz9LIJszDZh5wKcoQF71U"
        },
        "alg": "EdDSA"
    }

Profile JWS payload:

    {
        "http://ariadne.id/version": 0,
        "http://ariadne.id/type": "profile",
        "http://ariadne.id/name": "test",
        "http://ariadne.id/claims": [
            "https://domain.tld/user/test",
            "https://another.tld/test"
        ]
    }

Compact-serialized profile JWS:

eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicHJvZmlsZSIsImh0dHA6Ly9hcmlhZG5lLmlkL25hbWUiOiJ0ZXN0IiwiaHR0cDovL2FyaWFkbmUuaWQvY2xhaW1zIjpbImh0dHBzOi8vZG9tYWluLnRsZC91c2VyL3Rlc3QiLCJodHRwczovL2Fub3RoZXIudGxkL3Rlc3QiXX0.yiBJbaB2oyprfRzYcmP-iz3C-5PGwV1Yc5iDSLW_2JFKVPKH3BKL2mUHE62VvyH1EiXDfWjpGae7jT1bM8PSAQ

Request JWS header:

    {
        "typ": "JWT",
        "kid": "QPRGVPJNWDXH4ESK2RYDTZJLTE",
        "jwk": {
            "kty": "OKP",
            "use": "sig",
            "crv": "Ed25519",
            "x": "__poSQwNedopfLKP3ZgM6FXz9LIJszDZh5wKcoQF71U"
        },
        "alg": "EdDSA"
    }

Request JWS payload:

    {
        "http://ariadne.id/version": 0,
        "http://ariadne.id/type": "request",
        "http://ariadne.id/action": "update",
        "iat": 1688371835,
        "http://ariadne.id/profile_jws": "eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicHJvZmlsZSIsImh0dHA6Ly9hcmlhZG5lLmlkL25hbWUiOiJ0ZXN0IiwiaHR0cDovL2FyaWFkbmUuaWQvY2xhaW1zIjpbImh0dHBzOi8vZG9tYWluLnRsZC91c2VyL3Rlc3QiLCJodHRwczovL2Fub3RoZXIudGxkL3Rlc3QiXX0.yiBJbaB2oyprfRzYcmP-iz3C-5PGwV1Yc5iDSLW_2JFKVPKH3BKL2mUHE62VvyH1EiXDfWjpGae7jT1bM8PSAQ"
    }

Compact-serialized request JWS:

eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicmVxdWVzdCIsImh0dHA6Ly9hcmlhZG5lLmlkL2FjdGlvbiI6InVwZGF0ZSIsImlhdCI6MTY4ODM3MTgzNSwiaHR0cDovL2FyaWFkbmUuaWQvcHJvZmlsZV9qd3MiOiJleUowZVhBaU9pSktWMVFpTENKcmFXUWlPaUpSVUZKSFZsQktUbGRFV0VnMFJWTkxNbEpaUkZSYVNreFVSU0lzSW1wM2F5STZleUpyZEhraU9pSlBTMUFpTENKMWMyVWlPaUp6YVdjaUxDSmpjbllpT2lKRlpESTFOVEU1SWl3aWVDSTZJbDlmY0c5VFVYZE9aV1J2Y0daTVMxQXpXbWROTmtaWWVqbE1TVXB6ZWtSYWFEVjNTMk52VVVZM01WVWlmU3dpWVd4bklqb2lSV1JFVTBFaWZRLmV5Sm9kSFJ3T2k4dllYSnBZV1J1WlM1cFpDOTJaWEp6YVc5dUlqb3dMQ0pvZEhSd09pOHZZWEpwWVdSdVpTNXBaQzkwZVhCbElqb2ljSEp2Wm1sc1pTSXNJbWgwZEhBNkx5OWhjbWxoWkc1bExtbGtMMjVoYldVaU9pSjBaWE4wSWl3aWFIUjBjRG92TDJGeWFXRmtibVV1YVdRdlkyeGhhVzF6SWpwYkltaDBkSEJ6T2k4dlpHOXRZV2x1TG5Sc1pDOTFjMlZ5TDNSbGMzUWlMQ0pvZEhSd2N6b3ZMMkZ1YjNSb1pYSXVkR3hrTDNSbGMzUWlYWDAueWlCSmJhQjJveXByZlJ6WWNtUC1pejNDLTVQR3dWMVljNWlEU0xXXzJKRktWUEtIM0JLTDJtVUhFNjJWdnlIMUVpWERmV2pwR2FlN2pUMWJNOFBTQVEifQ.Ad3gfo6CA1d5YZPtKvbZrCDXgTxiMOYkUPasWpu6HfNLMZ1eZdVDIP1t6uikG0BcI3KTSaQOgLSU-2kCpiyZDA

A.3. Deleting a profile

Assuming we are using the same Ed25519 key as in A.1.

We now need to create a "request JWS" to tell the ASPE-compatible server to delete the profile. We do not need to create a "profile JWS".

Request JWS header:

    {
        "typ": "JWT",
        "kid": "QPRGVPJNWDXH4ESK2RYDTZJLTE",
        "jwk": {
            "kty": "OKP",
            "use": "sig",
            "crv": "Ed25519",
            "x": "__poSQwNedopfLKP3ZgM6FXz9LIJszDZh5wKcoQF71U"
        },
        "alg": "EdDSA"
    }

Request JWS payload:

    {
        "http://ariadne.id/version": 0,
        "http://ariadne.id/type": "request",
        "http://ariadne.id/action": "delete",
        "iat": 1688371843
    }

Compact-serialized request JWS:

eyJ0eXAiOiJKV1QiLCJraWQiOiJRUFJHVlBKTldEWEg0RVNLMlJZRFRaSkxURSIsImp3ayI6eyJrdHkiOiJPS1AiLCJ1c2UiOiJzaWciLCJjcnYiOiJFZDI1NTE5IiwieCI6Il9fcG9TUXdOZWRvcGZMS1AzWmdNNkZYejlMSUpzekRaaDV3S2NvUUY3MVUifSwiYWxnIjoiRWREU0EifQ.eyJodHRwOi8vYXJpYWRuZS5pZC92ZXJzaW9uIjowLCJodHRwOi8vYXJpYWRuZS5pZC90eXBlIjoicmVxdWVzdCIsImh0dHA6Ly9hcmlhZG5lLmlkL2FjdGlvbiI6ImRlbGV0ZSIsImlhdCI6MTY4ODM3MTg0M30.TulEElcr2mYuvQbXqEYfaBhEuQ1T-eEPQyBGRc0HIwjj34Ag0w67nqdgEzhC1SeHVvkHKSvbkBhLcyp6qtRcAw