Crates.io | dynamic-token |
lib.rs | dynamic-token |
version | 0.1.7 |
source | src |
created_at | 2024-03-10 21:30:28.416122 |
updated_at | 2024-03-15 20:53:02.014738 |
description | Encodes and evaluates a time-sensitive dynamic authentication token based on shared API key, a timestamp, some random noise characters and an optional UUID |
homepage | |
repository | https://github.com/neilg63/dynamic-token |
max_upload_size | |
id | 1168974 |
size | 27,160 |
Time-sensitive dynamic tokens authenticate client applications with the server via a shared API key, timestamp, some random characters and an optional UUID (Universally Unique IDentifier) for a second stage of authorisation. Unlike JWT tokens, dynamic tokens are not reusable and do not validate or maintain a user's session. They serve as a first line of defence against unauthorised requests.
They may supplement JWT tokens as an extra security layer. As dynamic tokens change every millisecond with randomised shuffling of characters, they cannot be easily deconstructed without detailed knowledge of the algorithm.
If the decoded timestamp falls outside a narrow time range, by default 5 minutes, it will be rejected. This allows for reltively long request times and minor discrepancies in system clock times. However, the only time that matters is the initial request, not the time it takes to process and send the response. In theory, the same token would work for this limited period.
As base-64 encoding is very common, it would be possible to decode a dynamic token and through brute force guess which parts may be the shared API token by comparing two generated dynamic tokens via a standard base-64 decoding function. However, potential hackers would still need to guess how to decode and reassemble the timestamp and exclude random control characters.
At a basic level, dynamic tokens only require a shared API key. Both the server and the client must use compatibile dynamic token algorithms. The Rust crate is ideal for server to server communication as an HTTP header added and authenticated as middleware. The dynamic token does not expose the API key or timestamp in an easily hackable format. Even if a dynamic token is intercepted, it has a limited lifetime.
let options = AuthOptions::new("my_cryptic_shared_api_key").set_tolerance_secs(15);
This will work if the client and server clocks are synchronised, share the same API key and the initial HTTP request does not take longer than 15 seconds. Short time-outs help prevent DDOS attacks
let options = AuthOptions::new("my_cryptic_shared_api_key").set_tolerance_mins(5);
In practice, allowing times over 5 minutes is not recommended as large uploads will reach the server in packets and the HTTP header with the token would only be authenticated at the beginning of the file transfer process.
let options = AuthOptions::new("my_cryptic_shared_api_key").set_rand_char_str("%@,.?£$");
The server and client must share the same API key and custom split characters. These may be any valid utf-8 characters except for letters, numerals or underscores (_). These characters will be base-64-encoded and thus add to the randomness of the encoded token.
Please note the random character sequence will be invalid if it contains Chinese ideograms, but emojis and mathematical symbols are fine as long as they are not interpreted as Greek letters.
A UUID is a universal unique identifier may be any hexadecimal string at least 24 characters in length. The encoder function strips any hyphens. These are used many common data systems such as MongoDB and may be generated in other database systems such MySQL or PostGres that traditionally use decimal integers as primary keys.
let options = AuthOptions::new("api_key_with_an_emoji_😎☀︎").check_uuid(true);
// The client generates a key that may be added to the request header
let to_key = to_dynamic_key(&options, Some("5d00012de43dcd165cceb295"));
// The sever decodes the key using the shared API key and control characters
// You may use different options for different endpoints
let result = from_dynamic_key(&to_key, &options);
if result.valid() {
// We have a valid result with a hexadecimal string that may be a UUID
// Let's see if it matches a user in our database
if let Some(user) = fetch_user_by_id(&result.uuid()).await {
if user.is_admin() {
// Ok proceed
} else {
// not authorised for this endpoint
}
} else {
// user not found
}
}
If UUIDs are required, the client must send a valid hexadecimal UUID. The from_dynamic_token() function will decode the injected UUID and validate only its presence and format. Any hexadecimal string with at least 24 characters is valid, but 32 character strings are also supported. You can use the extracted UUID for subsequent user-specific authenticatiom. If the client sends a UUID, but the server does not require it, the UUID component will be ignored.
This is an alpha release and will accompany Node JS and Web versions of the same utility.
Version 1.5