SIP for Authentication Protocol#50
Conversation
|
After the description of the current protocol 1.3.1, I have updated the spec to 2.0.0 in 7b35de6 using verifiable credentials and better definition of the issuers. |
| 1. Application creates app transit private key, signs an auth request with that key and sends the request to the Authenticator. | ||
| 2. In the Authenticator, User authorizes sharing of public key, Authenticator derives app private key from request and updates the user's public profile if required. | ||
| 3. Authenticator creates response with authorized data and sends response to the Application. | ||
| 4. Application verifies signature against the app transit private key. |
There was a problem hiding this comment.
| 1. Application creates app transit private key, signs an auth request with that key and sends the request to the Authenticator. | |
| 2. In the Authenticator, User authorizes sharing of public key, Authenticator derives app private key from request and updates the user's public profile if required. | |
| 3. Authenticator creates response with authorized data and sends response to the Application. | |
| 4. Application verifies signature against the app transit private key. | |
| **Client (app):** | |
| 1. Client generates ephemeral private/public key pair: `transitPrivateKey` | |
| 2. Client creates an auth request payload (`authRequestPayload`) with details about the application, eg: | |
| ```ts | |
| export interface AuthRequestPayload { | |
| scopes: AuthScope[]; | |
| redirect_uri: string; | |
| public_keys: string[]; | |
| domain_name: string; | |
| appDetails: AppDetails; | |
| } | |
| ``` | |
| 3. Client signs the auth request payload (a JWT) with the `transitPrivateKey`, with signature format `ES256k` | |
| 4. Client sends the JWT to an authenticator (eg: Hiro Web Wallet) | |
| **Authenticator (wallet):** | |
| 1. Authenticator validates the signature against the included public key(s) | |
| 2. Authenticator generates an account index by creating a SHA256 hash of the domain of the application that generated the `authRequestPayload`, and the wallet's salt | |
| 3. Authenticator then uses that index to derive a hardened child private key (`appPrivateKey`) from the root seed phrase (BIP32). | |
| 4. Authenticator generates an `authResponse` which includes the `appPrivateKey` | |
| 5. Authenticator encrypts the JWT with the public key provided in the `authRequestPayload` | |
| **Client (app):** | |
| 1. Client receives the encrypted `authResponse` and decrypts it with the `transitPrivateKey` | |
| 2. Client is now authenticated |
There was a problem hiding this comment.
I wanted to give a high level overview first. Ideally with a better diagram than the current one. I like the separation between the two entities, but I think it is too much detail. Maybe we should have this in pseudo code as an appendix? @aulneau
The auth response is not encrypted, only the appPrivateKey (and core_token). Messages are always normal JWTs.
|
|
||
| 1. Wallet salt: create the sha256 hash of the hex representation of the public key of derivation path (`m/888'/0'`) | ||
| 1. Create sha256 hash of concatinated string of the `domain_name` from the request and the hex representation of the wallet salt. | ||
| 1. Hash code: Create a hash code (as defined in Java and Javascript) from the hex representation of the hash, then apply bitwise `and` to the hash code and 0x7fffffff. |
There was a problem hiding this comment.
This is highly prone to collisions, and generally a bad implementation. Unfortunately, it has been used for years. I have created what I think is a better alternative here in micro-stacks.
// Rather than using the `hashCode` function to derive an index for the child
// which makes it so there's a unreasonable high probability that someone can
// log into a new app (website) and it accidentally shares data with another one
//
// we want to use the `appDomain` + `salt` to generate a sha256 hash that is
// then used as the chaincode for the new app keychain
const chainCode = hashSha256(utf8ToBytes(`${appDomain}${account.salt}`));
const rootNode = HDKeychain.fromBase58(account.appsKey);
const appKeychain = await HDKeychain.fromPrivateKey(rootNode.privateKey, chainCode).deriveChild(
0,
true
);With the formalization of this standard in a SIP, would it make sense to explore this (or another) alternative?
There was a problem hiding this comment.
Interesting. We should fix that!
| | public_keys | array | Single item array containing the public key of the selected account in hex representation. | | ||
| | profile | object | Object containing properties of the users, the object schema should be well-known type of Appendix B. This can be the public profile of the selected account. | | ||
| | apps_meta | object | Information about user data of different apps. Property names are the domain name of the app. Each property value is an object of containing properties for `storage` and `publicKey`. See "Application Meta Data". | | ||
| | username | string | BNS username, owned by the first public key of `public_keys` claim. Can be the empty string | |
There was a problem hiding this comment.
We're currently in the process of removing the username from the authentication flow completely. stx-labs/stacks.js#1230 Keeping the username adds a bunch of complications. Additionally, the username should be verified by the application anyway, so it makes sense for the application to fetch the username in the first place.
I bumped the token version to 1.4.0 for this, in case anybody is validating very strictly.
some discussions/comments here:
There was a problem hiding this comment.
+1 this seems like a good separation of concerns
|
I'm in the process of building a new library that implements this SIP in micro-stacks and I have a few questions: In the auth request area:
In the auth response section:
|
|
Replaced by #166 |
This SIP defines a authentication protocol used by Stacks apps.
The current version has (hopefully) all the required information about the protocol as it is currently used.
I changed three properties of the auth response:
hubUrl->hub_urlandassociationToken->association_token.profile.stxAddress->stx_address.I added
stateto the auth messages as defined in OAuth 2.0.It is recommended to use
did:stacks:v2instead ofdid:btc-addrFor the public profile, this spec uses the Verifiable Credential model. The VC spec was chosen because it now has W3C Recommendation status.