Skip to main content

The FedID Protocol

The below demonstrates the flow of creation of, and sign-in using, a FedID. The entire API structure can be found in a OpenAPI spec via Swagger at /api/v2.

swagger

Creating a FedID

Request to supported domains

First the FedID App will request the available domains to use for usernames from the FedID Server

Request:

GET /api/v2/domains

Response:

{
"success": true,
"data": {
"domains": [
"domain1.ext"
]
}
}

Creating the DID

The FedID App then generates private/public key pairs for a device control key (for managing the DID), and a pair for recovery, and delivers those to the FedID Server to create the DID.

Request:

POST /api/v2/did/create

Data:

{
"shortName": "theuser@domain1.ext",
"control": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE=",
"recoveryHash": "20b528ce3419b0731af25d0e79096937eb87cc5aa3f3361e"
}

Response:

{
"success": true,
"data": {
"didDoc": {
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"version": "2.0",
"@context": [
"https://www.w3.org/ns/did/v1",
"https://didspec.jlinc.io/v2/ctx.jsonld"
],
"verificationMethod": [
{
"id": "did:jlinc:h:device:524634f6af0a0e8fa95b3b1cc2e505c9",
"type": "device",
"controller": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"key": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}
],
"capabilityDelegation": [],
"service": [
{
"id": "did:jlinc:h:did.domain1.ext:b8fb6d540dba8e6979f9429f7f2c04f6",
"type": "login",
"serviceEndpoint": "https://fedid.domain1.ext"
}
],
"created": "2024-10-15T11:49:06Z",
"updated": "2024-10-15T11:49:06Z",
"deactivated": false,
"shortName": "theuser@domain1.ext",
"recoveryHash": "20b528ce3419b0731af25d0e79096937eb87cc5aa3f3361e"
}
}
}

Signing the DID

To prove this DID is for this user, an update call is made after signing the DID with the private control key.

Request:

POST /api/v2/did/update

Data:

{
"didDoc": {
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"version": "2.1",
"@context": [
"https://www.w3.org/ns/did/v1",
"https://didspec.jlinc.io/v2/ctx.jsonld"
],
"verificationMethod": [
{
"id": "did:jlinc:h:device:524634f6af0a0e8fa95b3b1cc2e505c9",
"type": "device",
"controller": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"key": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}
],
"capabilityDelegation": [],
"service": [
{
"id": "did:jlinc:h:did.domain1.ext:b8fb6d540dba8e6979f9429f7f2c04f6",
"type": "login",
"serviceEndpoint": "https://fedid.domain1.ext"
}
],
"created": "2024-10-15T11:49:06Z",
"updated": "2024-10-15T11:49:06Z",
"deactivated": false,
"shortName": "theuser@domain1.ext",
"recoveryHash": "20b528ce3419b0731af25d0e79096937eb87cc5aa3f3361e"
},
"publicKey": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE=",
"signature": "3_dINtsTUKhtFlnJia4UqPIMOTVA-_co4SZF3Aw0_AU_OqfToHXSBBvfXuC9VtBbfEx8zpSeIElwblvxmytzAw=="
}

Response:

{
"success": true,
"data": {
"version": "2.1",
"@context": [
"https://www.w3.org/ns/did/v1",
"https://didspec.jlinc.io/v2/ctx.jsonld"
],
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"shortName": "theuser@domain1.ext",
"verificationMethod": [
{
"id": "did:jlinc:h:device:524634f6af0a0e8fa95b3b1cc2e505c9",
"type": "device",
"controller": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"key": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}
],
"capabilityDelegation": [],
"service": [
{
"id": "did:jlinc:h:did.domain1.ext:b8fb6d540dba8e6979f9429f7f2c04f6",
"type": "login",
"serviceEndpoint": "https://fedid.domain1.ext"
}
],
"created": "2024-10-15T11:49:06Z",
"updated": "2024-10-15T11:49:06Z",
"deactivated": false,
"recoveryHash": "20b528ce3419b0731af25d0e79096937eb87cc5aa3f3361e",
"signature": "3_dINtsTUKhtFlnJia4UqPIMOTVA-_co4SZF3Aw0_AU_OqfToHXSBBvfXuC9VtBbfEx8zpSeIElwblvxmytzAw=="
}
}

Federating the DID

At this point, the DID is converted into an ActivityPub note object, and federated to any other conneted FedID Servers.

{
"id": "https://fedid.domain1.ext/s/eb71d8fa3bb11bd07e5cbedeeada8614e00642b0e5f35c97",
"type": "Create",
"actor": [
"https://fedid.domain1.ext/u/fedid"
],
"object": [
{
"id": "https://fedid.domain1.ext/o/06049c6e9c0a6fa4122f2361a813b038702a6fff0fe09d03",
"type": "Note",
"attributedTo": [
"https://fedid.domain1.ext/u/fedid"
],
"content": [
{
"didDoc": {
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"version": "2.1",
"@context": [
"https://www.w3.org/ns/did/v1",
"https://didspec.jlinc.io/v2/ctx.jsonld"
],
"verificationMethod": [
{
"id": "did:jlinc:h:device:524634f6af0a0e8fa95b3b1cc2e505c9",
"type": "device",
"controller": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"key": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}
],
"capabilityDelegation": [],
"service": [
{
"id": "did:jlinc:h:did.domain1.ext:b8fb6d540dba8e6979f9429f7f2c04f6",
"type": "login",
"serviceEndpoint": "https://fedid.domain1.ext"
}
],
"created": "2024-10-15T11:49:06Z",
"updated": "2024-10-15T11:49:06Z",
"deactivated": false,
"shortName": "theuser@domain1.ext",
"recoveryHash": "20b528ce3419b0731af25d0e79096937eb87cc5aa3f3361e",
"signature": "3_dINtsTUKhtFlnJia4UqPIMOTVA-_co4SZF3Aw0_AU_OqfToHXSBBvfXuC9VtBbfEx8zpSeIElwblvxmytzAw=="
},
"publicKey": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}
],
"to": [
"https://fedid.domain2.ext/u/fedid"
]
}
],
"published": [
"2024-10-15T11:49:06.547Z"
],
"to": [
"https://fedid.domain2.ext/u/fedid"
],
"shares": {
"id": "https://fedid.domain1.ext/s/eb71d8fa3bb11bd07e5cbedeeada8614e00642b0e5f35c97/shares",
"type": "OrderedCollection",
"first": [
"https://fedid.domain1.ext/s/eb71d8fa3bb11bd07e5cbedeeada8614e00642b0e5f35c97/shares?page=true"
],
"totalItems": [
0
]
},
"likes": {
"id": "https://fedid.domain1.ext/s/eb71d8fa3bb11bd07e5cbedeeada8614e00642b0e5f35c97/likes",
"type": "OrderedCollection",
"first": [
"https://fedid.domain1.ext/s/eb71d8fa3bb11bd07e5cbedeeada8614e00642b0e5f35c97/likes?page=true"
],
"totalItems": [
0
]
}
}

Creating the OIDC Profile

Profile data is stored on the FedID Server.

Requesting the challenge code

To update the profile data, the FedID App requests a challenge code.

Request:

POST /api/v2/oidc/challenge

Data:

{
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55"
}

Response:

{
"success": true,
"data": {
"challenge": "3acb1fc6a84cac727405c5d8dc919fc699de1a72f475d8e37df690d0a2cb3149"
}
}

Signing the challenge code

The FedID App then signs the challenge to prove it is the user a retrieve the existing profile. As a profile does not yet exist, a false success is returned.

Request:

POST /api/v2/oidc/profile

Data:

{
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"challenge": "3acb1fc6a84cac727405c5d8dc919fc699de1a72f475d8e37df690d0a2cb3149",
"signature": "fyD3_r-t8wL1nnnarAI_ogY61zfixTLIP971oiwZNJPUgDz9SQXUlCjxOLq8GqIk2WHFLeRmTec1ANzj6KScCQ==",
"publicKey": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}

Response:

{
"success": false,
"error": "no profile data from get profile",
"status": 404
}

Creating the profile

The profile is then created, signed, and delivered to the FedID Server. This profile data is not federated on the network.

Request:

POST /api/v2/oidc/profile

Data:

{
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"profile": {
"email": "theuser@domain.ext",
"addressCountry": "",
"addressLocality": "",
"addressPostalCode": "",
"addressRegion": "",
"addressStreetAddress": "",
"addressFormatted": "",
"birthdate": "",
"gender": "",
"givenName": "",
"middleName": "",
"familyName": "",
"nickName": "",
"phoneNumber": "",
"profile": "",
"website": "",
"zoneinfo": "",
"locale": "",
"picture": ""
},
"signature": "_0sqzliODuxDLxaDT0wEXnD9h1rFtfSi_T2xeVIiEfOvKgjUwZyl8TJRpa7KFyAFz26HX28rCRXjWEWwp-AXDg==",
"publicKey": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE="
}

Response:

{
"success": true,
"status": 200,
"data": {
"profile": {
"email": "theuser@domain.ext",
"emailVerified": false,
"addressCountry": "",
"addressLocality": "",
"addressPostalCode": "",
"addressRegion": "",
"addressStreetAddress": "",
"addressFormatted": "",
"birthdate": "",
"gender": "",
"givenName": "",
"middleName": "",
"familyName": "",
"nickName": null,
"phoneNumber": "",
"phoneNumberVerified": false,
"profile": "",
"website": "",
"zoneinfo": null,
"locale": null,
"picture": "",
"createdTs": "2024-10-15T11:49:44.297Z",
"updatedTs": "2024-10-15T11:49:44.297Z"
}
}
}

Signing in with a FedID

FIDC request

An application makes an FIDC request to the FedID Server using any standard OIDC library. This moves them into the FIDC interaction, just like it would for OIDC.

Displaying the QR code

Instead of a standard username/password SSO screen for OIDC, FIDC supplies the interaction ID and a challenge code in a QR code format that can be scanned by the FedID App. It then makes repeated calls to the check login endpoint until the code is successfully scanned.

Request:

POST /api/v2/oidc/check-login

Data:

{
"uid": "sGymWd2dpK2oaLNRK3E5J",
"challenge": "c963865b54244fec0d0e72efc071612387728d290f4110aa6dcdfe3d42819001"
}

Response:

{
"success": false,
"error": "challenge not validated"
}

Scanning the QR code

Once the QR code is scanned by the FedID App, the signature is sent to the FedID Server.

Request:

POST /api/v2/oidc/login

Data:

{
"id": "did:jlinc:h:did.domain1.ext:cf1fd4e244c4593d78e711b4cff22b55",
"uid": "sGymWd2dpK2oaLNRK3E5J",
"publicKey": "j6RHrlucLa7DnOrabIAe_Ec0QjgQ9oMQbGURJhAyJyE=",
"challenge": "c963865b54244fec0d0e72efc071612387728d290f4110aa6dcdfe3d42819001",
"signature": "qQs+0KX/ODwUHN6h+UyvX6i1xU1WFG8PIwkGWNjsaBxffAVQpQr6dKWBi5UJy6KxVbGYcZFQBpVRYbF6P10gDQ=="
}

Response:

{
"success": true
}

Successful login

At this point, a success for the check login endpoint is returned, which moves the user on to the FIDC confirmation screen displaying the profile data that will be shared with the OIDC capable site.

Request:

POST /api/v2/oidc/check-login

Data:

{
"uid": "sGymWd2dpK2oaLNRK3E5J",
"challenge": "c963865b54244fec0d0e72efc071612387728d290f4110aa6dcdfe3d42819001"
}

Response:

{
"success": true
}

Finalizing the FIDC interaction

Once the user confirms sharing of the select profile data, the FIDC interaction is finalized, and the user is logged into the supporting site.