Getting the Login Result from Frequency Access
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.
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 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-credentialsTypeScript 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 given that the credential is fetched directly from Frequency Access. These will have issuer did:web:testnet.frequencyaccess.com or did:web:frequencyaccess.com.
- Check that the
credentialSubject.idmatches theuserPublicKeyfollowing thedid:keyMethod from the W3C
- Example:
f6cL4wq1HUNx11TcvdABNf9UNXXoyH47mVUwT59tzSFRW8yDHis the SS58 version with prefix90of the hex address0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d.0xef01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27dis multicodecsr25519-pubhex which is multiformatbase58-btcz6QNzHod3tSSJbwo4e5xGDcnsndsR9WByZzPoCGdbv3sv1jJ
- Fetch the issuer DID Document following the
did:webMethod from the W3C
- Production-Mainnet should always be
did:web:frequencyaccess.comwhich resolves tohttps://frequencyaccess.com/.well-known/did.json - Staging-Testnet should always be
did:web:testnet.frequencyaccess.comwhich resolves tohttps://testnet.frequencyaccess.com/.well-known/did.json
- Check that the key in the
proof.verificationMethodis in the DID Document to verify that the key is still valid - Test that the
proofvalidates 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 from Frequency Access.
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}}
Validation Steps
- Perform an Sr25519 signature verification using:
userPublicKey: The signing keypayload.message: The signed message parsing\nintoLFline breakssignature.encodedValue: The signature
- Verify that the
userPublicKeymatches 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 Atvalue from the message is within your acceptable time range - Verify that
Noncevalue 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:
addProvideritemActionsclaimHandle
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. Frequency Access does 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": "0x84a4e03344b07d64087ebdf47b2c8c679aa7de78179689988992609f1b83c34f6086c7de99ef41c5325cce64d148624e716c605d355f22d1281f6d23f546f584"
},
"type": "login",
"payload": {
"message": "localhost wants you to sign in with your Frequency account:\nf6akufkq9Lex6rT8RCEDRuoZQRgo5pWiRzeo81nmKNGWGNJdJ\n\n\n\nURI: https://testnet.frequencyaccess.com/signin/confirm\nNonce: N6rLwqyz34oUxJEXJ\nIssued At: 2024-03-05T23:18:03.041Z\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"
}
}
]
}