The Organizations feature adds a way for your organization to connect with users and allows you to:
Share the personal data your organization has about a given user with them in a secure and private
channel (to comply with GDPR for example).
Have data shared with your organization from a given user in a secure and private channel
with explicit consent and have the data updated by the user automatically updated in your
company's systems.
Assuming you have followed the guide from the quickstart section Quickstart section you should have a file for your user .alice.yaml
. For the purposes of this example let's also create a second user .bob.yaml
.
meeco users:create -p supersecretpassword > .bob.yaml
The next thing you are going to want to do is create the organization. Create a file called .organization-config.yaml
with the content something like the following.
kind: Organizationmetadata:spec:name: SuperData Inc.description: My super data handling organizationurl: https://superdata.example.comemail: admin@superdata.example.com
Then run the following command
meeco organizations:create -a .alice.yaml -c .organization-config.yaml > .organization.yaml
The output .organization.yaml
file will look something like the following.
kind: Organizationmetadata:privateKey: "-----BEGIN RSA PRIVATE KEY-----\r...-----END RSA PRIVATE KEY-----\r\n"publicKey: "-----BEGIN PUBLIC KEY-----\r...-----END PUBLIC KEY-----\r\n"spec:id: cc656956-6fb3-4bd1-a906-81c85dd6cb7ename: SuperData Inc.description: My super data handling organizationurl: https://superdata.example.comemail: admin@superdata.example.comstatus: requestedrequestor_id: 33bd39f9-980f-4ea6-92d3-6a28a218e6acvalidated_by_id: nullagent_id: nullvalidated_at: nullcreated_at: 2020-10-29T03:12:18.153Z
Notice how the status
field is set to requested
at this stage, this means our team has been notified of your intent to create the organization and will review and get in contact with you via the email provided. At this stage only you and the team at Meeco can see the organization. You can check organization was created and in requested state waiting for approval with the following command.
meeco organizations:list -m requested -a .alice.yaml
Once your organization has been approved by the team at meeco we'll let you know via email. From this point on your organization is publicly viewable via the API in Meeco. After that you can check to see that your organization is listed with the other publicly viewable organizations with this command.
meeco organizations:list -a .alice.yaml
Which outputs like the following.
kind: Organizationsspec:- id: cc656956-6fb3-4bd1-a906-81c85dd6cb7ename: SuperData Inc.description: My super data handling organizationurl: https://superdata.example.comemail: admin@superdata.example.comstatus: validatedrequestor_id: 33bd39f9-980f-4ea6-92d3-6a28a218e6acvalidated_by_id: 33bd39f9-980f-4ea6-92d3-6a28a218e6acagent_id: 79b75bec-aafa-4850-9c47-dfce2c633453validated_at: 2020-10-29T05:40:22.991Zcreated_at: 2020-10-29T03:12:18.153Z...
Start adding members to your organization. To invite a user to your organization first we create an invitation using the following command.
meeco organization-members:create-invitation -o .organization.yaml -a .alice.yaml > .org-invitation.yaml
Next lets have user Bob accept this invitation to become a member of the organization.
meeco organization-members:accept-invitation -i .org-invitation.yaml -a .bob.yaml > .bob-org-membership.yaml
You can see the list of members in the organization with the command.
meeco organization-members:list -a .alice.yaml cc656956-6fb3-4bd1-a906-81c85dd6cb7e# meeco organization-members:list -a <USER_AUTH_YAML> <ORGANIZATION_ID>
Organization Services are what your organization can use to connect to users, share data with them, and have data shared back with you. These services are a set of credentials that you can put into your third party systems to give them access to meeco's services. For the purposes of this guide we will complete everything using the CLI however we recommend you set up an application which performs these tasks either using the @meeco/sdk
npm package or hitting our API endpoints directly using the SDK as a guide.
First lets create a service configuration file .organization-service-config.yaml
something like the following. (Hint: you can use the cryppo cli https://github.com/Meeco/cryppo-cli to quickly and easily create a keypair with the command cryppo genkeypair -p private.pem -P public.pem
).
kind: OrganizationServicespec:name: Data Sharing Servicedescription: This service is for outgoing shared data from application Xcontract: A message about the contract
Next we create the service using that config file.
Ameeco organization-services:create -a .alice.yaml -c .organization-service-config.yaml cc656956-6fb3-4bd1-a906-81c85dd6cb7e > .organization-service.yaml# meeco organization-services:create -a <USER_AUTH_YAML> -c <ORGANIZATION_SERVICE_CONFIG_FILE> <ORGANIZATION_ID> > <OUTPUT_FILE>
The .organization-service.yaml
should have output like the following.
kind: OrganizationServicemetadata:privateKey: "-----BEGIN RSA PRIVATE KEY-----\r...-----END RSA PRIVATE KEY-----\r\n"publicKey: "-----BEGIN PUBLIC KEY-----\r...-----END PUBLIC KEY-----\r\n"spec:id: c213d93e-32a5-4e1d-96bb-0816e7eb6c74name: Data Sharing Servicedescription: This service is for outgoing shared data from application Xcontract: A message about the contractstatus: requestedorganization_id: cc656956-6fb3-4bd1-a906-81c85dd6cb7evalidated_by_id: nullagent_id: nullvalidated_at: nullcreated_at: 2020-11-03T03:43:03.751Z
At this stage the Organization service has been requested and has the status requested
. The meeco Team will again review this OrganizationService, reach out to you via email if needed, and validate your service. Once this is done we will notify you via email and you will be able to confirm that the organization service is now validated with the command. The metadata.privateKey
here should be saved as configuration for your organization service application.
meeco organization-services:get -a .alice.yaml cc656956-6fb3-4bd1-a906-81c85dd6cb7e c213d93e-32a5-4e1d-96bb-0816e7eb6c74# meeco organization-services:get -a .alice.yaml <ORGANIZATION_ID> <SERVICE_ID>
The result should be something like the following, if the list is empty it means the service has not yet been validated.
kind: OrganizationServicespec:id: c213d93e-32a5-4e1d-96bb-0816e7eb6c74name: Data Sharing Servicedescription: This service is for outgoing shared data from application Xcontract: A message about the contractstatus: validatedorganization_id: cc656956-6fb3-4bd1-a906-81c85dd6cb7evalidated_by_id: 33bd39f9-980f-4ea6-92d3-6a28a218e6acagent_id: 3392a0e4-0046-40d5-a532-5bca94f1d801validated_at: 2020-11-03T04:51:59.724Zcreated_at: 2020-11-03T04:27:16.784Z
Now we have created our organization service we can request an authentication token for it.
meeco organization-services:login -a .alice.yaml -s .organization-service.yaml > .organization_service_auth.yaml
The .organization_service_auth.yaml
should look like the following.
kind: Authenticationmetadata:data_encryption_key: ""key_encryption_key: ""keystore_access_token: ""passphrase_derived_key: ""secret: ""vault_access_token: ANDJk1gJpFKmwrCjNyd7spec: {}
The metadata.vault_access_token
should be saved as configuration for your organization service application. So from now your application has a vault_access_token
and a private_key
, these should be set as configuration variables. But how do we use them.
Your organization first needs to connect to a user through it's organization service. To do that it will first create an invitation.
The keypair_external_id
can be left blank in this case if we are using the same public key to connect with all users. In some cases you may wish to use a unique public key for each user connection, in this case you should store the related private key somewhere with reference to the user who you are connecting to.
The encrypted_recipient_name
is a record to be used by your organization only, it should identify in some way who the invitation has been created for. It should encrypted and serialized using a Cryppo serialization format (see https://github.com/Meeco/cryppo-js for more details).
The public_key
here can be unique per connection but in this case we are just going th use the keypair from the organization service.
# first part here just writes the json to a file removing all whitespace and newlinescat <<'EOF' | tr -d '\040\011\012\015' > data.json{"public_key": {"keypair_external_id": "string","public_key": "-----BEGIN PUBLIC KEY-----\rMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzao4lCviLTEg2ze8jmts\ry6iG6iKX3TGIdlcHJbFBAs0oCVp29jhlOXVfwuxX6gqplLT44rpSnYcsvKYao7ol\rt7ZadkQg/j1xm+Sw/FTyLKhNyHznclnTUXPnnvY6sHwpfaC0NBIAy1XRI8r3gqiu\rngOx4afC+PeZnrCvhjsnmR1cd/FXTWQuH8GfrqdDbH3K8ObAv4r3VT2RcUvgUEVg\r6Yg29fAF5B9Wmcwl9Kr53nryp04412QvNjlJZlilbNsmvXYnPfu4bM8kRV56iBeE\rL1OOBu65oZcBvXym3Gtd057J+0kDqGp4t76qB9DNy8n3SikvY8hyZHQsx54QBecy\rKxPETEGVWGMFHI5+UIriMr0PEF4AUE9KZWVt3bAhQPyby3Fm9dju01q9nV2qt5Cy\rZnsNui2VZ7EGDxoJPH74fsnrXX7cX8VPFgg2pxmpzmI12X1YBKdymKvCRsa+5I5S\rF2/g5pwJznx1babFSCSenmPr8eIz6Y1iJSigwr4tsUAbE1C6Vn6PEBrsmzMFhe3M\rA7YwqJvNjOZZb3Yocaf08Xn8/oISCd1ItU5W6mLW/uwRSB4cGs/D7E5mNj0bvE+1\rG94RFHSDCzIYyPtb/8dFKlwSJ3Jm2HytiN7c2dVv61KrQFRyktPHPLVR/V6r8XcB\rFR6qZSfofTNCs7HI+VAIKV8CAwEAAQ==\r-----END PUBLIC KEY-----\r\n"},"invitation": {"encrypted_recipient_name": "Aes256Gcm.J9YhaGdIUBKa2dULbMU=.LS0tCml2OiAhYmluYXJ5IHwtCiAgd1JGK2QrRjYzRHJhbDRmdgphdDogIWJpbmFyeSB8LQogIGllS3JnK05iV0JVY2N3L3VVS2N6Rnc9PQphZDogbm9uZQo="}}EOF# second part here actually makes the requestcurl -X POST "https://sandbox.meeco.me/vault/invitations" \-d @data.json \-H "Accept: application/json" \-H "Meeco-Subscription-Key: Q7dFWQDGSsAE6tUo1G93Mlhn4SCOBrJe" \-H "Authorization: ANDJk1gJpFKmwrCjNyd7" \-H "Content-Type: application/json" \| json_pp \> invitation.json
The invitation.json
file should have output that looks something like.
{"invitation" : {"keypair_external_id" : "string","token" : "cPWV4CwpWTHxhqaJGG9MRkVWxKojGhMPGs4oTuoBdTU","message" : null,"user_image" : null,"integration_data" : {"organization_id" : "cc656956-6fb3-4bd1-a906-81c85dd6cb7e","intent" : "service","service_id" : "c213d93e-32a5-4e1d-96bb-0816e7eb6c74"},"id" : "62b54a86-66db-4e88-8e3d-3ce4457a2e97","user_name" : null,"invited_user_id" : null,"outgoing" : true,"encrypted_recipient_name" : "Aes256Gcm.J9YhaGdIUBKa2dULbMU=.LS0tCml2OiAhYmluYXJ5IHwtCiAgd1JGK2QrRjYzRHJhbDRmdgphdDogIWJpbmFyeSB8LQogIGllS3JnK05iV0JVY2N3L3VVS2N6Rnc9PQphZDogbm9uZQo=","sent_at" : null}}
The invitation has been created so lets make an unrelated user to accept this connection invitation.
meeco users:create -p supersecretpassword > .dave.yaml
Then for bob to accept this invitaion (and create the connection).
We should have a new keypair and public_key
somewhere that we can use for this connection for Dave, dave might use the meeco keystore to manage this but in this case lets forget about the keystore for now to keep it simple.
Again the keypair_external_id
would be a reference for Dave to retrieve the appropriate keypair (when using the keystore this would be the id of the key record) but we can just put the name of the organization service in there for this reference.
The invitation_token
here would be .invitation.token
from the invitation.json
file.
The Authorization
here should be Dave's authorization token (from .dave.yaml
).
# first part here just writes the json to a file removing all whitespace and newlinescat <<'EOF' | tr -d '\040\011\012\015' > data.json{"public_key": {"keypair_external_id": "DataSharingService","public_key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqMILz56KuEsGlsEpML3h\nPN7OUf7HrLTtWkazwbNIkK3RLWtNI5X8bd0ISUuwgXQVzZuWyC6wXPiWSDwXILAf\nJPusVT6Kh0EmXhJtBRCkF64fXKz54rI/2kYpuP4HZbNStj8OIRv/ECV7glDf+4Yq\nWDdLmh2vHDHF7bIRQnuWwV3ZL10Gkuh671aJkkVRdApUZUNcDfz1VK/SDMLxuxMg\n8D78u+d0WgThXzEwlcHtRitLA4QekNjVNPkoZoRIJSWLWqwkaOd0+YAhPNso3t9Y\nwaLT0/hDe4qBRuWpkoCIIUxE1JPuUbv3ePwsvyX9ksKNwQ6zVyOBXJwjspjac3mS\nH2DXS8dwU/ObKI3v9c/aY0i4iV6xJIkDxV2V8HclMOm1cLmgoc9YMU9YuM2LZ1GX\n707XBrdRD1v/FNQa/HJjFSapXcztN03etswrJcYFxVxDWZ84uMO2TNHOsSbOgop9\nmF5hRLQ+PT45v+mNNmbJa62yRaVkIV4VvsHgBVsz6TWsZGxu+IsNLKT/OYju/zzn\nvQSig5Ue7BAZqMOlibWiB6gX8vM336okrOWASnvWZNe+a7QpQdYYbHbH/leFZFCA\nht20DXUHLXYAKk9gvdqKycYnVsaRb2dnaSdUez+AUsIme0gWPscwSf3XpARUDc5i\nEKfIKQZzxyj4Y7W6eGwAfCMCAwEAAQ==\n-----END PUBLIC KEY-----\n"},"connection": {"encrypted_recipient_name": "Aes256Gcm.SjlZaGFHZElVQkthMmRVTGJNVQ==.LS0tCml2OiAhYmluYXJ5IHwtCiAgd1JGK2QrRjYzRHJhbDRmdgphdDogIWJpbmFyeSB8LQogIGllS3JnK05iV0JVY2N3L3VVS2N6Rnc9PQphZDogbm9uZQo=","invitation_token": "cPWV4CwpWTHxhqaJGG9MRkVWxKojGhMPGs4oTuoBdTU"}}EOF# second part here actually makes the requestcurl -X POST "https://sandbox.meeco.me/vault/connections" \-d @data.json \-H "Accept: application/json" \-H "Meeco-Subscription-Key: Q7dFWQDGSsAE6tUo1G93Mlhn4SCOBrJe" \-H "Authorization: hZwx4XPj6MZJcPHPKHqc" \-H "Content-Type: application/json" \| json_pp \> connection.json
The connection will have been created and the output in connection.json
will look something like.
{"connection" : {"own" : {"connection_type" : "service","integration_data" : {"intent" : "service","service_id" : "c213d93e-32a5-4e1d-96bb-0816e7eb6c74","organization_id" : "cc656956-6fb3-4bd1-a906-81c85dd6cb7e"},"user_id" : "d62d37f8-9f53-4be2-9df3-af7541d08316","id" : "c76b28f6-ab27-4b41-a8db-3184d17b8fbc","user_public_key" : "-----BEGINPUBLICKEY----- ... -----ENDPUBLICKEY-----\n","user_type" : "human","user_keypair_external_id" : "DataSharingService","encrypted_recipient_name" : "Aes256Gcm.SjlZaGFHZElVQkthMmRVTGJNVQ==.LS0tCml2OiAhYmluYXJ5IHwtCiAgd1JGK2QrRjYzRHJhbDRmdgphdDogIWJpbmFyeSB8LQogIGllS3JnK05iV0JVY2N3L3VVS2N6Rnc9PQphZDogbm9uZQo="},"the_other_user" : {"connection_type" : "service","id" : "359486bb-e998-4699-9eed-5e7194987565","user_id" : "c3482646-f6cf-48a2-877c-04857802d4de","integration_data" : {"organization_id" : "cc656956-6fb3-4bd1-a906-81c85dd6cb7e","service_id" : "c213d93e-32a5-4e1d-96bb-0816e7eb6c74","intent" : "service"},"user_keypair_external_id" : "string","user_type" : "service_agent","user_public_key" : "-----BEGINPUBLICKEY----- ... -----ENDPUBLICKEY-----\n",}}}
The OrganizationService
has now made it's first connection with a user.