Developers / Guides

Verified Ham with WordPress

Add call sign sign-in to a club website running WordPress, with a free plugin.

The free OpenID Connect Generic Client plugin adds a "Login with Verified Ham" button to the WordPress login screen. It suits a club site where members sign in to see member-only pages.

1. Register your app

  1. Create a Verified Ham account, if you don't have one, and sign in.
  2. Go to Register an app.
  3. Give it a name. People see it when they sign in.
  4. Set the redirect URI to:
    https://club.example.org/wp-admin/admin-ajax.php?action=openid-connect-authorize
  5. Choose Confidential, and register.
  6. Copy the client ID and client secret. The secret is shown only once.

You can sign in to your own app straight away, to test. Other people can sign in once you've verified your own call sign.

Use your site's address in place of club.example.org. The redirect URI must match exactly, query string included.

2. Install and configure the plugin

Install OpenID Connect Generic Client from Plugins → Add New, activate it, and open Settings → OpenID Connect Client:

SettingValue
Login TypeOpenID Connect button on login form
Client IDyour client ID
Client Secret Keyyour client secret
OpenID Scopeopenid email callsign
Login Endpoint URLhttps://verifiedham.net/authorize
Userinfo Endpoint URLhttps://verifiedham.net/userinfo
Token Validation Endpoint URLhttps://verifiedham.net/token
Identity Keysub
Nickname Keycallsign
Email Formatting{email}
Display Name Formatting{callsign}
Create user if does not existon, to let members create their account by signing in

3. Add PKCE

Verified Ham requires PKCE for every app, and the plugin doesn't send it. Add it with this small must-use plugin: save it as wp-content/mu-plugins/verifiedham-pkce.php (create the mu-plugins folder if it doesn't exist). WordPress loads must-use plugins automatically.

<?php
/**
 * Plugin Name: Verified Ham PKCE
 * Description: Adds PKCE (S256) to the OpenID Connect Generic Client plugin, which Verified Ham requires for every app.
 * Version: 1.0
 *
 * Install as a must-use plugin: copy this file to wp-content/mu-plugins/.
 *
 * The OpenID Connect Generic Client plugin doesn't send PKCE itself. This adds
 * a code challenge to the sign-in link it builds, keeps the matching verifier
 * for the few minutes a sign-in takes, keyed by the request's state, and sends
 * the verifier with the code when the plugin exchanges it for tokens.
 */

if (!defined('ABSPATH')) {
    exit;
}

function verifiedham_pkce_base64url(string $bytes): string
{
    return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '=');
}

add_filter('openid-connect-generic-auth-url', function ($url) {
    parse_str((string) wp_parse_url($url, PHP_URL_QUERY), $query);

    if (empty($query['state']) || str_contains($url, 'code_challenge=')) {
        return $url;
    }

    $verifier = verifiedham_pkce_base64url(random_bytes(32));
    set_transient('verifiedham-pkce--' . $query['state'], $verifier, 10 * MINUTE_IN_SECONDS);

    return $url
        . '&code_challenge=' . verifiedham_pkce_base64url(hash('sha256', $verifier, true))
        . '&code_challenge_method=S256';
});

add_filter('openid-connect-generic-alter-request', function ($request, $operation) {
    if ($operation !== 'get-authentication-token' || empty($_GET['state'])) {
        return $request;
    }

    $key      = 'verifiedham-pkce--' . sanitize_text_field(wp_unslash($_GET['state']));
    $verifier = get_transient($key);

    if (is_string($verifier) && $verifier !== '') {
        $request['body']['code_verifier'] = $verifier;
        delete_transient($key);
    }

    return $request;
}, 10, 2);

It hooks the plugin's openid-connect-generic-auth-url and openid-connect-generic-alter-request filters: it adds a code challenge to the sign-in link, and sends the matching verifier when the plugin exchanges the code for tokens.

4. Try it

Open your login page in a private window and use the new button.

Who can sign in

Only verified amateur radio operators, so every account created this way belongs to a verified call sign. Anyone else who tries is shown how to verify first, then sent back to your site. The exception is you, the app's developer, who can sign in before verifying, to test.