Skip to main content

Overview

The ScyllaDB Rust Driver supports multiple authentication methods to secure connections to your database cluster. You can use the built-in plain text authenticator for username/password authentication, or implement a custom authenticator for more advanced authentication schemes.

Plain Text Authentication

The simplest and most common authentication method is plain text authentication using a username and password.

Using the user() Method

The easiest way to set up authentication is using the user() method on SessionBuilder:
use scylla::client::session_builder::SessionBuilder;
use scylla::client::session::Session;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9042")
        .user("cassandra", "cassandra")
        .build()
        .await?;

    // Now you can use the authenticated session
    Ok(())
}

PlainTextAuthenticator

Under the hood, the user() method creates a PlainTextAuthenticator. You can also create one explicitly:
use scylla::authentication::PlainTextAuthenticator;
use std::sync::Arc;

let session: Session = SessionBuilder::new()
    .known_node("127.0.0.1:9042")
    .authenticator_provider(Arc::new(PlainTextAuthenticator::new(
        "cassandra".to_string(),
        "cassandra".to_string(),
    )))
    .build()
    .await?;

Default Credentials

ScyllaDB and Cassandra come with default credentials:
  • Username: cassandra
  • Password: cassandra
Always change default credentials in production environments. Using default credentials is a significant security risk.

Custom Authentication

For advanced authentication scenarios, you can implement custom authenticators by implementing the AuthenticatorProvider and AuthenticatorSession traits.

AuthenticatorProvider Trait

The AuthenticatorProvider trait is a factory for creating authenticator sessions:
use async_trait::async_trait;
use scylla::authentication::{AuthenticatorProvider, AuthenticatorSession, AuthError};

#[async_trait]
pub trait AuthenticatorProvider: Sync + Send {
    /// Returns initial response and an AuthenticatorSession
    /// if authentication is required by the server.
    async fn start_authentication_session(
        &self,
        authenticator_name: &str,
    ) -> Result<(Option<Vec<u8>>, Box<dyn AuthenticatorSession>), AuthError>;
}

AuthenticatorSession Trait

The AuthenticatorSession trait handles the authentication protocol:
use async_trait::async_trait;

#[async_trait]
pub trait AuthenticatorSession: Send + Sync {
    /// Handle an authentication challenge initiated by the server.
    /// The token parameter contains authentication protocol-specific information.
    async fn evaluate_challenge(
        &mut self,
        token: Option<&[u8]>,
    ) -> Result<Option<Vec<u8>>, AuthError>;

    /// Handle the success phase of the authentication exchange.
    /// The token parameter may contain finalization information.
    async fn success(&mut self, token: Option<&[u8]>) -> Result<(), AuthError>;
}

Complete Custom Authenticator Example

Here’s a complete example of implementing a custom authenticator:
use std::sync::Arc;
use scylla::client::session_builder::SessionBuilder;
use scylla::client::session::Session;
use async_trait::async_trait;
use scylla::authentication::{AuthenticatorProvider, AuthenticatorSession, AuthError};

// Define the authenticator session
struct CustomAuthenticator {
    // Add any state needed for authentication
}

#[async_trait]
impl AuthenticatorSession for CustomAuthenticator {
    async fn evaluate_challenge(
        &mut self,
        token: Option<&[u8]>,
    ) -> Result<Option<Vec<u8>>, AuthError> {
        // Implement your challenge-response logic here
        // Return None if no response is needed
        // Return Some(response) to send a response to the server
        Ok(None)
    }

    async fn success(&mut self, token: Option<&[u8]>) -> Result<(), AuthError> {
        // Handle successful authentication
        // You can validate the success token here
        Ok(())
    }
}

// Define the authenticator provider
struct CustomAuthenticatorProvider {
    // Add configuration needed to create authenticators
}

#[async_trait]
impl AuthenticatorProvider for CustomAuthenticatorProvider {
    async fn start_authentication_session(
        &self,
        authenticator_name: &str,
    ) -> Result<(Option<Vec<u8>>, Box<dyn AuthenticatorSession>), AuthError> {
        // Check the authenticator name if needed
        // Return initial response and the session
        Ok((None, Box::new(CustomAuthenticator {})))
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9042")
        .authenticator_provider(Arc::new(CustomAuthenticatorProvider {}))
        .build()
        .await?;

    Ok(())
}

Authentication Error Handling

Authentication errors are represented as String values:
pub type AuthError = String;
When authentication fails, you should return a descriptive error message:
#[async_trait]
impl AuthenticatorSession for MyAuthenticator {
    async fn evaluate_challenge(
        &mut self,
        token: Option<&[u8]>,
    ) -> Result<Option<Vec<u8>>, AuthError> {
        if token.is_none() {
            return Err("Expected authentication token from server".to_string());
        }
        // Process the token...
        Ok(Some(response))
    }
}

Supported Authenticators

ScyllaDB and Cassandra support several authenticator types:
pub enum Authenticator {
    AllowAllAuthenticator,
    PasswordAuthenticator,
    CassandraPasswordAuthenticator,
    CassandraAllowAllAuthenticator,
    ScyllaTransitionalAuthenticator,
}
  • AllowAllAuthenticator: No authentication required (default for development)
  • PasswordAuthenticator: ScyllaDB’s password authenticator
  • CassandraPasswordAuthenticator: Cassandra’s password authenticator
  • ScyllaTransitionalAuthenticator: ScyllaDB’s transitional authenticator for gradual migration

Complete Example with Keyspace

Here’s a complete example combining authentication with other session configuration:
use scylla::client::session_builder::SessionBuilder;
use scylla::client::session::Session;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let session: Session = SessionBuilder::new()
        .known_node("127.0.0.1:9042")
        .user("cassandra", "cassandra")
        .use_keyspace("my_keyspace", false)
        .build()
        .await?;

    // Create a table in the authenticated session
    session.query_unpaged(
        "CREATE TABLE IF NOT EXISTS users (id int PRIMARY KEY, name text)",
        &[],
    ).await?;

    // Insert data
    session.query_unpaged(
        "INSERT INTO users (id, name) VALUES (?, ?)",
        (1, "Alice"),
    ).await?;

    println!("Successfully connected and executed queries with authentication");

    Ok(())
}

Security Best Practices

Important Security Considerations:
  1. Never commit credentials to source control - Use environment variables or secure configuration management
  2. Use TLS/SSL in production - Plain text authentication sends credentials over the network
  3. Change default passwords - Always change default credentials in any environment
  4. Use strong passwords - Follow your organization’s password policy
  5. Rotate credentials regularly - Implement a credential rotation strategy

Using Environment Variables

use std::env;

let username = env::var("SCYLLA_USERNAME")
    .expect("SCYLLA_USERNAME not set");
let password = env::var("SCYLLA_PASSWORD")
    .expect("SCYLLA_PASSWORD not set");

let session: Session = SessionBuilder::new()
    .known_node("127.0.0.1:9042")
    .user(username, password)
    .build()
    .await?;

See Also

TLS/SSL

Secure your connections with TLS encryption

Connection Overview

Learn about basic connection configuration

Build docs developers (and LLMs) love