RFC 10050

Protocol-Specific Profiles for JSContact

๐Ÿ“… published September 2026, from ietf

RFC 10050: Protocol-Specific Profiles for JSContact ๐ŸŽ€

Okay bestie, let's do the title block first ๐ŸŽ€. RFC 10050 is called Protocol-Specific Profiles for JSContact, written by R. Stepanek at Fastmail and M. Loffredo at IIT-CNR ๐Ÿ‘‘. It's on the Standards Track, dated September 2026, and filed under ISSN 2070-1721 ๐Ÿ“…. The title block doesn't list any documents it obsoletes or updates, so there's nothing to replace or patch here โœจ. (part 1 of 3, more coming!)


Abstract ๐ŸŒธ

This doc defines the "JSContact Profiles" registry ๐Ÿ“‹, an IANA registry for named subsets of JSContact elements. The goal is to make it easier to use JSContact in contact data exchange protocols, or in other use cases where supporting every single JSContact semantic might be inappropriate ๐Ÿ’….

Status of This Memo ๐Ÿ“œ

This is an Internet Standards Track document ๐ŸŒˆ.

So this doc is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community ๐Ÿซถ. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). If you want more on Internet Standards, check Section 2 of RFC 7841 ๐Ÿ“š.

Want the current status, any errata, or a way to send feedback? Those live at https://www.rfc-editor.org/info/rfc10050 ๐Ÿ”—.

Copyright (c) 2026 IETF Trust and the people listed as the document authors ๐Ÿซถ. All rights reserved ๐Ÿ’œ.

This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info), as they're in effect on the date this doc was published ๐Ÿ“œ. Please read those carefully, because they spell out your rights and restrictions for this doc ๐Ÿ‘€. Code Components pulled out of this doc must include Revised BSD License text, as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Revised BSD License ๐ŸŒธ.

Table of Contents ๐Ÿ—‚๏ธ

   1.  Introduction
   2.  Notational Conventions
   3.  JSContact Profiles
     3.1.  Profile Name
     3.2.  Profile Version
     3.3.  Profile Properties
     3.4.  Supported Properties
   4.  IANA Considerations
   5.  Security Considerations
   6.  References
     6.1.  Normative References
     6.2.  Informative References
   Appendix A.  Example Profile
     A.1.  Profile Properties Example
     A.2.  Card Object Example
     A.3.  IANA Registry Example
     A.4.  Supported Properties Example
   Authors' Addresses

1. Introduction โœจ

Okay so the JSContact [RFC9553] contact card data model and format is built for address book apps and directory services ๐Ÿ’œ. It's the glow-up alternative to the super common vCard [RFC6350] format โœจ. It covers vCard's core semantics and extensions, and it has a seriously rich model for personal names, postal addresses, and localization ๐ŸŒ. Every JSContact element is useful for some contact card use case, and just like vCard, implementations are expected to support these elements when they exchange contact card info over protocols like CardDAV [RFC6352] and the JSON Meta Application Protocol (JMAP) for Contacts [RFC9610] ๐ŸŽ€.

Plot twist ๐Ÿ™ˆ: other protocols and document specs might need to exchange some contact card info, but not everything JSContact offers. Section 1.7.4 of [RFC9553] says JSContact implementations may ignore unknown JSContact elements, but that only applies to future extensions of [RFC9553]. They're still expected to implement all the elements of the core spec ๐Ÿงš. Also, JSContact's extensibility and its requirement to preserve arbitrary contact elements might not cut it for some protocols ๐Ÿ’€.

So for those situations, this doc defines a brand-new IANA registry for JSContact ๐Ÿฆ‹ that lets people register named subsets of JSContact elements. These subsets are called "JSContact profiles", and they're meant to bring these perks:

  • Protocol designers might be encouraged to use JSContact instead of inventing their own contacts format ๐Ÿ™Œ. That makes cross-protocol data exchange and migration way easier.
  • Different protocols can use the same IANA registry to say which JSContact elements they support ๐Ÿ“ฃ. That makes it easy to spot what they have in common and to reuse profiles that already exist ๐Ÿงฉ.
  • One central registry gives JSContact library implementors a consistent format that documents which profile supports which elements ๐Ÿ“š. No more digging through Internet-Drafts that might all be organized totally differently ๐Ÿ˜ญ.

Here's the layout ๐Ÿ—บ๏ธ: Section 3 defines JSContact profiles, Section 4 talks about the new "JSContact Profiles" registry IANA creates, and Appendix A shows JSContact profiles with an example ๐ŸŒธ.

2. Notational Conventions ๐Ÿ“

Okay, so the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this doc are to be interpreted as described in BCP 14 [RFC2119] [RFC8174], but only when they're written in all capitals, just like here ๐Ÿ‘‘.

The ABNF definitions here use the notation from [RFC5234] ๐Ÿงฎ. ABNF rules that aren't defined in this doc are defined in [RFC5234] too, like the ABNF for DIGIT.

3. JSContact Profiles ๐ŸŒŸ

A JSContact profile is a named, versioned set of JSContact elements, like properties, types, and values ๐Ÿ’–. The JSContact elements MUST be registered in the IANA "JSContact" registry group [IANA.jscontact]. A profile MAY add extra restrictions for these elements, as outlined in Section 3.3, but a profile MUST NOT loosen restrictions ๐Ÿ™…. This doc creates an IANA registry for JSContact profiles (see Section 4) ๐Ÿ“‹.

A JSContact object complies with a profile if all of its properties are in the set that profile defines, and its property values follow that profile's restrictions for each property โœ…. A JSContact object MAY comply with multiple profiles. So this doc doesn't specify any way for JSContact data to say which profiles it complies with ๐Ÿคท. For example, it doesn't define a "profile" property for the Card object.

Every property and value in a JSContact object that complies with a profile MUST also be valid (Section 1.7 of [RFC9553]) ๐Ÿซถ. How you handle JSContact data that's valid but doesn't comply with the expected profile is protocol-specific ๐Ÿค. This doc deliberately does not define such non-compliant data as invalid. Profile designers decide their own strategies for handling non-compliant data, and one of those could be rejecting it as invalid ๐Ÿšซ. JSContact data that complies with a profile might still not be valid in the context of that protocol, and the protocol specification MAY define additional restrictions that a profile can't express ๐Ÿงฉ.

Quick map ๐Ÿ—บ๏ธ: Section 3.1 covers naming a JSContact profile, Section 3.2 covers versioning it, Section 3.3 covers specifying the properties a profile supports, and Section 3.4 explains how to figure out the supported properties ๐Ÿ’œ.

3.1. Profile Name ๐Ÿท๏ธ

Every JSContact profile gets a unique name ๐Ÿชช. The name MUST only contain ASCII lowercase alphabetic and numeric characters, and it can optionally have hyphens between them ๐Ÿ”ค. It MUST start with an alphabetic character, and it MUST be at least 1 character and at most 255 characters in size ๐Ÿ“. Formally, it MUST be a valid "profile-name" as defined in Figure 1 ๐ŸŽ€.

profile-name = lalpha *( ["-"] lalpha / DIGIT )
               ; at most 255 characters in size

lalpha       = %x61-7A ; a-z

Figure 1: ABNF Rule for JSContact Profile Name

3.2. Profile Version ๐Ÿ”ข

Each JSContact profile has a current version, and every profile is versioned on its own ๐Ÿ”ข. The version MUST be a positive integer, and it MUST increase whenever the profile properties (see Section 3.3) change โฌ†๏ธ. The initial version value is 1 ๐ŸŒฑ.

3.3. Profile Properties ๐ŸŽ€

okay so a profile is basically a list of property entries, and together those entries decide which properties the profile supports (more on that in Section 3.4). the list MUST NOT be empty ๐Ÿ™…โ€โ™€๏ธ no empty guest lists, bestie!

Each property entry has these elements:

  • Property Name: This is the name of the JSContact property this entry is about. It MUST be a property name registered in the "JSContact Properties" registry. A property name MAY show up more than once in the property entry list if the profile-specific restrictions for that property can't be squeezed into one entry, but those multiple entries MUST NOT end up with conflicting restrictions for the same property. This field MUST NOT be empty. ๐Ÿ’–
  • Property Context: This is a comma-separated list of JSContact object types that support this property in this profile. Each of these types MUST also be listed in the Property Contexts for this property in the "JSContact Properties" registry, but a profile MAY only support the property in a subset of these contexts. This field MUST NOT be empty. ๐ŸŒธ
  • Restricted Attributes: This restricts the attributes of the property. This spec only defines how to restrict the attributes so a property becomes mandatory in the listed Property Contexts, even though the property was originally optional in those same contexts. The verbatim value mandatory (no quotes) means it's mandatory in this profile. No value at all means the profile doesn't restrict the attributes from the original definition. ๐Ÿฆ‹
  • Restricted Property Type: This restricts the property value type in the listed Property Contexts. It lets a profile pin the allowed types to the original type definition, so future JSContact changes can't extend the allowed types for this profile. It also lets a profile narrow the allowed types down to a subset of the original type definition. No value means the profile doesn't restrict the value type of the original definition or any future extensions of the value type. ๐Ÿ”ฅ

If set, the restricted value type MUST exactly match the original definition at the time the profile is defined, or the original value type MUST contain some type signature in the form A|B and the restricted value type MUST resemble the original, except that some of the original A|B forms now only allow a subset of the original choices. Restricted property types MUST NOT redefine the "defaultType" attribute (Section 1.3.3 of [RFC9553]). The rules about when to set the "@type" property (Section 1.3.4 of [RFC9553]) of the original type definition still apply. โœจ

As an example of restricting the type definition to prevent future type extensions in the profile, one might restrict the type definition of the "addresses" property of the Card object to Id[Address], which matches the original definition as of this writing. ๐Ÿก

As an example of restricting the type to a subset of the original value, one might want to restrict the "date" property of the Anniversary object to only allow partial dates as values. To do so, the original value type PartialDate|Timestamp can be restricted to PartialDate. Note that the original value type need not be exactly in the form A|B. For example, the type signature Id[A|B|C] could be restricted to any of Id[A|B], Id[A|C], Id[B|C], Id[A], Id[B], or Id[C], and the type signature (A|B)[] could be restricted to one of A[] or B[]. ๐Ÿงš

  • Restricted Enum Values: This restricts the enumerated values defined for this property to a subset of those values. The values MUST be listed in the "JSContact Enum Values" registry for this property and context. Allowed values are separated by a comma. The absence of any value means all enumerated values are allowed. A profile MAY exclude the default enumerated value of a property, in which case all instances of the object MUST have this property set to one of the allowed values. ๐Ÿ“
  • Restricted PatchObject: This restricts the PatchObject value of this property such that each JSON Pointer key in the PatchObject MUST consist of exactly one JSON Pointer reference token (Section 3 of [RFC6901]). For example, with this restriction, the "localizations" property of the Card object can only patch properties of the Card object by replacing their values entirely. The verbatim value yes (no quotes) means this profile restricts PatchObject keys to a single token. The absence of any value means it does not restrict them. This MUST NOT be set to yes if the property value type is not a PatchObject. ๐Ÿ’œ

All profiles MUST support "@type" and "version", therefore profiles MUST NOT include entries for these properties. no sneaking them in, periodt! ๐Ÿ™ˆ

3.4. Supported Properties ๐Ÿฆ‹

okay this is where it gets fun. The supported properties of a JSContact profile are decided by the profile's property entries plus the contents of the IANA "JSContact Properties" registry. We call the registry ones "IANA-registered properties" for short. The "version" property of the Card object and the "@type" property of any object type are always supported, full stop. ๐Ÿ’…

A Card object complies with the profile if all of its properties are part of the supported properties and all of its property values are valid according to the restrictions defined in the applicable property entries. A PatchObject MUST NOT patch properties that are not supported in that profile. ๐Ÿซถ

The following describes the steps to determine the supported properties:

  1. Initialize the set with all properties of the Card object for which a property entry contains "Card" in the Property Context of the profile. If no such entry exists, then initialize the set with all IANA-registered properties of the Card object.
  2. For every property in the set having either an object type as the value type or a list, map, or union of object types, add all properties for which a property entry contains those object types in the Property Context of the profile. If no such property entry exists, then add all IANA-registered properties for the object types.
  3. Repeat the previous step until all object types that are value types of properties in the set have been considered.

Appendix A.4 walks through how to determine the supported properties of the example profile in Appendix A. ๐ŸŒˆ


4. IANA Considerations ๐ŸŒธ

IANA has created a brand new "JSContact Profiles" registry inside the "JSContact" registry group, so profiles for JSContact data finally have a home ๐Ÿก. The purpose of this registry is to register profiles for JSContact data. Adding an entry is "Specification Required" [RFC8126], and that covers defining a new profile name or version. Updating an existing profile is "Expert Review", and that covers updating the references of an entry. The change controller is the IETF.

An entry in this registry has the following fields, and all of them MUST be set:

  • Name: This is the name of the profile. This field is immutable after creation. The name MUST be unique among all registered profiles and MUST comply with the definitions in Section 3.1. ๐Ÿ’–
  • Version: This is the version number of the profile. This field is immutable after creation. It MUST comply with the definitions in Section 3.2. ๐ŸŽ€
  • Reference: This refers to the specification of the protocol or use case that this profile applies to. The reference MUST include the section number or section name that defines or updates the property entries for this profile, as defined in Section 3.3. โญ

Designated experts assert that all proposed assignments are valid according to the definitions in this document. For example, they check that:

  • the profile name is unique,
  • the entries in the profile entries are syntactically valid,
  • only known property names are referred to,
  • type restrictions do not incorrectly alter the type of a property, and
  • the version number increases.

On the other hand, designated experts do not decide the contents of the profile as long as the assignments are valid. they're the bouncers, not the stylists ๐Ÿ’…

The decision whether to register a new profile name or a new version for an existing profile depends on the scope of the proposed profile. A new profile name is recommended if the profile is introduced in the context of an application or protocol for which no JSContact profile is already registered, or if the proposed profile properties or restrictions substantially differ from existing profiles for that context. A new version is recommended if the profile context does not change and multiple implementations of the current profile will also support the new version. The profile version of the new entry for an already-registered profile by that name has to be higher than the last registered version for that profile. Existing registry entries are preserved. ๐Ÿฆ‹

This document does not define any initial contents for the "JSContact Profiles" registry. blank slate, bestie! โœจ


5. Security Considerations ๐Ÿ”’

This document does not provide any new security considerations. The security considerations in Section 4 of [RFC9553] apply. Nothing new to panic about, but please go read that section, it's not optional ๐Ÿ˜ญ


6. References ๐Ÿ“š

6.1. Normative References

6.2. Informative References

Appendix A. Example Profile ๐ŸŽ€

okay bestie, this appendix is my absolute fave because it's a whole example profile that shows how a JSContact Card actually behaves inside one โœจ it's giving tour guide energy ๐Ÿ’…

The profile is super picky about what it allows. It's like a bouncer with a very specific guest list ๐Ÿงš Contact cards using this profile can only contain:

  • Contact cards for individuals and organizations, but no other kinds such as groups or devices. ๐ŸŒธ
  • Full postal address lines, but no address components or any other property of the Address object type. The value type of the "addresses" property is pinned to its original definition, so that future JSContact extensions of that type do not become part of the profile. ๐Ÿก
  • Full names and name components, but no other properties of the Name object type. ๐Ÿซถ
  • Email addresses, where all properties of the EmailAddress object are supported. ๐Ÿ’Œ
  • Anniversaries for birthdays, and only having "date" property values of type PartialDate, not Timestamp. ๐ŸŽ‚
  • Localizations, with the restriction that the PatchObject must only patch properties of the Card object. ๐ŸŒˆ

An example of JSContact data that complies with this profile is shown in Appendix A.2. An example of its fictive IANA registration is shown in Appendix A.3. This profile is just for illustration, so it is not registered with IANA. Appendix A.4 walks through how to figure out the supported properties for that profile ๐Ÿฆ‹


A.1. Profile Properties Example ๐Ÿ’–

these entries define the properties of that profile. entry elements with empty values are omitted, so they don't show up here ๐Ÿ™ˆ

Property Name:  addresses
Property Context:  Card
Restricted Property Type:  Id[Address]

Property Name:  anniversaries
Property Context:  Card

Property Name:  emails
Property Context:  Card

Property Name:  kind
Property Context:  Card
Restricted Enum Values:  individual,org

Property Name:  localizations
Property Context:  Card
Restricted PatchObject:  yes

Property Name:  name
Property Context:  Card

Property Name:  full
Property Context:  Address
Restricted Attributes:  mandatory

Property Name:  date
Property Context:  Anniversary
Restricted Property Type:  PartialDate

Property Name:  kind
Property Context:  Anniversary
Restricted Enum Values:  birth

Property Name:  components
Property Context:  Name

Property Name:  full
Property Context:  Name

Property Name:  kind
Property Context:  NameComponent

Property Name:  value
Property Context:  NameComponent

A.2. Card Object Example ๐Ÿ“

here's a Card object that totally complies with the example profile. it's giving main character ๐Ÿ‘‘

{
  "@type": "Card",
  "version": "1.0",
  "name": {
     "components": [
      { "kind": "given", "value": "Hayao" },
      { "kind": "surname", "value": "Miyazaki" }
    ]
  },
  "addresses": {
    "a1": {
      "full": "71 Cherry Court, Somewhere, 123SO, UK"
    }
  },
  "emails": {
    "e1": {
      "address": "hayao@example.com"
    }
  },
  "anniversaries": {
    "a1": {
      "kind": "birth",
      "date": {
        "month": 3,
        "day": 4
      }
    }
  },
  "localizations": {
    "jp": {
      "name": {
        "components": [
         { "kind": "surname", "value": "ๅฎฎๅดŽ" },
         { "kind": "given", "value": "้งฟ" }
        ]
      }
    }
  }
}

ok so here's what's going on, periodt:

  • The Address, Card, Name, and NameComponent object values only contain properties for which a property entry exists in the profile. ๐Ÿซง
  • The EmailAddress object contains the "address" property. This is allowed because the profile contains a property entry for the "emails" property of the Card object, but it does not define entries for the EmailAddress object properties. Consequently, all properties of the EmailAddress object can be set. ๐Ÿ’Œ
  • The "full" property of the Address object is set. It is the only property allowed to be set in that profile for Address, and the "full" property is mandatory for this profile. ๐Ÿก
  • The "kind" property of the NameComponent object is set to "surname" and "given". Since the profile does not restrict the enumerated values of this property, all valid NameComponent "kind" property values are supported. ๐ŸŒท
  • The "kind" property of the Card object is not set. The profile restricts the enumerated values of this property to "individual" and "org". Since "individual" is the default value for this property, there is no need to set it. ๐Ÿ™ˆ
  • The "date" property of the Anniversary object is restricted to be of type PartialDate in this profile. Because PartialDate is the default type for this property, there is no need to set the "@type" property of the PartialDate object. ๐ŸŽ‚

A.3. IANA Registry Example ๐Ÿ“œ

the following would be registered at IANA if this were a real profile:

Name:  jscontact-simple-example

Version:  1

Reference:  This document, Appendix A.1

see Section 4 for the definition of each registry item ๐Ÿฆ‹


A.4. Supported Properties Example ๐Ÿงš

this part shows how to figure out the supported properties of the example profile in this appendix, following the steps defined in Section 3.4. it's a whole detective arc and I'm obsessed ๐Ÿ•ต๏ธโ€โ™€๏ธโœจ

  1. ok first, we start the set of supported properties with all profile properties where the Property Context includes the Card object. the set now has:
    • Card.addresses
    • Card.anniversaries
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name
  2. next, we check which properties in the current set have an object type as their value type. those are Card.addresses, Card.anniversaries, Card.emails, and Card.name, so we need to inspect the object types Address, Anniversary, EmailAddress, and Name. the "addresses" entry restricts the value type of that property to "Id[Address]", which matches its original definition. but any future type extension would still only require us to inspect the Address type ๐Ÿซถ
  3. for the Address object type, the profile has an entry for the "full" property, which has the Address object in the Property Context, so we add that and only that to the set of supported properties. it now contains:
    • Address.full
    • Card.addresses
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name

the value type of the Address.full property is not an object type, so we don't need to consider a new object type to inspect. the remaining object types to inspect are the Anniversary, EmailAddress, and Name objects ๐Ÿ’–

  1. for the Anniversary object type, the profile explicitly lists the "kind" and "date" properties, so we add them to the set of supported properties. it now contains:
    • Address.full
    • Anniversary.date
    • Anniversary.kind
    • Card.addresses
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name

the newly added Anniversary.date property has the object value type PartialDate, so we add that to the list of object types to inspect. the entry restricts the type of that property to only be of that type, so we do not add the object value type Timestamp. the remaining object types to inspect are the EmailAddress, Name, and PartialDate objects ๐ŸŽ‚

  1. for the PartialDate object type, the profile does not contain any entry where the Property Context contains the PartialDate object. instead, we add properties from the "JSContact Properties" registry where the Property Context includes the PartialDate object. the set of supported properties now contains:
    • Address.full
    • Anniversary.date
    • Anniversary.kind
    • Card.addresses
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name
    • PartialDate.calendarScale
    • PartialDate.day
    • PartialDate.month
    • PartialDate.year

none of the newly added properties have object value types. the remaining object types to inspect are the EmailAddress and Name objects ๐ŸŒˆ

  1. for the EmailAddress object type, the profile does not contain any entry where the Property Context contains the EmailAddress object. instead, we add properties from the "JSContact Properties" registry where the Property Context includes the EmailAddress object. the set of supported properties now contains:
    • Address.full
    • Anniversary.date
    • Anniversary.kind
    • Card.addresses
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name
    • EmailAddress.address
    • EmailAddress.contexts
    • EmailAddress.label
    • EmailAddress.pref
    • PartialDate.calendarScale
    • PartialDate.day
    • PartialDate.month
    • PartialDate.year

none of the newly added properties have object value types. the remaining object type to inspect is the Name object ๐Ÿ’Œ

  1. for the Name object type, the profile explicitly lists the "components" and "full" properties, so we add them to the set of supported properties. it now contains:
    • Address.full
    • Anniversary.date
    • Anniversary.kind
    • Card.addresses
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name
    • EmailAddress.address
    • EmailAddress.contexts
    • EmailAddress.label
    • EmailAddress.pref
    • Name.full
    • Name.components
    • PartialDate.calendarScale
    • PartialDate.day
    • PartialDate.month
    • PartialDate.year

the newly added Name.components property has the object value type NameComponent, so we add that to the list of object types to inspect ๐Ÿซง

  1. for the NameComponent object type, the profile doesn't explicitly list any property. instead, we add properties of the "JSContact Properties" registry where the Property Context includes the NameComponent object. the set of supported properties now contains:
    • Address.full
    • Anniversary.date
    • Anniversary.kind
    • Card.addresses
    • Card.emails
    • Card.kind
    • Card.localizations
    • Card.name
    • EmailAddress.address
    • EmailAddress.contexts
    • EmailAddress.label
    • EmailAddress.pref
    • NameComponent.kind
    • NameComponent.phonetic
    • NameComponent.value
    • PartialDate.calendarScale
    • PartialDate.day
    • PartialDate.month
    • PartialDate.year

none of the newly added properties have object value types, and there are no remaining object types to inspect. this determines the set of supported properties for that profile, in addition to the "Card.version" and "@type" properties, which are always supported ๐ŸŽ‰๐Ÿ‘‘


Authors' Addresses ๐Ÿซถ

Robert Stepanek
Fastmail
PO Box 234
Collins St. West
Melbourne VIC 8007
Australia
Email: rsto@fastmailteam.com
Mario Loffredo
IIT-CNR
Via Moruzzi, 1
56124 Pisa
Italy
Email: mario.loffredo@iit.cnr.it
๐Ÿ“ฆ where this page comes from