Integrating Steemit Account Authentication into Your WebsitesteemCreated with Sketch.

in #webdesign13 hours ago (edited)

Integrating Steemit Account Authentication into Your Website

A month ago, I had a firm desire to create a project for interaction between Steemit users. At first, I wanted to make a marketplace for selling digital goods with the ability to pay in Steem. Then I changed my mind and the idea of a project where Steemit users could offer each other services for a fee in Steem, like freelance services, seemed more interesting to me. I even sketched out a draft version of such a site. But the further I progressed, the less time I had to properly work on it due to a heavy workload at my job. For now, I’ll limit myself to some technical guidance on how to integrate login via a Steemit account into a regular website. There are many ways to implement site authorization using PHP, and there’s no limit to the level of complexity. I’m not talking about login through existing accounts on other services like Google, Microsoft, Twitter, etc. This is about pure PHP. You can use cookies, sessions, or both — it all depends on your security requirements. Passwords can be stored in a database using MD5 encryption or AES. You can use double encryption and additional keys to increase password complexity. Login on a website can also be done without a password, just by entering a code sent to a registered email address or phone number.

 
In the past, I didn’t realize how efficient and convenient it could be to log into a website using a username and key from a Steemit account! I even regret not using all the advantages of the Steem blockchain earlier. To set up login using a Steemit account, you don’t need to worry about security or come up with tricks to protect yourself from being hacked.. All you need for login is to install the browser extensionb Steem Keychain and configure your code to properly connect to the account . Private keys are stored only in Keychain extension, and the site simply ask it to perform the required action without accessing the keys themselves. After successful login a cookie or session identifier is set, allowing the system to recognize the user. On the PHP side, a variable is created and used in different parts of the site to identify that it’s you.

I’ve prepared a detailed example that demonstrates how to work with a Steemit account and integrate it into a regular website.

The main login method on the site is through SteemKeychain, but as an alternative, I added the ability to use a private posting key. But don’t forget that entering a private key directly on a site is a highly undesirable practice. This login method is significantly less secure due to the risk of data interception, especially if the connection is not secure. Just keep that in mind.

After successful login, as a bonus, there's a demonstration of an additional script that allows sending Steem through a web page to any user on the Steem blockchain. This action is also performed using the SteemKeychain browser extension. Note that for the Steem transfer to work, your account added to Keychain must include your private active key.

Integrating Steemit Account Authentication into Your Website

Without it, the transfer simply won’t go through. Sending STEEM can also be done manually by entering the private active key directly into the browser. But this is strongly discouraged for security reasons, and I don’t intend to use this method.

Integrating Steemit Account Authentication into Your Website

The Steem sending mechanism works in such a way that the coins will be sent from the account that confirms the action in Keychain. That is, the case is considered when a user has multiple accounts added to a single Keychain.

The code is written in HTML and JavaScript markup and also includes a bit of PHP for successful login and saving cookies. Yes, cookies can be set using JavaScript, but with PHP it’s somehow easier and more understandable. I’ve added as many annotations as possible to the markup code so that there are no questions at various stages.

Before working with the script, it is necessary to connect the interface — steem_keychain.js, which will allow the web page to interact with Keychain. And for authorization using the private posting key, it is required to connect the steem.min.js library.

<?
/* --- Handle logout: delete cookie and redirect --- */
if (isset($_GET['logout'])) {
    setcookie('steem_user', '', time() - 3600, '/'); // Delete cookie
    header("Location: /"); // Redirect to homepage
    exit;
}

/* --- Handle login: set cookie when called with ?setcookie and POSTed login --- */
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['setcookie']) && !empty($_POST['login'])) {
    $login = strtolower(trim($_POST['login']));
    setcookie('steem_user', $login, time() + (86400 * 30), "/"); // Save username for 30 days
    http_response_code(200);
    exit;
}

/* --- Read user from cookie, if available --- */
$user = isset($_COOKIE['steem_user']) ? htmlspecialchars($_COOKIE['steem_user']) : null;
$username = $user;

$ver = date("dmY", time()); // versioning for CSS and JS 

?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Steem Keychain Login</title>
    (html comment removed:  CSS and JS with versioning via $ver for cache busting )
    <link rel="stylesheet" href="/css/style.css?v=<?=$ver;?>" type="text/css" />
    <script src="/js/steem_keychain.js?v=<?=$ver;?>"></script>
    <script src="/js/steem.min.js?v=<?=$ver;?>"></script>
</head>
<body>
    <div id="main">
        <div>
            <a href="/">Home</a>
            <?=(($user) ? ' | <span onclick="logout()" style="cursor: pointer; text-decoration: underline;">Logout</span>' : '');?>
        </div>

        &nbsp;

        <? if (!$user): ?>
            (html comment removed:  --- If user is not logged in, show login tabs --- )
            <div class="tabs">
                <input type="radio" name="tab" id="tab1" checked>
                <label class="tab-label" for="tab1">Login with Keychain</label>

                <input type="radio" name="tab" id="tab2">
                <label class="tab-label" for="tab2">Login with Posting Key</label>

                <div class="tabs-body">
                    <div class="tab-content">
                        (html comment removed:  --- Keychain login form --- )
                        <div class="content" id="content1">
                            <div id="auth-container">
                                <input type="text" id="login" placeholder="Enter username" /><br />
                                <button id="auth-btn">Login via Keychain</button>
                            </div>
                        </div>
                        (html comment removed:  --- Manual posting key login form --- )
                        <div class="content" id="content2">
                            <div id="manual-login">
                                <input type="text" id="manual-user" placeholder="Username" /><br />
                                <input type="password" id="manual-key" placeholder="Posting Key" /><br />
                                <button id="manual-btn">Login with Posting Key</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        <? else: ?>
            (html comment removed:  --- If user is logged in, show welcome message and transaction form --- )
            <div id="welcome-box" style="margin-top: 10px; display: flex; align-items: center; gap: 8px;">
                <img src="https://steemitimages.com/u/<?=$user;?>/avatar" width="32" height="32" style="border-radius: 50%;">
                Hello, <b><a href="https://steemit.com/@<?=$user;?>"><?=$user;?></a></b>!
            </div>

            &nbsp;

            <div id="container">
                <h4>Send STEEM via Keychain</h4>
                <br />
                (html comment removed:  --- Transfer form --- )
                <label>To: <input type="text" id="to" placeholder="Recipient name"></label><br />
                <label>Amount: <input type="number" step="0.001" min="0.001" id="amount" placeholder="Amount in STEEM"></label><br />
                <label>Memo: <input type="text" id="memo" placeholder="Memo (optional)"></label><br />
                <br />
                <button id="pay-steem" type="button">Send</button>
            </div>
        <? endif; ?>

        <script>
            <? if ($user): ?>
                // --- Logout handler: clears localStorage and cookie ---
                function logout() {
                    localStorage.removeItem('steem_user');
                    window.location.href = '/?logout';
                }

                // --- Send STEEM using Keychain ---
                document.getElementById('pay-steem').addEventListener('click', () => {
                    if (!window.steem_keychain) {
                        return alert('Please install Steem Keychain to proceed');
                    }

                    const to = document.getElementById('to').value.trim();
                    const amount = parseFloat(document.getElementById('amount').value).toFixed(3);
                    const memo = document.getElementById('memo').value.trim();
                    const currency = 'STEEM';

                    if (!to || isNaN(amount) || amount <= 0) {
                        return alert('Please fill in all fields correctly');
                    }

                    steem_keychain.requestTransfer(
                        null, // Sender is automatically selected by Keychain
                        to,
                        amount,
                        memo,
                        currency,
                        response => {
                            if (response.success) {
                                alert('Thank you! Payment sent.');
                            } else {
                                alert('Failed to send payment:\n' + response.message);
                            }
                        },
                        false
                    );
                });
            <? endif;

            if (!$user): ?>
                // --- Login via Keychain (sign buffer with posting key) ---
                const loginInput = document.getElementById('login');
                const authBtn = document.getElementById('auth-btn');

                authBtn.addEventListener('click', () => {
                    const login = loginInput.value.trim().toLowerCase();
                    if (!login) return alert('Please enter a username');

                    const challenge = 'Login at ' + new Date().toISOString();

                    steem_keychain.requestSignBuffer(
                        login,
                        challenge,
                        'posting',
                        res => {
                            if (res.success) {
                                // Save login locally and on server via cookie
                                localStorage.setItem('steem_user', login);
                                fetch('/?setcookie', {
                                    method: 'POST',
                                    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                                    body: 'login=' + encodeURIComponent(login)
                                }).then(() => location.reload());
                            } else {
                                alert('Login error: ' + res.message);
                            }
                        }
                    );
                });

                // --- Manual login with private posting key ---
                document.getElementById('manual-btn').addEventListener('click', () => {
                    const username = document.getElementById('manual-user').value.trim().toLowerCase();
                    const postingKey = document.getElementById('manual-key').value.trim();

                    if (!username || !postingKey) return alert('Enter both username and key');

                    let pubKey;
                    try {
                        pubKey = steem.auth.wifToPublic(postingKey); // Convert private key to public
                    } catch (e) {
                        console.error('Invalid key format:', e);
                        return alert('Invalid private key format');
                    }

                    steem.api.getAccounts([username], function(err, result) {
                        if (err || !result || result.length === 0) {
                            console.log('Error fetching account:', err);
                            return alert("User not found");
                        }

                        const keys = result[0].posting.key_auths.map(item => item[0]);
                        if (!keys.includes(pubKey)) {
                            console.log("Expected one of:", keys, "but got:", pubKey);
                            return alert("Key does not match account");
                        }

                        // Successful login — save and reload
                        localStorage.setItem('steem_user', username);
                        fetch('/?setcookie', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                            body: 'login=' + encodeURIComponent(username)
                        }).then(() => location.reload());
                    });
                });
            <? endif; ?>
        </script>
    </div>
</body>
</html>

 
I noticed that my comments in the HTML code are automatically corrected to "html comment removed" during publication. Therefore I've zipped all the files into a single archive so you have the opportunity to download them in their original form.

  • Download the full archive with all files (CSS, JS, and index file).