Momento tokens
トークンは、ユーザーセッションのような一時的な状況で使用されることを目的とした、短命でスコープが限定された値です。 ユーザーログインのようなソフトウェアライフサイクルイベントでは、セッションの標準的な期間だけ有効なトークンが発行されることがよくあります。
Momento トークンは、データプレーンにのみアクセスできます。つまり、有効なトークンを持つユーザは、キャッシュの作成、削除、フラッシュなどを行うことができません。また、新しいトークンを作成することもできません。
完全に特権化されたトークンを持つユーザーは、以下のアクションを実行できます:
- あらゆるキャッシュのキャッシュアイテムを追加/編集/削除する。
- 任意のキャッシュ内の任意のトピックをパブリッシュ、サブスクライブする。
- どのキャッシュでも、インクリメント API を使ってキャッシュの値を増やすことができます。
システム要件に基づいてトークンのアクセスを制限するのはあなた次第です。
トークンを作成する
APIキーを作成する手順とは異なり、トークンを作成する唯一の方法はコードから作成することです。Momentoコンソールから作成することはできません。
以下は、さまざまな権限でトークンを作成する例です:
- JavaScript
- Go
// Generate a token that allows all data plane APIs on all caches and topics.
const allDataRWTokenResponse = await authClient.generateApiKey(AllDataReadWrite, ExpiresIn.minutes(30));
switch (allDataRWTokenResponse.type) {
case GenerateApiKeyResponse.Success:
console.log('Generated an API key with AllDataReadWrite scope!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${allDataRWTokenResponse.apiKey.substring(0, 10)}`);
console.log(`Refresh token starts with: ${allDataRWTokenResponse.refreshToken.substring(0, 10)}`);
console.log(`Expires At: ${allDataRWTokenResponse.expiresAt.epoch()}`);
break;
case GenerateApiKeyResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with AllDataReadWrite scope: ${allDataRWTokenResponse.errorCode()}: ${allDataRWTokenResponse.toString()}`
);
}
// Generate a token that can only call read-only data plane APIs on a specific cache foo. No topic apis (publish/subscribe) are allowed.
const singleCacheROTokenResponse = await authClient.generateApiKey(
TokenScopes.cacheReadOnly('foo'),
ExpiresIn.minutes(30)
);
switch (singleCacheROTokenResponse.type) {
case GenerateApiKeyResponse.Success:
console.log('Generated an API key with read-only access to cache foo!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${singleCacheROTokenResponse.apiKey.substring(0, 10)}`);
console.log(`Refresh token starts with: ${singleCacheROTokenResponse.refreshToken.substring(0, 10)}`);
console.log(`Expires At: ${singleCacheROTokenResponse.expiresAt.epoch()}`);
break;
case GenerateApiKeyResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with single cache read-only scope: ${singleCacheROTokenResponse.errorCode()}: ${singleCacheROTokenResponse.toString()}`
);
}
// Generate a token that can call all data plane APIs on all caches. No topic apis (publish/subscribe) are allowed.
const allCachesRWTokenResponse = await authClient.generateApiKey(
TokenScopes.cacheReadWrite(AllCaches),
ExpiresIn.minutes(30)
);
switch (allCachesRWTokenResponse.type) {
case GenerateApiKeyResponse.Success:
console.log('Generated an API key with read-write access to all caches!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${allCachesRWTokenResponse.apiKey.substring(0, 10)}`);
console.log(`Refresh token starts with: ${allCachesRWTokenResponse.refreshToken.substring(0, 10)}`);
console.log(`Expires At: ${allCachesRWTokenResponse.expiresAt.epoch()}`);
break;
case GenerateApiKeyResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with all caches read-write scope: ${allCachesRWTokenResponse.errorCode()}: ${allCachesRWTokenResponse.toString()}`
);
}
// Generate a token that can call publish and subscribe on all topics within cache bar
const singleCacheAllTopicsRWTokenResponse = await authClient.generateApiKey(
TokenScopes.topicPublishSubscribe({name: 'bar'}, AllTopics),
ExpiresIn.minutes(30)
);
switch (singleCacheAllTopicsRWTokenResponse.type) {
case GenerateApiKeyResponse.Success:
console.log('Generated an API key with publish-subscribe access to all topics within cache bar!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${singleCacheAllTopicsRWTokenResponse.apiKey.substring(0, 10)}`);
console.log(`Refresh token starts with: ${singleCacheAllTopicsRWTokenResponse.refreshToken.substring(0, 10)}`);
console.log(`Expires At: ${singleCacheAllTopicsRWTokenResponse.expiresAt.epoch()}`);
break;
case GenerateApiKeyResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with read-write scope for all topics in a single cache: ${singleCacheAllTopicsRWTokenResponse.errorCode()}: ${singleCacheAllTopicsRWTokenResponse.toString()}`
);
}
// Generate a token that can only call subscribe on topic where_is_mo within cache mo_nuts
const oneCacheOneTopicRWTokenResponse = await authClient.generateApiKey(
TokenScopes.topicSubscribeOnly('mo_nuts', 'where_is_mo'),
ExpiresIn.minutes(30)
);
switch (oneCacheOneTopicRWTokenResponse.type) {
case GenerateApiKeyResponse.Success:
console.log('Generated an API key with subscribe-only access to topic where_is_mo within cache mo_nuts!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${oneCacheOneTopicRWTokenResponse.apiKey.substring(0, 10)}`);
console.log(`Refresh token starts with: ${oneCacheOneTopicRWTokenResponse.refreshToken.substring(0, 10)}`);
console.log(`Expires At: ${oneCacheOneTopicRWTokenResponse.expiresAt.epoch()}`);
break;
case GenerateApiKeyResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with read-write scope for single topic in a single cache: ${oneCacheOneTopicRWTokenResponse.errorCode()}: ${oneCacheOneTopicRWTokenResponse.toString()}`
);
}
// Generate a token with multiple permissions
const cachePermission1 = {
role: CacheRole.ReadWrite, // Managed role that grants access to read as well as write apis on caches
cache: 'acorns', // Scopes the access to a single cache named 'acorns'
};
const cachePermission2 = {
role: CacheRole.ReadOnly, // Managed role that grants access to only read data apis on caches
cache: AllCaches, // Built-in value for access to all caches in the account
};
const topicPermission1 = {
role: TopicRole.PublishSubscribe, // Managed role that grants access to subscribe as well as publish apis
cache: 'walnuts', // Scopes the access to a single cache named 'walnuts'
topic: 'mo_favorites', // Scopes the access to a single topic named 'mo_favorites' within cache 'walnuts'
};
const topicPermission2 = {
role: TopicRole.SubscribeOnly, // Managed role that grants access to only subscribe api
cache: AllCaches, // Built-in value for all cache(s) in the account.
topic: AllTopics, // Built-in value for access to all topics in the listed cache(s).
};
const permissions = {
permissions: [cachePermission1, cachePermission2, topicPermission1, topicPermission2],
};
const multiplePermsTokenResponse = await authClient.generateApiKey(permissions, ExpiresIn.minutes(30));
switch (multiplePermsTokenResponse.type) {
case GenerateApiKeyResponse.Success:
console.log('Generated an API key with multiple cache and topic permissions!');
// logging only a substring of the tokens, because logging security credentials is not advisable :)
console.log(`API key starts with: ${multiplePermsTokenResponse.apiKey.substring(0, 10)}`);
console.log(`Refresh token starts with: ${multiplePermsTokenResponse.refreshToken.substring(0, 10)}`);
console.log(`Expires At: ${multiplePermsTokenResponse.expiresAt.epoch()}`);
break;
case GenerateApiKeyResponse.Error:
throw new Error(
`An error occurred while attempting to call generateApiKey with multiple permissions: ${multiplePermsTokenResponse.errorCode()}: ${multiplePermsTokenResponse.toString()}`
);
}
// Generate a token that allows all data plane APIs on all caches and topics.
resp, err := authClient.GenerateApiKey(ctx, &momento.GenerateApiKeyRequest{
ExpiresIn: utils.ExpiresInMinutes(30),
Scope: momento.AllDataReadWrite,
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateApiKeySuccess:
log.Printf("Successfully generated an API key with AllDataReadWrite scope!\n")
log.Printf("API key expires at: %d\n", r.ExpiresAt.Epoch())
}
// Generate a token that can only call read-only data plane APIs on a specific cache foo. No topic apis (publish/subscribe) are allowed.
resp, err = authClient.GenerateApiKey(ctx, &momento.GenerateApiKeyRequest{
ExpiresIn: utils.ExpiresInMinutes(30),
Scope: momento.CacheReadOnly(momento.CacheName{Name: "foo"}),
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateApiKeySuccess:
log.Printf("Successfully generated an API key with read-only access to cache foo!\n")
log.Printf("API key expires at: %d\n", r.ExpiresAt.Epoch())
}
// Generate a token that can call all data plane APIs on all caches. No topic apis (publish/subscribe) are allowed.
resp, err = authClient.GenerateApiKey(ctx, &momento.GenerateApiKeyRequest{
ExpiresIn: utils.ExpiresInMinutes(30),
Scope: momento.CacheReadWrite(momento.AllCaches{}),
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateApiKeySuccess:
log.Printf("Successfully generated an API key with read-write access to all caches!\n")
log.Printf("API key expires at: %d\n", r.ExpiresAt.Epoch())
}
// Generate a token that can call publish and subscribe on all topics within cache bar
resp, err = authClient.GenerateApiKey(ctx, &momento.GenerateApiKeyRequest{
ExpiresIn: utils.ExpiresInMinutes(30),
Scope: momento.TopicPublishSubscribe(momento.CacheName{Name: "bar"}, momento.AllTopics{}),
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateApiKeySuccess:
log.Printf("Successfully generated an API key publish-subscribe access to all topics within cache bar!\n")
log.Printf("API key expires at: %d\n", r.ExpiresAt.Epoch())
}
// Generate a token that can only call subscribe on topic where_is_mo within cache mo_nuts
resp, err = authClient.GenerateApiKey(ctx, &momento.GenerateApiKeyRequest{
ExpiresIn: utils.ExpiresInMinutes(30),
Scope: momento.TopicSubscribeOnly(momento.CacheName{Name: "mo_nuts"}, momento.TopicName{Name: "where_is_mo"}),
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateApiKeySuccess:
log.Printf("Successfully generated an API key with subscribe-only access to topic where_is_mo within cache mo_nuts!\n")
log.Printf("API key expires at: %d\n", r.ExpiresAt.Epoch())
}
// Generate a token with multiple permissions
cachePermission1 := momento.CachePermission{
Cache: momento.CacheName{Name: "acorns"}, // Scopes the access to a single cache named 'acorns'
Role: momento.ReadWrite, // Managed role that grants access to read as well as write apis on caches
}
cachePermission2 := momento.CachePermission{
Cache: momento.AllCaches{}, // Built-in value for access to all caches in the account
Role: momento.ReadOnly, // Managed role that grants access to only read data apis on caches
}
topicPermission1 := momento.TopicPermission{
Cache: momento.CacheName{Name: "walnuts"}, // Scopes the access to a single cache named 'walnuts'
Topic: momento.TopicName{Name: "mo_favorites"}, // Scopes the access to a single topic named 'mo_favorites' within cache 'walnuts'
Role: momento.PublishSubscribe, // Managed role that grants access to subscribe as well as publish apis
}
topicPermission2 := momento.TopicPermission{
Cache: momento.AllCaches{}, // Built-in value for all cache(s) in the account.
Topic: momento.AllTopics{}, // Built-in value for access to all topics in the listed cache(s).
Role: momento.SubscribeOnly, // Managed role that grants access to only subscribe api
}
permissions := []momento.Permission{
cachePermission1, cachePermission2, topicPermission1, topicPermission2,
}
resp, err = authClient.GenerateApiKey(ctx, &momento.GenerateApiKeyRequest{
ExpiresIn: utils.ExpiresInMinutes(30),
Scope: momento.Permissions{
Permissions: permissions,
},
})
if err != nil {
panic(err)
}
switch r := resp.(type) {
case *auth_resp.GenerateApiKeySuccess:
log.Printf("Successfully generated an API key with multiple cache and topic permissions!\n")
log.Printf("API key expires at: %d\n", r.ExpiresAt.Epoch())
}
トークン作成の詳細については、APIリファレンスページを参照してください。
有効期限
Momento トークンには有効期限が必要です。トークンの最大有効期限は1時間です。トークンの有効期限が切れると、新しいトークンを作成する必要があります。
有効期限が切れたトークンでmomentoを呼び出しても、提供された認証情報がサービスに接続できなかったことを示す AUTHENTICATION_ERROR
応答が返されます。
トークンはリフレッシュできません。そのため、トークンの有効期限が切れると、永久に使えなくなります。セッションを継続する場合は、新しいものを作成して発行する責任があります。
ユースケース
これらのトークンは、以下のユースケースに最適です:
- フロントエンド開発にMomentoを使用する
- IoT デバイスとの通信
- 特定のリソースへの一時的なアクセス権の発行
- ログイン時にユーザーに認証情報を提供する
データ制限
トークンの一般的な使用例は、リソースの小さなサブセットのみにアクセスを制限することです。 トークンを読み取り専用アクセスで提供するように機能を制限できるだけでなく、個々のキャッシュアイテムやトピックにスコープすることもできます。
データ制限で何ができるかを完全に理解するには、permissions pageをチェックしてください。