Getting the Login Result from SIWF
After the user completes the authentication and authorization, the user is redirected to the callback URL with one additional parameter set: authorizationCode
.
The authorizationCode
can be used to retrieve the result of the login.
Note: The following instruction examples are based on Frequency Access.
Quick Reference
- Staging-Testnet:
https://testnet.frequencyaccess.com/siwa/api/payload
- Production-Mainnet:
https://www.frequencyaccess.com/siwa/api/payload
- Response Structure:
SiwfResponse
Step 1: Retrieve the Response
GET
:- Staging-Testnet:
https://testnet.frequencyaccess.com/siwa/api/payload?authorizationCode=[Parameter from callback URL]
- Production-Mainnet:
https://www.frequencyaccess.com/siwa/api/payload?authorizationCode=[Parameter from callback URL]
- Staging-Testnet:
Step 2: Parsing the Response
Response Sections
userPublicKey
: The key for the user signing this requestpayloads
: Signed payloads from the usercredentials
: User approved verified credentials from Frequency Access (or other SIWF-compatible services) such as email, phone, user keys, etc...
userPublicKey
The public key for the user identifies the user for this session.
If that user has a Frequency blockchain account (MSA), the MSA Id can be retrieved from Frequency using this key.
Or in the case when it does not, the payloads
section will contain the payload to create said MSA Id.
While the userPublicKey
may change, the MSA Id will always be the same for the same user account.
Step 3: Processing the Credentials
The credentials
array will contain any requested and approved credentials.
Each credential would be matched based on the type
field.
These credentials follow the DSNP Verifiable Credentials Specification.
@dsnp/verifiable-credentials
TypeScript library for verifying these DSNP Credentials specifically- Other W3C Verifiable Credentials verifiers may also be compatable.
Verify the Credential
Trust Model Note: You may choose to just trust credentials issued by Frequency Access (or other SIWF-compatible services) given that the credential is fetched directly. These will have issuer did:web:testnet.frequencyaccess.com
or did:web:frequencyaccess.com
.
- Check that the
credentialSubject.id
matches theuserPublicKey
following thedid:key
Method from the W3C
- Example:
f6cL4wq1HUNx11TcvdABNf9UNXXoyH47mVUwT59tzSFRW8yDH
is the SS58 version with prefix90
of the hex address0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
.0xef01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d
is multicodecsr25519-pub
hex which is multiformatbase58-btc
z6QNzHod3tSSJbwo4e5xGDcnsndsR9WByZzPoCGdbv3sv1jJ
- Fetch the issuer DID Document following the
did:web
Method from the W3C
- Production-Mainnet should always be
did:web:frequencyaccess.com
which resolves tohttps://frequencyaccess.com/.well-known/did.json
- Staging-Testnet should always be
did:web:testnet.frequencyaccess.com
which resolves tohttps://testnet.frequencyaccess.com/.well-known/did.json
- Check that the key in the
proof.verificationMethod
is in the DID Document to verify that the key is still valid - Test that the
proof
validates according the to W3C Verifiable Credentials Specification
Graph Encryption Key Credential
If the user has permitted access to their private social graph per the request for VerifiedGraphKeyPairCredential
, credentials
will have a entry with type
including VerifiedGraphKeyPairCredential
.
This is an x25519
key pair for use with the curve25519xsalsa20poly1305
encryption algorithm from the NaCl Library.
For more information on how the Graph data is structured after decryption, see the DSNP Specification.
This key pair is PII and should be stored with care, but must be stored to read the user's private graph.
Example Credential
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedPhoneNumberCredential",
"VerifiableCredential"
],
"issuer": "did:web:frequencyaccess.com",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedPhoneNumberCredential/bciqjspnbwpc3wjx4fewcek5daysdjpbf5xjimz5wnu5uj7e3vu2uwnq.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"phoneNumber": "+01-234-867-5309",
"lastVerified": "2024-08-21T21:27:59.309+0000"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:web:frequencyaccess.com#z6MkofWExWkUvTZeXb9TmLta5mBT6Qtj58es5Fqg1L5BCWQD",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z5sJ2CjHX1wwgzfFGoZNocxeFKd2ffpo5TVgUvdaSkYq1M6gF7UjpYfePo97QoZgmiWdgPAWPjxFvGBysaxHV8DZ4"
}
}
Step 4: Processing the Payloads
The payload section has several different types that can be returned:
login
: When the user already has a correct delegationaddProvider
*: When the user does not have a delegation (a new user signup) or when the delegation was needing to be changeditemActions
*: When the user has user chain data to set or updateclaimHandle
*: When the user needs to claim a new handle
* Requires submission to Frequency
The payloads that require submission to Frequency should be submitted in one batch using Capacity.
The addProvider
must always be first in the batch to ensure the correct permissions and delegations are in place for subsequent actions in the batch.
Signatures to Frequency have an expiration set to a future Frequency block number. If the actions are not submitted before expriation, Frequency will reject the transactions and your application will need to request new signatures.
Payload Examples and Signature Details
login
The correct delegation for the user already exists. No submission to the chain is required, but the application must validate the signature to be sure that the user is authenticated.
The message signed follows CAIP-122: Sign in With X specification which is derived from EIP-4361: Sign-In with Ethereum.
Example Message with Placeholders
{{domain}} wants you to sign in with your Frequency account:
frequency:{{chainReference}}:{{ss58Address}}
URI: {{uri}}
Version: {{version}}
Nonce: {{nonce}}
Chain ID: frequency:{{chainReference}}
Issued At: {{issued-at}}
Inside the message, {{domain}}
is the domain of the application requesting the sign-in. {{domain}}
should match the domain contained in the URI
field.
Validation Steps
- Perform an Sr25519 signature verification using:
userPublicKey
: The signing keypayload.message
: The signed message parsing\n
intoLF
line breakssignature.encodedValue
: The signature
- Verify that the
userPublicKey
matches the second line of the message for the correct chain identifier- Production-Mainnet:
frequency:mainnet:
- Staging-Testnet:
frequency:testnet-paseo:
- Production-Mainnet:
- Verify that the message starts with your domain based on RFC 4501
dnsauthority
- Verify the
Issued At
value from the message is within your acceptable time range - Verify that
Nonce
value in the message is not being reused
Parsing the Message Data
- Break the lines by
\n
- Match based on the prefix:
Nonce:
Issued At:
URI:
addProvider
The user either needs a new delegation or a new MSA created with the delegation.
The endpoint.extrinsic
field will distinguish between the two:
createSponsoredAccountWithDelegation
: New MSAgrantDelegation
: New/Updated Delegation
See Frequency Documentation on forming the transaction for the extrinsics.
itemActions
Item actions will update the user's chain data for things such as their public key for the encrypted graph. These actions must be submitted to the chain for the correct functioning of private graph and other systems.
See Frequency Documentation on forming the transaction for the extrinsics.
claimHandle
The user wishes to claim a Frequency Handle.
See Frequency Documentation on forming the transaction for the extrinsics.
Step 6: Frequency Transaction Submission
All payloads that are returned will be able to be processed using Capacity on Frequency.
Frequency submission is required for any of the following payloads:
addProvider
itemActions
claimHandle
They can be submitted to the chain in one transaction using pay_with_capacity_batch_all
.
Step 6: Session Starts
Once the payloads have been validated, the user's authenticated session may start. SIWF services do not manage user sessions.
Examples
New Frequency User Response
{
"userPublicKey": {
"encodedValue": "f6akufkq9Lex6rT8RCEDRuoZQRgo5pWiRzeo81nmKNGWGNJdJ",
"encoding": "base58",
"format": "ss58",
"type": "Sr25519"
},
"payloads": [
{
"signature": {
"algo": "SR25519",
"encoding": "base16",
"encodedValue": "0x1a27cb6d79b508e1ffc8d6ae70af78d5b3561cdc426124a06f230d7ce70e757e1947dd1bac8f9e817c30676a5fa6b06510bae1201b698b044ff0660c60f18c8a"
},
"endpoint": {
"pallet": "msa",
"extrinsic": "createSponsoredAccountWithDelegation"
},
"type": "addProvider",
"payload": {
"authorizedMsaId": 1,
"schemaIds": [
5,
7,
8,
9,
10
],
"expiration": 24
}
},
{
"signature": {
"algo": "SR25519",
"encoding": "base16",
"encodedValue": "0x9eb338773b386ded2e3731ba68ba734c80408b3ad24f92ed3c60342d374a32293851fa8e41d722c72a5a4e765a9e401c68570a8c666ab678e4e5d94aa6825d85"
},
"endpoint": {
"pallet": "statefulStorage",
"extrinsic": "applyItemActionsWithSignatureV2"
},
"type": "itemActions",
"payload": {
"schemaId": 7,
"targetHash": 0,
"expiration": 20,
"actions": [
{
"type": "addItem",
"payloadHex": "0x40eea1e39d2f154584c4b1ca8f228bb49ae5a14786ed63c90025e755f16bd58d37"
}
]
}
},
{
"signature": {
"algo": "SR25519",
"encoding": "base16",
"encodedValue": "0xb004140fd8ba3395cf5fcef49df8765d90023c293fde4eaf2e932cc24f74fc51b006c0bebcf31d85565648b4881fa22115e0051a3bdb95ab5bf7f37ac66f798f"
},
"endpoint": {
"pallet": "handles",
"extrinsic": "claimHandle"
},
"type": "claimHandle",
"payload": {
"baseHandle": "ExampleHandle",
"expiration": 24
}
}
],
"credentials": [
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedEmailAddressCredential",
"VerifiableCredential"
],
"issuer": "did:web:frequencyaccess.com",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedEmailAddressCredential/bciqe4qoczhftici4dzfvfbel7fo4h4sr5grco3oovwyk6y4ynf44tsi.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"emailAddress": "john.doe@example.com",
"lastVerified": "2024-08-21T21:27:59.309+0000"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:web:frequencyaccess.com#z6MkofWExWkUvTZeXb9TmLta5mBT6Qtj58es5Fqg1L5BCWQD",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z4jArnPwuwYxLnbBirLanpkcyBpmQwmyn5f3PdTYnxhpy48qpgvHHav6warjizjvtLMg6j3FK3BqbR2nuyT2UTSWC"
}
},
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedGraphKeyCredential",
"VerifiableCredential"
],
"issuer": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedGraphKeyCredential/bciqmdvmxd54zve5kifycgsdtoahs5ecf4hal2ts3eexkgocyc5oca2y.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"encodedPublicKeyValue": "0xb5032900293f1c9e5822fd9c120b253cb4a4dfe94c214e688e01f32db9eedf17",
"encodedPrivateKeyValue": "0xd0910c853563723253c4ed105c08614fc8aaaf1b0871375520d72251496e8d87",
"encoding": "base16",
"format": "bare",
"type": "X25519",
"keyType": "dsnp.public-key-key-agreement"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:key:z6MktZ15TNtrJCW2gDLFjtjmxEdhCadNCaDizWABYfneMqhA",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z2HHWwtWggZfvGqNUk4S5AAbDGqZRFXjpMYAsXXmEksGxTk4DnnkN3upCiL1mhgwHNLkxY3s8YqNyYnmpuvUke7jF"
}
}
]
}
New Application/Delegation Response
{
"userPublicKey": {
"encodedValue": "f6akufkq9Lex6rT8RCEDRuoZQRgo5pWiRzeo81nmKNGWGNJdJ",
"encoding": "base58",
"format": "ss58",
"type": "Sr25519"
},
"payloads": [
{
"signature": {
"algo": "SR25519",
"encoding": "base16",
"encodedValue": "0xbac399831b9e3ad464a16e62ad1252cc8344a2c52f80252b2aa450a06ae2362f6f4afcaca791a81f28eaa99080e2654bdbf1071a276213242fc153cca43cfa8e"
},
"endpoint": {
"pallet": "msa",
"extrinsic": "grantDelegation"
},
"type": "addProvider",
"payload": {
"authorizedMsaId": 1,
"schemaIds": [
5,
7,
8,
9,
10
],
"expiration": 24
}
}
],
"credentials": [
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedEmailAddressCredential",
"VerifiableCredential"
],
"issuer": "did:web:frequencyaccess.com",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedEmailAddressCredential/bciqe4qoczhftici4dzfvfbel7fo4h4sr5grco3oovwyk6y4ynf44tsi.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"emailAddress": "john.doe@example.com",
"lastVerified": "2024-08-21T21:27:59.309+0000"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:web:frequencyaccess.com#z6MkofWExWkUvTZeXb9TmLta5mBT6Qtj58es5Fqg1L5BCWQD",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z4jArnPwuwYxLnbBirLanpkcyBpmQwmyn5f3PdTYnxhpy48qpgvHHav6warjizjvtLMg6j3FK3BqbR2nuyT2UTSWC"
}
},
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedGraphKeyCredential",
"VerifiableCredential"
],
"issuer": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedGraphKeyCredential/bciqmdvmxd54zve5kifycgsdtoahs5ecf4hal2ts3eexkgocyc5oca2y.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"encodedPublicKeyValue": "0xb5032900293f1c9e5822fd9c120b253cb4a4dfe94c214e688e01f32db9eedf17",
"encodedPrivateKeyValue": "0xd0910c853563723253c4ed105c08614fc8aaaf1b0871375520d72251496e8d87",
"encoding": "base16",
"format": "bare",
"type": "X25519",
"keyType": "dsnp.public-key-key-agreement"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:key:z6MktZ15TNtrJCW2gDLFjtjmxEdhCadNCaDizWABYfneMqhA",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z2HHWwtWggZfvGqNUk4S5AAbDGqZRFXjpMYAsXXmEksGxTk4DnnkN3upCiL1mhgwHNLkxY3s8YqNyYnmpuvUke7jF"
}
}
]
}
Login Only Response
{
"userPublicKey": {
"encodedValue": "f6akufkq9Lex6rT8RCEDRuoZQRgo5pWiRzeo81nmKNGWGNJdJ",
"encoding": "base58",
"format": "ss58",
"type": "Sr25519"
},
"payloads": [
{
"signature": {
"algo": "SR25519",
"encoding": "base16",
"encodedValue": "0xe261698297111834e68b4152bf1f89819e886b6528f6fff45715f7781d0f1e7dc4007ccfed1e85b8c603c0fea2f7abf22bfe6336869ad21f11a09a114452c680"
},
"type": "login",
"payload": {
"message": "your-app.com wants you to sign in with your Frequency account:\nf6akufkq9Lex6rT8RCEDRuoZQRgo5pWiRzeo81nmKNGWGNJdJ\n\n\n\nURI: https://your-app.com/signin/callback\nNonce: N6rLwqyz34oUxJEXJ\nIssued At: 2024-10-29T19:17:27.077Z\nExpiration Time: 2060-03-05T23:23:03.041Z"
}
}
],
"credentials": [
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedEmailAddressCredential",
"VerifiableCredential"
],
"issuer": "did:web:frequencyaccess.com",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedEmailAddressCredential/bciqe4qoczhftici4dzfvfbel7fo4h4sr5grco3oovwyk6y4ynf44tsi.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"emailAddress": "john.doe@example.com",
"lastVerified": "2024-08-21T21:27:59.309+0000"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:web:frequencyaccess.com#z6MkofWExWkUvTZeXb9TmLta5mBT6Qtj58es5Fqg1L5BCWQD",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z4jArnPwuwYxLnbBirLanpkcyBpmQwmyn5f3PdTYnxhpy48qpgvHHav6warjizjvtLMg6j3FK3BqbR2nuyT2UTSWC"
}
},
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/undefined-terms/v2"
],
"type": [
"VerifiedGraphKeyCredential",
"VerifiableCredential"
],
"issuer": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"validFrom": "2024-08-21T21:28:08.289+0000",
"credentialSchema": {
"type": "JsonSchema",
"id": "https://schemas.frequencyaccess.com/VerifiedGraphKeyCredential/bciqmdvmxd54zve5kifycgsdtoahs5ecf4hal2ts3eexkgocyc5oca2y.json"
},
"credentialSubject": {
"id": "did:key:z6QNucQV4AF1XMQV4kngbmnBHwYa6mVswPEGrkFrUayhttT1",
"encodedPublicKeyValue": "0xb5032900293f1c9e5822fd9c120b253cb4a4dfe94c214e688e01f32db9eedf17",
"encodedPrivateKeyValue": "0xd0910c853563723253c4ed105c08614fc8aaaf1b0871375520d72251496e8d87",
"encoding": "base16",
"format": "bare",
"type": "X25519",
"keyType": "dsnp.public-key-key-agreement"
},
"proof": {
"type": "DataIntegrityProof",
"verificationMethod": "did:key:z6MktZ15TNtrJCW2gDLFjtjmxEdhCadNCaDizWABYfneMqhA",
"cryptosuite": "eddsa-rdfc-2022",
"proofPurpose": "assertionMethod",
"proofValue": "z2HHWwtWggZfvGqNUk4S5AAbDGqZRFXjpMYAsXXmEksGxTk4DnnkN3upCiL1mhgwHNLkxY3s8YqNyYnmpuvUke7jF"
}
}
]
}