Momento tokens for short-lived permissions
Tokens are short-lived, limited-scope values intended to be used in temporary situations like a user's session. Software lifecycle events like a user login often result in the issuing of a token only valid for the duration of that session.
Not sure if you should be using an API key
or a token
? Check out our authentication page for all the details!
Tokens cannot be refreshed. So once it expires, it's gone forever. You'll be responsible for creating and issuing a new one if the session continues.
A Momento token allows access to data plane API operations only. The user is unable to do control plane operations like creating, deleting, or flushing a cache.
A user with a fully privileged token will be able to perform the following actions:
- Add/edit/delete cache items in any cache
- Publish and subscribe to any topic in any cache
- Increment cache values via the increment API in any cache
It's up to you to limit the access of a token based on your system requirements.
Creating a token
Unlike our API keys, the only way to create a token is through code. You cannot create them through the Momento console.
Below are some examples to create tokens with different sets of permissions:
- JavaScript
- Python
- Java
- Go
- C#
// Generate a disposable token with read-write access to a specific key in one cache
const oneKeyOneCacheToken = await authClient.generateDisposableToken(
DisposableTokenScopes.cacheKeyReadWrite('squirrels', 'mo'),
ExpiresIn.minutes(30)
);
switch (oneKeyOneCacheToken.type) {
case GenerateDisposableTokenResponse.Success:
console.log('Generated a disposable API key with access to the "mo" key in the "squirrels" cache!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${oneKeyOneCacheToken.authToken.substring(0, 10)}`);
console.log(`Expires At: ${oneKeyOneCacheToken.expiresAt.epoch()}`);
break;
case GenerateDisposableTokenResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with disposable token scope: ${oneKeyOneCacheToken.errorCode()}: ${oneKeyOneCacheToken.toString()}`
);
}
// Generate a disposable token with read-write access to a specific key prefix in all caches
const keyPrefixAllCachesToken = await authClient.generateDisposableToken(
DisposableTokenScopes.cacheKeyPrefixReadWrite(AllCaches, 'squirrel'),
ExpiresIn.minutes(30)
);
switch (keyPrefixAllCachesToken.type) {
case GenerateDisposableTokenResponse.Success:
console.log('Generated a disposable API key with access to keys prefixed with "squirrel" in all caches!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${keyPrefixAllCachesToken.authToken.substring(0, 10)}`);
console.log(`Expires At: ${keyPrefixAllCachesToken.expiresAt.epoch()}`);
break;
case GenerateDisposableTokenResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with disposable token scope: ${keyPrefixAllCachesToken.errorCode()}: ${keyPrefixAllCachesToken.toString()}`
);
}
// Generate a disposable token with read-only access to all topics in one cache
const allTopicsOneCacheToken = await authClient.generateDisposableToken(
TokenScopes.topicSubscribeOnly('squirrel', AllTopics),
ExpiresIn.minutes(30)
);
switch (allTopicsOneCacheToken.type) {
case GenerateDisposableTokenResponse.Success:
console.log('Generated a disposable API key with access to all topics in the "squirrel" cache!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${allTopicsOneCacheToken.authToken.substring(0, 10)}`);
console.log(`Expires At: ${allTopicsOneCacheToken.expiresAt.epoch()}`);
break;
case GenerateDisposableTokenResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with disposable token scope: ${allTopicsOneCacheToken.errorCode()}: ${allTopicsOneCacheToken.toString()}`
);
}
// Generate a disposable token with write-only access to a single topic in all caches
const oneTopicAllCachesToken = await authClient.generateDisposableToken(
TokenScopes.topicPublishOnly(AllCaches, 'acorn'),
ExpiresIn.minutes(30)
);
switch (oneTopicAllCachesToken.type) {
case GenerateDisposableTokenResponse.Success:
console.log('Generated a disposable API key with access to all topics in the "squirrel" cache!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${oneTopicAllCachesToken.authToken.substring(0, 10)}`);
console.log(`Expires At: ${oneTopicAllCachesToken.expiresAt.epoch()}`);
break;
case GenerateDisposableTokenResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with disposable token scope: ${oneTopicAllCachesToken.errorCode()}: ${oneTopicAllCachesToken.toString()}`
);
}
response = await auth_client.generate_disposable_token(
DisposableTokenScopes.topic_publish_subscribe("a-cache", "a-topic"),
ExpiresIn.minutes(5),
DisposableTokenProps(token_id="a-token-id"),
)
match response:
case GenerateDisposableToken.Success():
print("Successfully generated a disposable token")
case GenerateDisposableToken.Error() as error:
print(f"Error generating a disposable token: {error.message}")
final GenerateDisposableTokenResponse response =
authClient
.generateDisposableTokenAsync(
DisposableTokenScopes.cacheKeyReadWrite("squirrel", "mo"), ExpiresIn.minutes(30))
.join();
if (response instanceof GenerateDisposableTokenResponse.Success success) {
System.out.println("Successfully generated the disposable token: " + success.authToken());
} else if (response instanceof GenerateDisposableTokenResponse.Error error) {
throw new RuntimeException(
"An error occurred while attempting to generate disposable token: "
+ error.getErrorCode(),
error);
}
tokenId := "a token id"
resp, err := authClient.GenerateDisposableToken(ctx, &momento.GenerateDisposableTokenRequest{
ExpiresIn: utils.ExpiresInSeconds(10),
Scope: momento.TopicSubscribeOnly(
momento.CacheName{Name: "a cache"},
momento.TopicName{Name: "a topic"},
),
Props: momento.DisposableTokenProps{
TokenId: &tokenId,
},
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateDisposableTokenSuccess:
log.Printf("Successfully generated a disposable token for endpoint=%s with tokenId=%s\n", r.Endpoint, tokenId)
}
// Generate a disposable token with read-write access to a specific key in one cache
var oneKeyOneCacheToken = await authClient.GenerateDisposableTokenAsync(
DisposableTokenScopes.CacheKeyReadWrite("squirrels", "mo"),
ExpiresIn.Minutes(30)
);
if (oneKeyOneCacheToken is GenerateDisposableTokenResponse.Success token1)
{
// logging only a substring of the tokens, because logging security credentials is not advisable :)
Console.WriteLine("The generated disposable token starts with: " + token1.AuthToken.Substring(0, 10));
Console.WriteLine("The token expires at (epoch timestamp): " + token1.ExpiresAt.Epoch());
}
else if (oneKeyOneCacheToken is GenerateDisposableTokenResponse.Error err)
{
Console.WriteLine("Error generating disposable token: " + err.Message);
}
// Generate a disposable token with read-write access to a specific key prefix in all caches
var keyPrefixAllCachesToken = await authClient.GenerateDisposableTokenAsync(
DisposableTokenScopes.CacheKeyPrefixReadWrite(CacheSelector.AllCaches, "squirrel"),
ExpiresIn.Minutes(30)
);
if (keyPrefixAllCachesToken is GenerateDisposableTokenResponse.Success token2)
{
// logging only a substring of the tokens, because logging security credentials is not advisable :)
Console.WriteLine("The generated disposable token starts with: " + token2.AuthToken.Substring(0, 10));
Console.WriteLine("The token expires at (epoch timestamp): " + token2.ExpiresAt.Epoch());
}
else if (keyPrefixAllCachesToken is GenerateDisposableTokenResponse.Error err)
{
Console.WriteLine("Error generating disposable token: " + err.Message);
}
// Generate a disposable token with read-only access to all topics in one cache
var allTopicsOneCacheToken = await authClient.GenerateDisposableTokenAsync(
DisposableTokenScopes.TopicSubscribeOnly("squirrel", TopicSelector.AllTopics),
ExpiresIn.Minutes(30)
);
if (allTopicsOneCacheToken is GenerateDisposableTokenResponse.Success token3)
{
// logging only a substring of the tokens, because logging security credentials is not advisable :)
Console.WriteLine("The generated disposable token starts with: " + token3.AuthToken.Substring(0, 10));
Console.WriteLine("The token expires at (epoch timestamp): " + token3.ExpiresAt.Epoch());
}
else if (allTopicsOneCacheToken is GenerateDisposableTokenResponse.Error err)
{
Console.WriteLine("Error generating disposable token: " + err.Message);
}
// Generate a disposable token with write-only access to a single topic in all caches
var oneTopicAllCachesToken = await authClient.GenerateDisposableTokenAsync(
DisposableTokenScopes.TopicPublishOnly(CacheSelector.AllCaches, "acorn"),
ExpiresIn.Minutes(30)
);
if (oneTopicAllCachesToken is GenerateDisposableTokenResponse.Success token4)
{
// logging only a substring of the tokens, because logging security credentials is not advisable :)
Console.WriteLine("The generated disposable token starts with: " + token4.AuthToken.Substring(0, 10));
Console.WriteLine("The token expires at (epoch timestamp): " + token4.ExpiresAt.Epoch());
}
else if (oneTopicAllCachesToken is GenerateDisposableTokenResponse.Error err)
{
Console.WriteLine("Error generating disposable token: " + err.Message);
}
For detailed information on creating a token, please refer to the API reference page.
Expiration
Momento tokens are required to have an expiration time. The maximum expiration time for a token is 1 hour. When the token expiration time elapses, you will be required to create a new one.
If you attempt to make a call with an expired token, you will receive a AUTHENTICATION_ERROR
response indicating the provided credentials could not connect to the service.
Tokens cannot be refreshed. So once it expires, it's gone forever. You'll be responsible for creating and issuing a new one if the session continues.
Use cases
These tokens are a great fit for the following use cases:
- Using Momento for front-end development
- Communicating with IoT devices
- Issuing temporary access to specific resources
- Providing credentials to users on login
Data restriction
A common use case for a token is to limit access to only a small subset of resources. Not only can you limit capabilities, like providing a token with read-only access, but you can also scope it to individual cache items or topics.
To get a full understanding of what you can do with data restriction, check out our permissions page.