JSON Web Tokens
As a security measure, your server must allow identity creation and anonymous encryptions using JSON Web tokens.
For signup, this feature replaces the now deprecated User License Tokens.
Creating a JWTSecret
Once the JWTSecret is created, you will need to retrieve this JWTSecret
and its JWTSecretId
to enable your server to create JSON Web Tokens.
Each JWTSecret has permissions. For more details, see permissions.
TIP
JWTSecret
is, as the name implies, secret. Please take appropriate measures to store it securely.
However, JWTSecretId
is not secret.
Via the dashboard
When creating your dashboard account, a JWT secret including all permissions (permission: -1) is automatically created. This is displayed on the homepage.
To generate another JWT Secret, login to your admin dashboard and follow these steps:
- Go to the settings,
JWT secrets
tab. - Click on
create a secret
. - Select the desired permissions.
- Confirm the creation of the secret.
Once the secret is created, retrieve its ID, JWTSecretId
, and its value: JWTSecret
.
Programmatically
To create a JSON Web Token, you first need a JWTSecret.
You can create, list, and delete JWTSecret, which allow to create JSON Web Tokens for your team, on the DashboardAPI.
In order to create a JWTSecret, you can make a POST /dashboardapi/v2/jwtsharedsecret/
, with the request body:
{
"permissions": Array<Permission>
}
Code example
Example request to create a JWTSecret:
curl -X POST https://dashboard.seald.io/dashboardapi/v2/jwtsharedsecret/ \
-H 'X-DASHBOARD-API-KEY: YOUR_ACCESS_TOKEN' \
-H 'Content-Type: application/json' \
--data-raw '{"permissions": [1]}'
Example response:
{
"id": "32266d8c-2085-490a-8ef5-259ea35e1501", // UUID : JWTSecretId
"created": "2021-11-09T10:49:09.490338Z", // Timestamp ISO
"shared_secret": "c9kijQo1kJgieXZ9TAHFj9R0TgHb4bgLhDnWWRgjq4TmBzUdSB5mzuOcBb0gQMSi", // String : JWTSecret
"permissions": [ 1 ] // Array<Permission>
}
Adding a connector
You can add a connector
to a SDK identity. This connector
is a string that specifies a user uniquely for your application. You can choose any unique identifier. Depending on the user model in your application, you can for example choose: the username, their email address, their internal ID in your application, ...
The connector
must be in the format ${IDENTIFIER}@${APP_ID}
. The connector
type must always be 'AP'
.
An identity can have multiple identifiers.
TIP
The old name of this feature, now deprecated, used to be userId
. The userId
used to correspond to the IDENTIFIER
part of the connector
format described above, without the @${APP_ID}
.
For this, the JWT Secret must have the PERMISSION_ADD_CONNECTOR
permission. This connector
is specified in the connector_add
key of the JWT.
WARNING
The connector
is stored in clear text in our database. In order to minimize the data that Seald stores about your users, it is not recommended to use an email address or any other personal identifying information. The optimal is to use a UUID.
JSON Web Token permissions
Each JWTSecret has permissions, and it can assign any or all of the permissions it has to each JSON Web Token it creates.
Permission
are integers. Possible values are as follows:
PERMISSION_ALL = -1
: all permissions.PERMISSION_ANONYMOUS_CREATE_SESSION = 0
: allows creating JSON Web Tokens which can anonymously create an Encryption Session.PERMISSION_ANONYMOUS_FIND_KEYS = 1
: allows creating JSON Web Tokens which can retrieve the recipients' encryption keys.PERMISSION_ANONYMOUS_FIND_SIGCHAIN = 2
: allows creating JSON Web Tokens which can retrieve the recipients' SigChain. Unused.PERMISSION_JOIN_TEAM = 3
: allows creating JSON Web Tokens which can add an SDK identity to your team.PERMISSION_ADD_CONNECTOR = 4
: allows creating JSON Web Tokens which can add a customuserId
to an SDK identity.PERMISSION_ANONYMOUS_FIND_SYMENCKEY = 5
: allows creating JSON Web Tokens which can retrieve an Encryption Session anonymously via a SymEncKey.
Creating a JSON Web Token
The JSON Web Token, or JWT, is created with the JWTSecret
and its JWTSecretId
: it has the JWTSecretId
as iss
, and is signed with the JWTSecret
with the HS256
algorithm.
Its payload is:
Name | Type | Use | Description |
---|---|---|---|
iss | string | Always | "Issuer" : the JWTSecretId |
iat | number | Always | "Issued at" : timestamp (in seconds) of the JWT creation. If exp is not set, the JWT expires 10 min after creation. |
exp? | number | Always | "Expire" : timestamp (in seconds) of when the JWT will expire. If not set, the JWT expires 10 min after creation. |
jti? | string | Always | "JWT ID" : unique nonce. Must never be re-used. Optional. If defined, the JWT is usable only once. If not, it is usable until its potential expiration. |
scopes? | Array<Permission> | Always | List of this JWT's permissions. Optional. Must be a subset of the JWTSecret 's permissions. If defined, the JWT is limited to these permissions only. If not, it has all the permissions assigned to the creating JWTSecret . |
recipients? | Array<string> | Anonymous encryption | List of sealdIds of recipients for whom this JWT is authorized to perform operations. |
owner? | string | Anonymous encryption | Optional for retrieving recipient keys. Necessary for session creation. sealdId of the user who will own the created session. |
join_team? | boolean | Identities | Allow the identity to join your team. Each identity can only be in one team at a time. |
connector_add? | { value: connectorValue, type: 'AP' } | Identities | Allows the addition of a custom identifier connector to an identity. The value must be of the form ${IDENTIFIER}@${APP_ID} . |
sym_enc_keys? | Array<string> | Anonymous session retrieval | Required for anonymous session retrieval. Array of IDs of the SymEncKeys that this JWT will be allowed to use to retrieve a session. |
Code examples
Signup JWT
Example of creating a JWT for signup, on your backend:
import { SignJWT } from 'jose'
// A JWT secret that has `PERMISSION_JOIN_TEAM`
const JWTSecretId = 'JWT SHARED SECRET ID'
const JWTSecret = 'JWT SHARED SECRET'
const token = new SignJWT({
iss: JWTSecretId,
jti: random(), // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Math.floor(Date.now() / 1000), // JWT valid only for 10 minutes. `Date.now()` returns the timestamp in milliseconds, this needs it in seconds.
scopes: [3], // PERMISSION_JOIN_TEAM
join_team: true
})
.setProtectedHeader({ alg: 'HS256' })
const signupJWT = await token.sign(Buffer.from(JWTSecret, 'ascii'))
import JWT
// A JWT secret that has `PERMISSION_JOIN_TEAM`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
let now = Date()
let headers = ["typ" : "JWT"]
let payload = ["iss" : JWTSharedSecretId,
"jti" : UUID().uuidString, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat" : NSNumber(value: now.timeIntervalSince1970), // JWT valid only for 10 minutes.
"join_team": true,
"scopes": [3], // PERMISSION_JOIN_TEAM
] as [String : Any]
let signupJWT = JWT.encodePayload(payload, withSecret: JWTSharedSecret, withHeaders: headers, algorithm: JWTAlgorithm)
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.security.Keys
import java.util.*
import javax.crypto.SecretKey
// A JWT secret that has `PERMISSION_JOIN_TEAM`
val JWTSecretId: String = "JWT SHARED SECRET ID"
val JWTSecret: String = "JWT SHARED SECRET"
JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.toByteArray())
val date = Date()
val expiryDate = Date(date.time + 2 * 60 * 60 * 1000)
val signupJWT = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("join_team", true)
.claim("scopes", listOf(3)) // PERMISSION_JOIN_TEAM
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSharedSecretId)
.setIssuedAt(date) // JWT valid only for 10 minutes.
.setExpiration(expiryDate)
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact()
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import java.util.UUID;
import javax.crypto.SecretKey;
// A JWT secret that has `PERMISSION_JOIN_TEAM`
final String JWTSecretId = "JWT SHARED SECRET ID";
final String JWTSecret = "JWT SHARED SECRET";
SecretKey JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.getBytes());
Date date = new Date();
Date expiryDate = new Date(date.getTime() + 2 * 60 * 60 * 1000);
String signupJWT = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("join_team", true)
.claim("scopes", List.of(3)) // PERMISSION_JOIN_TEAM
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSecretId)
.setIssuedAt(date) // JWT valid only for 10 minutes.
.setExpiration(expiryDate)
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact();
import jwt # This example uses the PyJWT library: https://pypi.org/project/PyJWT/
from datetime import datetime
# A JWT secret that has `PERMISSION_JOIN_TEAM`
jwt_shared_secret_id = "JWT SHARED SECRET ID"
jwt_shared_secret = "JWT SHARED SECRET"
signup_JWT = jwt.encode(
{
"iss": jwt_shared_secret_id,
"jti": str(uuid.uuid4()), # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat": datetime.now(), # JWT valid only for 10 minutes.
"scopes": [3], # PERMISSION_JOIN_TEAM
"join_team": True,
},
jwt_shared_secret,
algorithm="HS256",
)
package main
import (
"crypto/rand"
"encoding/base64"
"github.com/dgrijalva/jwt-go"
"time"
)
// A JWT secret that has `PERMISSION_JOIN_TEAM`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
type ConnectorAdd struct {
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
}
type JWTPermissionScopes int
const (
PermissionAll JWTPermissionScopes = -1
PermissionAnonymousCreateSession JWTPermissionScopes = 0
PermissionAnonymousFindKeys JWTPermissionScopes = 1
PermissionAnonymousFindSigchain JWTPermissionScopes = 2
PermissionJoinTeam JWTPermissionScopes = 3
PermissionAddConnector JWTPermissionScopes = 4
PermissionAnonymousFindSymEncKey JWTPermissionScopes = 5
)
type CustomClaims struct {
Recipients []string `json:"recipients,omitempty"`
Owner string `json:"owner,omitempty"`
JoinTeam bool `json:"join_team,omitempty"`
ConnectorAdd ConnectorAdd `json:"connector_add,omitempty"`
SymEncKeys []string `json:"sym_enc_keys,omitempty"`
Scopes []JWTPermissionScopes `json:"scopes"`
jwt.StandardClaims
}
func randomString() string {
bytes := make([]byte, 32)
_, err := rand.Read(bytes)
if err != nil {
panic("Failed to generate a random string")
}
return base64.StdEncoding.EncodeToString(bytes)
}
func main() {
claims := CustomClaims{
Scopes: []JWTPermissionScopes{PermissionJoinTeam},
JoinTeam: true,
StandardClaims: jwt.StandardClaims{
Id: randomString(),
Issuer: JWTSecretId,
IssuedAt: time.Now().Unix(),
},
}
signupJWT, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(JWTSecret))
}
require 'jose'
# A JWT secret that has `PERMISSION_JOIN_TEAM`
jwt_secret_id = "JWT SHARED SECRET ID"
jwt_secret = "JWT SHARED SECRET"
payload = {
iss: jwt_secret_id,
jti: SecureRandom.uuid, # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Time.now.to_i, # JWT valid only for 10 minutes.
scopes: [3], # PERMISSION_JOIN_TEAM
join_team: true
}
jwk = JOSE::JWK.from_oct(jwt_secret)
jws = JOSE::JWS.sign(jwk, payload.to_json, { "alg" => "HS256" })
signupJWT = jws.compact
// using web-token/jwt-framework and web-token/jwt-core libraries
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Serializer\CompactSerializer;
// A JWT secret that has `PERMISSION_JOIN_TEAM`
$JWTSecretId = "JWT SHARED SECRET ID";
$JWTSecret = "JWT SHARED SECRET";
$random = bin2hex(random_bytes(16));
$algorithmManager = new AlgorithmManager([
new HS256(),
]);
$jwsBuilder = new JWSBuilder($algorithmManager);
$payload = json_encode([
'iss' => $JWTSecretId,
'jti' => $random, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
'iat' => time(), // JWT valid only for 10 minutes.
'scopes' => [3], // PERMISSION_JOIN_TEAM
'join_team' => true,
]);
$jwk = JWKFactory::createFromSecret(
$JWTSecret,
[
'alg' => 'HS256',
'use' => 'sig'
]
);
$jws = $jwsBuilder
->create()
->withPayload($payload)
->addSignature($jwk, ['alg' => 'HS256'])
->build();
$serializer = new CompactSerializer();
$signupJWT = $serializer->serialize($jws, 0);
JWT usage, client-side:
import SealdSDK from '@seald-io/sdk'
const sdk = SealdSDK({ appId })
await sdk.initiateIdentity({ signupJWT: jwt })
import SealdSdk
let sdk = try! SealdSdk.init(apiUrl: apiURL,
appId: appId,
dbPath: "PATH TO LOCAL DATABASE",
dbb64SymKey: databaseEncryptionKeyB64,
instanceName: "instanceName",
logLevel: -1,
logNoColor: true,
encryptionSessionCacheTTL: 0,
keySize: 4096)
try! sdk.createAccount(withSignupJwt: signupJWT, deviceName: "Device name", displayName: "User name", expireAfter: 5 * 365 * 24 * 60 * 60)
#import <SealdSdk/SealdSdk.h>
SealdSdk *sdk1 = [[SealdSdk alloc] initWithApiUrl:sealdCredentials->apiURL appId:sealdCredentials->appId dbPath:[NSString stringWithFormat:@"%@/inst1", sealdDir] dbb64SymKey:databaseEncryptionKeyB64 instanceName:@"User1" logLevel:0 logNoColor:true encryptionSessionCacheTTL:0 keySize:4096 error:&error];
[sdk1 createAccountWithSignupJwt:[jwtbuilder signupJWT] deviceName:@"Device name" displayName:@"User name" expireAfter:0 error:&error];
import io.seald.seald_sdk.SealdSDK
val sdk1 = SealdSDK(apiURL, appId, "$path/sdk1", databaseEncryptionKeyB64, instanceName = "instanceName", logLevel = -1)
val user1AccountInfo = sdk1.createAccount(signupJWT, "User name", "Device name")
import (
"go-seald-sdk/sdk"
)
initOptions := &sdk.InitializeOptions{
ApiURL: credentials.ApiUrl,
Database: &sdk.MemoryStorage{},
KeySize: 1024,
AppId: credentials.AppId,
EncryptionSessionCacheTTL: 24 * time.Hour,
LogLevel: zerolog.TraceLevel,
}
sdk, err := sdk.Initialize(initOptions)
_, err = account.CreateAccount(&sdk.CreateAccountOptions{
DisplayName: "User name",
DeviceName: "Device name",
SignupJWT: signupJWT,
ExpireAfter: time.Hour * 24 * 365 * 5,
})
JWT to add a connector
On your backend, example of creating a JWT to add a connector
:
import { SignJWT } from 'jose'
// A JWT secret that has `PERMISSION_ADD_CONNECTOR`
const JWTSecretId = 'JWT SHARED SECRET ID'
const JWTSecret = 'JWT SHARED SECRET'
const token = new SignJWT({
iss: JWTSecretId,
jti: random(), // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Math.floor(Date.now() / 1000), // JWT valid only for 10 minutes. `Date.now()` returns the timestamp in milliseconds, this needs it in seconds.
scopes: [4], // PERMISSION_ADD_CONNECTOR
connector_add: {
value: customId + '@' + appId,
type: 'AP'
}
})
.setProtectedHeader({ alg: 'HS256' })
const connectorJWT = await token.sign(Buffer.from(JWTSecret, 'ascii'))
import JWT
// A JWT secret that has `PERMISSION_ADD_CONNECTOR`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
let now = Date()
let headers = ["typ" : "JWT"]
let payload = ["iss" : JWTSharedSecretId,
"jti" : UUID().uuidString, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat" : NSNumber(value: now.timeIntervalSince1970), // JWT valid only for 10 minutes.
"scopes": [4], // PERMISSION_ADD_CONNECTOR
"connector_add": ["type": "AP", "value": "\(customId)@\(appId)"],
] as [String : Any]
let connectorJWT = JWT.encodePayload(payload, withSecret: JWTSharedSecret, withHeaders: headers, algorithm: JWTAlgorithm)
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.security.Keys
import java.util.*
import javax.crypto.SecretKey
// A JWT secret that has `PERMISSION_ADD_CONNECTOR`
val JWTSecretId: String = "JWT SHARED SECRET ID"
val JWTSecret: String = "JWT SHARED SECRET"
JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.toByteArray())
val date = Date()
val expiryDate = Date(date.time + 2 * 60 * 60 * 1000)
val connectorJWT = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("join_team", true)
.claim("scopes", listOf(4)) // PERMISSION_ADD_CONNECTOR
.claim("connector_add", mapOf("type" to "AP", "value" to "customId@$appId"))
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSharedSecretId)
.setIssuedAt(date) // JWT valid only for 10 minutes.
.setExpiration(expiryDate)
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact()
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import java.util.UUID;
import javax.crypto.SecretKey;
// A JWT secret that has `PERMISSION_ADD_CONNECTOR`
final String JWTSecretId = "JWT SHARED SECRET ID";
final String JWTSecret = "JWT SHARED SECRET";
SecretKey JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.getBytes());
Date date = new Date();
Date expiryDate = new Date(date.getTime() + 2 * 60 * 60 * 1000);
String connectorJWT = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("scopes", List.of(4)) // PERMISSION_ADD_CONNECTOR
.claim("connector_add", new JSONObject()
.put("value", customId + "@" + appId)
.put("type", "AP")
)
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSecretId)
.setIssuedAt(date) // JWT valid only for 10 minutes.
.setExpiration(expiryDate)
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact();
import jwt # This example uses the PyJWT library: https://pypi.org/project/PyJWT/
from datetime import datetime
# A JWT secret that has `PERMISSION_ADD_CONNECTOR`
jwt_shared_secret_id = "JWT SHARED SECRET ID"
jwt_shared_secret = "JWT SHARED SECRET"
connector_JWT = jwt.encode(
{
"iss": jwt_shared_secret_id,
"jti": str(uuid.uuid4()), # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat": datetime.now(), # JWT valid only for 10 minutes.
"scopes": [4], # PERMISSION_ADD_CONNECTOR
"connector_add": {
"value": f"{customId}@{appId}",
"type": "AP"
}
},
jwt_shared_secret,
algorithm="HS256",
)
package main
import (
"crypto/rand"
"encoding/base64"
"github.com/dgrijalva/jwt-go"
"time"
)
// A JWT secret that has `PERMISSION_ADD_CONNECTOR`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
type ConnectorAdd struct {
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
}
type JWTPermissionScopes int
const (
PermissionAll JWTPermissionScopes = -1
PermissionAnonymousCreateSession JWTPermissionScopes = 0
PermissionAnonymousFindKeys JWTPermissionScopes = 1
PermissionAnonymousFindSigchain JWTPermissionScopes = 2
PermissionJoinTeam JWTPermissionScopes = 3
PermissionAddConnector JWTPermissionScopes = 4
PermissionAnonymousFindSymEncKey JWTPermissionScopes = 5
)
type CustomClaims struct {
Recipients []string `json:"recipients,omitempty"`
Owner string `json:"owner,omitempty"`
JoinTeam bool `json:"join_team,omitempty"`
ConnectorAdd ConnectorAdd `json:"connector_add,omitempty"`
SymEncKeys []string `json:"sym_enc_keys,omitempty"`
Scopes []JWTPermissionScopes `json:"scopes"`
jwt.StandardClaims
}
func randomString() string {
bytes := make([]byte, 32)
_, err := rand.Read(bytes)
if err != nil {
panic("Failed to generate a random string")
}
return base64.StdEncoding.EncodeToString(bytes)
}
func main() {
claims := CustomClaims{
Scopes: []JWTPermissionScopes{PermissionAddConnector},
ConnectorAdd: ConnectorAdd{Type: "AP", Value: customId + "@" + appId},
StandardClaims: jwt.StandardClaims{
Id: randomString(),
Issuer: JWTSecretId,
IssuedAt: time.Now().Unix(),
},
}
connectorJWT, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(JWTSecret))
}
require 'jose'
# A JWT secret that has `PERMISSION_ADD_CONNECTOR`
jwt_secret_id = "JWT SHARED SECRET ID"
jwt_secret = "JWT SHARED SECRET"
payload = {
iss: jwt_secret_id,
jti: SecureRandom.uuid, # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Time.now.to_i, # JWT valid only for 10 minutes.
scopes: [4], # PERMISSION_ADD_CONNECTOR
connector_add: {
value: "#{customId}@#{appId}",
type: 'AP'
}
}
jwk = JOSE::JWK.from_oct(jwt_secret)
jws = JOSE::JWS.sign(jwk, payload.to_json, { "alg" => "HS256" })
connectorJWT = jws.compact
// using web-token/jwt-framework and web-token/jwt-core libraries
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Serializer\CompactSerializer;
// A JWT secret that has `PERMISSION_ADD_CONNECTOR`
$JWTSecretId = "JWT SHARED SECRET ID";
$JWTSecret = "JWT SHARED SECRET";
$random = bin2hex(random_bytes(16));
$algorithmManager = new AlgorithmManager([
new HS256(),
]);
$jwsBuilder = new JWSBuilder($algorithmManager);
$payload = json_encode([
'iss' => $JWTSecretId,
'jti' => $random, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
'iat' => time(), // JWT valid only for 10 minutes.
'scopes' => [4], // PERMISSION_ADD_CONNECTOR
'connector_add' => [
'value' => $customId . '@' . $appId,
'type' => 'AP'
],
]);
$jwk = JWKFactory::createFromSecret(
$JWTSecret,
[
'alg' => 'HS256',
'use' => 'sig'
]
);
$jws = $jwsBuilder
->create()
->withPayload($payload)
->addSignature($jwk, ['alg' => 'HS256'])
->build();
$serializer = new CompactSerializer();
$connectorJWT = $serializer->serialize($jws, 0);
client-side: JWT usage, on an already instanciated SDK identity.
await sdk.pushJWT(jwt)
try! sdk.pushJWT(addConnectorJWT)
[sdk pushJWT:addConnectorJWT error:&error];
sdk.pushJWT(addConnectorJWT)
sdk.PushJWT(joinTeamJWT)
JWTs for anonymous encryption
On your backend, example of creating JWTs for anonymous encryption:
import { SignJWT } from 'jose'
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
const JWTSecretId = 'JWT SHARED SECRET ID'
const JWTSecret = 'JWT SHARED SECRET'
const getKeysToken = await new SignJWT({
iss: JWTSecretId,
// No 'jti' for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
iat: Math.floor(Date.now() / 1000), // JWT valid only for 10 minutes. `Date.now()` returns the timestamp in milliseconds, this needs it in seconds.
scopes: [1], // PERMISSION_ANONYMOUS_FIND_KEYS
recipients: [sealdIdUser1, sealdIdUser2]
})
.setProtectedHeader({ alg: 'HS256' })
.sign(Buffer.from(JWTSecret, 'ascii'))
const encryptionToken = await new SignJWT({
iss: JWTSecretId,
jti: random(), // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Math.floor(Date.now() / 1000), // JWT valid only for 10 minutes. `Date.now()` returns the timestamp in milliseconds, this needs it in seconds.
scopes: [0], // PERMISSION_ANONYMOUS_CREATE_SESSION
recipients: [sealdIdUser1, sealdIdUser2],
owner: sealdIdUser1 // necessary for session creation
})
.setProtectedHeader({ alg: 'HS256' })
.sign(Buffer.from(JWTSecret, 'ascii'))
import JWT
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
let now = Date()
let headers = ["typ" : "JWT"]
let payloadGetKeys = ["iss" : JWTSharedSecretId,
// No 'jti' for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
"iat" : NSNumber(value: now.timeIntervalSince1970), // JWT valid only for 10 minutes.
"scopes": [1], // PERMISSION_ANONYMOUS_FIND_KEYS
"recipients": [sealdIdUser1, sealdIdUser2],
] as [String : Any]
let getKeysToken = JWT.encodePayload(payloadGetKeys, withSecret: JWTSharedSecret, withHeaders: headers, algorithm: JWTAlgorithm)
let payloadEncryption = ["iss" : JWTSharedSecretId,
"jti" : UUID().uuidString, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat" : NSNumber(value: now.timeIntervalSince1970), // JWT valid only for 10 minutes.
"scopes": [0], // PERMISSION_ANONYMOUS_CREATE_SESSION
"recipients": [sealdIdUser1, sealdIdUser2],
"owner": sealdIdUser1, // necessary for session creation
] as [String : Any]
let encryptionToken = JWT.encodePayload(payloadEncryption, withSecret: JWTSharedSecret, withHeaders: headers, algorithm: JWTAlgorithm)
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.security.Keys
import java.util.*
import javax.crypto.SecretKey
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
val JWTSecretId: String = "JWT SHARED SECRET ID"
val JWTSecret: String = "JWT SHARED SECRET"
JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.toByteArray())
val getKeysToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("scopes", listOf(1)) // PERMISSION_ANONYMOUS_FIND_KEYS
.claim("recipients", listOf(sealdIdUser1, sealdIdUser2))
// No 'jti' (`.setId`) for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
.setIssuer(JWTSharedSecretId)
.setIssuedAt(Date()) // JWT valid only for 10 minutes.
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact()
val encryptionToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("scopes", listOf(0)) // PERMISSION_ANONYMOUS_CREATE_SESSION
.claim("recipients", listOf(sealdIdUser1, sealdIdUser2))
.claim("owner", sealdIdUser1) // necessary for session creation
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSharedSecretId)
.setIssuedAt(Date()) // JWT valid only for 10 minutes.
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact()
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import java.util.UUID;
import javax.crypto.SecretKey;
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
final String JWTSecretId = "JWT SHARED SECRET ID";
final String JWTSecret = "JWT SHARED SECRET";
SecretKey JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.getBytes());
String getKeysToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("scopes", List.of(1)) // PERMISSION_ANONYMOUS_FIND_KEYS
.claim("recipients", List.of(sealdIdUser1, sealdIdUser2))
// No 'jti' (`.setId`) for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
.setIssuer(JWTSecretId)
.setIssuedAt(new Date()) // JWT valid only for 10 minutes.
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact();
String encryptionToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("scopes", List.of(0)) // PERMISSION_ANONYMOUS_CREATE_SESSION
.claim("recipients", List.of(sealdIdUser1, sealdIdUser2))
.claim("owner", sealdIdUser1) // necessary for session creation
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSecretId)
.setIssuedAt(new Date()) // JWT valid only for 10 minutes.
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact();
import jwt # This example uses the PyJWT library: https://pypi.org/project/PyJWT/
from datetime import datetime
# A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
jwt_shared_secret_id = "JWT SHARED SECRET ID"
jwt_shared_secret = "JWT SHARED SECRET"
get_keys_token = jwt.encode(
{
"iss": jwt_shared_secret_id,
// No 'jti' for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
"iat": datetime.now(), # JWT valid only for 10 minutes.
"scopes": [1], # PERMISSION_ANONYMOUS_FIND_KEYS
"recipients": [sealdIdUser1, sealdIdUser2],
},
jwt_shared_secret,
algorithm="HS256",
)
encryption_token = jwt.encode(
{
"iss": jwt_shared_secret_id,
"jti": str(uuid.uuid4()), # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat": datetime.now(), # JWT valid only for 10 minutes.
"scopes": [0], # PERMISSION_ANONYMOUS_CREATE_SESSION
"recipients": [sealdIdUser1, sealdIdUser2],
"owner": sealdIdUser1, # necessary for session creation
},
jwt_shared_secret,
algorithm="HS256",
)
package main
import (
"crypto/rand"
"encoding/base64"
"github.com/dgrijalva/jwt-go"
"time"
)
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
type ConnectorAdd struct {
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
}
type JWTPermissionScopes int
const (
PermissionAll JWTPermissionScopes = -1
PermissionAnonymousCreateSession JWTPermissionScopes = 0
PermissionAnonymousFindKeys JWTPermissionScopes = 1
PermissionAnonymousFindSigchain JWTPermissionScopes = 2
PermissionJoinTeam JWTPermissionScopes = 3
PermissionAddConnector JWTPermissionScopes = 4
PermissionAnonymousFindSymEncKey JWTPermissionScopes = 5
)
type CustomClaims struct {
Recipients []string `json:"recipients,omitempty"`
Owner string `json:"owner,omitempty"`
JoinTeam bool `json:"join_team,omitempty"`
ConnectorAdd ConnectorAdd `json:"connector_add,omitempty"`
SymEncKeys []string `json:"sym_enc_keys,omitempty"`
Scopes []JWTPermissionScopes `json:"scopes"`
jwt.StandardClaims
}
func randomString() string {
bytes := make([]byte, 32)
_, err := rand.Read(bytes)
if err != nil {
panic("Failed to generate a random string")
}
return base64.StdEncoding.EncodeToString(bytes)
}
func main() {
getKeysClaims := CustomClaims{
Scopes: []JWTPermissionScopes{PermissionAnonymousFindKeys},
Recipients: []string{sealdIdUser1, sealdIdUser2},
StandardClaims: jwt.StandardClaims{
// No 'jti' (`Id`) for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
Issuer: JWTSecretId,
IssuedAt: time.Now().Unix(),
},
}
getKeysToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, getKeysClaims).SignedString([]byte(JWTSecret))
encryptionClaims := CustomClaims{
Scopes: []JWTPermissionScopes{PermissionAnonymousCreateSession},
Recipients: []string{sealdIdUser1, sealdIdUser2},
Owner: sealdIdUser1, // necessary for session creation
StandardClaims: jwt.StandardClaims{
Id: randomString(),
Issuer: JWTSecretId,
IssuedAt: time.Now().Unix(),
},
}
encryptionToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, encryptionClaims).SignedString([]byte(JWTSecret))
}
require 'jose'
# A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
jwt_secret_id = "JWT SHARED SECRET ID"
jwt_secret = "JWT SHARED SECRET"
get_keys_claims = {
iss: jwt_secret_id,
// No 'jti' for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
iat: Time.now.to_i, # JWT valid only for 10 minutes.
scopes: [1], # PERMISSION_ANONYMOUS_FIND_KEYS
recipients: [sealdIdUser1, sealdIdUser2],
}
encryption_claims = {
iss: jwt_secret_id,
jti: SecureRandom.uuid, # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Time.now.to_i, # JWT valid only for 10 minutes.
scopes: [0], # PERMISSION_ANONYMOUS_CREATE_SESSION
recipients: [sealdIdUser1, sealdIdUser2],
owner: sealdIdUser1, // necessary for session creation
}
jwk = JOSE::JWK.from_oct(jwt_secret)
get_keys_token = JOSE::JWS.sign(jwk, get_keys_claims.to_json, { "alg" => "HS256" }).compact
encryption_token = JOSE::JWS.sign(jwk, encryption_claims.to_json, { "alg" => "HS256" }).compact
// using web-token/jwt-framework and web-token/jwt-core libraries
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Serializer\CompactSerializer;
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_KEYS` & `PERMISSION_ANONYMOUS_CREATE_SESSION`
$JWTSecretId = "JWT SHARED SECRET ID";
$JWTSecret = "JWT SHARED SECRET";
$random = bin2hex(random_bytes(16));
$algorithmManager = new AlgorithmManager([
new HS256(),
]);
$jwsBuilder = new JWSBuilder($algorithmManager);
$getKeysClaims = json_encode([
'iss' => $JWTSecretId,
// No 'jti' for the 'get keys' JWT: the request may be paginated, so done in multiple API calls
'iat' => time(), // JWT valid only for 10 minutes.
'scopes' => [1], // PERMISSION_ANONYMOUS_FIND_KEYS
'recipients' => [sealdIdUser1, sealdIdUser2],
]);
$encryptionClaims = json_encode([
'iss' => $JWTSecretId,
'jti' => $random, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
'iat' => time(), // JWT valid only for 10 minutes.
'scopes' => [0], // PERMISSION_ANONYMOUS_CREATE_SESSION
'recipients' => [sealdIdUser1, sealdIdUser2],
'owner' => sealdIdUser1, // necessary for session creation
]);
$jwk = JWKFactory::createFromSecret(
$JWTSecret,
[
'alg' => 'HS256',
'use' => 'sig'
]
);
$getKeysJws = $jwsBuilder
->create()
->withPayload($getKeysClaims)
->addSignature($jwk, ['alg' => 'HS256'])
->build();
$getKeysToken = (new CompactSerializer())->serialize($getKeysJws, 0);
$encryptionJws = $jwsBuilder
->create()
->withPayload($encryptionClaims)
->addSignature($jwk, ['alg' => 'HS256'])
->build();
$getKeysToken = (new CompactSerializer())->serialize($encryptionJws, 0);
JWT usage, client-side:
const encryptedFile = await anonymousSDK.encrypt({
encryptionToken,
sealdIds: [sealdIdUser1, sealdIdUser2],
clearFile,
filename: 'test.txt'
})
sessionId, encrypted, err := anonymousSDK.encrypt(
signedToken,
signedToken,
[]string{sealdIdUser1, sealdIdUser2},
clearText,
"test.txt"
)
JWT to retrieve a session anonymously via a SymEncKey
On your backend, example of creating a JWTs to retrieve an EncryptionSession anonymously via a SymEncKey:
import { SignJWT } from 'jose'
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
const JWTSecretId = 'JWT SHARED SECRET ID'
const JWTSecret = 'JWT SHARED SECRET'
const token = new SignJWT({
iss: JWTSecretId,
jti: random(), // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Math.floor(Date.now() / 1000), // JWT valid only for 10 minutes. `Date.now()` returns the timestamp in milliseconds, this needs it in seconds.
scopes: [5], // PERMISSION_ANONYMOUS_FIND_SYMENCKEY
sym_enc_keys: [symEncKeyId] // ID of the SymEncKey that will be used to retrieve the session.
})
.setProtectedHeader({ alg: 'HS256' })
const retrieveSessionToken = await token.sign(Buffer.from(JWTSecret, 'ascii'))
import JWT
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
let now = Date()
let headers = ["typ" : "JWT"]
let payload = ["iss" : JWTSharedSecretId,
"jti" : UUID().uuidString, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat" : NSNumber(value: now.timeIntervalSince1970), // JWT valid only for 10 minutes.
"scopes": [5], // PERMISSION_ANONYMOUS_FIND_SYMENCKEY
"sym_enc_keys": [symEncKeyId], // ID of the SymEncKey that will be used to retrieve the session.
] as [String : Any]
let retrieveSessionToken = JWT.encodePayload(payload, withSecret: JWTSharedSecret, withHeaders: headers, algorithm: JWTAlgorithm)
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.SignatureAlgorithm
import io.jsonwebtoken.security.Keys
import java.util.*
import javax.crypto.SecretKey
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
val JWTSecretId: String = "JWT SHARED SECRET ID"
val JWTSecret: String = "JWT SHARED SECRET"
JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.toByteArray())
val date = Date()
val expiryDate = Date(date.time + 2 * 60 * 60 * 1000)
val retrieveSessionToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("join_team", true)
.claim("scopes", listOf(5)) // PERMISSION_ANONYMOUS_FIND_SYMENCKEY
.claim("sym_enc_keys", listOf(symEncKeyId)) // ID of the SymEncKey that will be used to retrieve the session.
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSharedSecretId)
.setIssuedAt(date) // JWT valid only for 10 minutes.
.setExpiration(expiryDate)
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact()
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
import java.util.UUID;
import javax.crypto.SecretKey;
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
final String JWTSecretId = "JWT SHARED SECRET ID";
final String JWTSecret = "JWT SHARED SECRET";
SecretKey JWTSecretKey = Keys.hmacShaKeyFor(JWTSecret.getBytes());
Date date = new Date();
Date expiryDate = new Date(date.getTime() + 2 * 60 * 60 * 1000);
String retrieveSessionToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("typ", "JWT")
.claim("scopes", List.of(5)) // PERMISSION_ANONYMOUS_FIND_SYMENCKEY
.claim("sym_enc_keys", List.of(symEncKeyId)) // ID of the SymEncKey that will be used to retrieve the session.
.setId(UUID.randomUUID().toString()) // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
.setIssuer(JWTSecretId)
.setIssuedAt(date) // JWT valid only for 10 minutes.
.setExpiration(expiryDate)
.signWith(JWTSecretKey, SignatureAlgorithm.HS256)
.compact();
import jwt # This example uses the PyJWT library: https://pypi.org/project/PyJWT/
from datetime import datetime
# A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
jwt_shared_secret_id = "JWT SHARED SECRET ID"
jwt_shared_secret = "JWT SHARED SECRET"
retrieve_session_token = jwt.encode(
{
"iss": jwt_shared_secret_id,
"jti": str(uuid.uuid4()), # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
"iat": datetime.now(), # JWT valid only for 10 minutes
"scopes": [5], # PERMISSION_ANONYMOUS_FIND_SYMENCKEY
"sym_enc_keys": [sym_enc_key_id] # ID of the SymEncKey that will be used to retrieve the session.
},
jwt_shared_secret,
algorithm="HS256",
)
package main
import (
"crypto/rand"
"encoding/base64"
"github.com/dgrijalva/jwt-go"
"time"
)
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
const JWTSecretId = "JWT SHARED SECRET ID"
const JWTSecret = "JWT SHARED SECRET"
type ConnectorAdd struct {
Value string `json:"value,omitempty"`
Type string `json:"type,omitempty"`
}
type JWTPermissionScopes int
const (
PermissionAll JWTPermissionScopes = -1
PermissionAnonymousCreateSession JWTPermissionScopes = 0
PermissionAnonymousFindKeys JWTPermissionScopes = 1
PermissionAnonymousFindSigchain JWTPermissionScopes = 2
PermissionJoinTeam JWTPermissionScopes = 3
PermissionAddConnector JWTPermissionScopes = 4
PermissionAnonymousFindSymEncKey JWTPermissionScopes = 5
)
type CustomClaims struct {
Recipients []string `json:"recipients,omitempty"`
Owner string `json:"owner,omitempty"`
JoinTeam bool `json:"join_team,omitempty"`
ConnectorAdd ConnectorAdd `json:"connector_add,omitempty"`
SymEncKeys []string `json:"sym_enc_keys,omitempty"`
Scopes []JWTPermissionScopes `json:"scopes"`
jwt.StandardClaims
}
func randomString() string {
bytes := make([]byte, 32)
_, err := rand.Read(bytes)
if err != nil {
panic("Failed to generate a random string")
}
return base64.StdEncoding.EncodeToString(bytes)
}
func main() {
claims := CustomClaims{
Scopes: []JWTPermissionScopes{PermissionAnonymousFindSymEncKey},
SymEncKeys: []string{symEncKeyId},
StandardClaims: jwt.StandardClaims{
Id: randomString(),
Issuer: JWTSecretId,
IssuedAt: time.Now().Unix(),
},
}
retrieveSessionToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(JWTSecret))
}
require 'jose'
# A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
jwt_secret_id = "JWT SHARED SECRET ID"
jwt_secret = "JWT SHARED SECRET"
payload = {
iss: jwt_secret_id,
jti: SecureRandom.uuid, # So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
iat: Time.now.to_i, # JWT valid only for 10 minutes.
scopes: [5], # PERMISSION_ANONYMOUS_FIND_SYMENCKEY
sym_enc_keys: [sym_enc_key_id] # ID of the SymEncKey that will be used to retrieve the session.
}
jwk = JOSE::JWK.from_oct(jwt_secret)
jws = JOSE::JWS.sign(jwk, payload.to_json, { "alg" => "HS256" })
retrieveSessionToken = jws.compact
// using web-token/jwt-framework and web-token/jwt-core libraries
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\Algorithm\HS256;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Serializer\CompactSerializer;
// A JWT secret that has `PERMISSION_ANONYMOUS_FIND_SYMENCKEY`
$JWTSecretId = "JWT SHARED SECRET ID";
$JWTSecret = "JWT SHARED SECRET";
$random = bin2hex(random_bytes(16));
$algorithmManager = new AlgorithmManager([
new HS256(),
]);
$jwsBuilder = new JWSBuilder($algorithmManager);
$payload = json_encode([
'iss' => $JWTSecretId,
'jti' => $random, // So the JWT is only usable once. The `random` generates a random string, with enough entropy to never repeat : a UUIDv4 would be a good choice.
'iat' => time(), // JWT valid only for 10 minutes.
'scopes' => [5], // PERMISSION_ANONYMOUS_FIND_SYMENCKEY
'sym_enc_keys' => [symEncKeyId], // ID of the SymEncKey that will be used to retrieve the session.
]);
$jwk = JWKFactory::createFromSecret(
$JWTSecret,
[
'alg' => 'HS256',
'use' => 'sig'
]
);
$jws = $jwsBuilder
->create()
->withPayload($payload)
->addSignature($jwk, ['alg' => 'HS256'])
->build();
$serializer = new CompactSerializer();
$retrieveSessionToken = $serializer->serialize($jws, 0);
JWT usage, client-side:
const encryptedFile = await anonymousSDK.retrieveEncryptionSession({
appId,
retrieveSessionToken,
sessionId,
symEncKeyId,
symEncKeyPassword
})