Taking advantage of WordPress’ user system is a practical thing especially since it has out of the box permission-by-roles functionality. In this article we will discuss the key points on how we implemented Single-Sign-On for our WordPress site using the existing credentials from a non-WordPress one.

By rule, this has to be done via a plugin instead of just on the current theme’s function.php to practice the separation of functionality with design. We are planning to release this in the future as a plugin so keep an eye out for that!

Our initial requirement is the endpoint ( for checking the login credentials (email and password). Postman has made our lives easier by providing generated code snippets – we specifically used PHP cURL and made use of the response by targeting the user role value.

The SSO was made possible by WP’s authenticate filter hook. This is where the checking happens to validate if the user is existent on the non-WP site, and has access to the subsite (only administrators in our case).

add_filter( "authenticate", "offshorly_authenticate", 10, 3 );

function offshorly_authenticate( $user, $email, $password ) {

    if($email == "" || $password == "") return;

    $input = array("email" => $email, "password" => $password);

    $response = CallAPI($input);

    $auth = json_decode( $response, true );

    // --- First validation ---


Note that the $auth array will vary on your response’s structure and values. On ours, a role of 1 means the user is an administrator.

// If user is NOT on main site or is NOT admin

if ( $auth['role']['id'] != 1 ) {

    // WP_Error message


// If user is on main site and is admin

elseif  ( $auth['role']['id'] == 1 ) {

// Get user by main site's ID

    $userobj = new WP_User();

    $user = $userobj->get_data_by( 'login', $auth['user']['id'] );

    $user = new WP_User($user->ID);

    // --- Second validation ---



Next is to check if the user already has an account on the WP subsite – if not, then we will create one for them using the same creds using wp_insert_user. This is a must because WordPress itself requires an actual account on its database before it can grant pass and perform anything on it.

// If user doesn't have WP account yet (first time logging in)

if( $user->ID == 0 ) {

    // Create user

    $userdata = array( 'user_email' => $auth['user']['email'],

        'user_login' => $auth['user']['id']

        // Other fields like username, first name, etc.


    $new_user_id = wp_insert_user( $userdata );

    $user = new WP_User ($new_user_id);



However, if they already have a WordPress account on the subsite, we just have to make sure their login details are the same using wp_update_user. This is for situations like when they changed their creds on the main non-WP web app.

// If user has WP account

else {

    // Update new WP user with new creds

    $userdata = array( 'ID' => $user->ID,

        'user_email' => $auth['user']['email']

        // Other fields like username, first name, etc.


    $new_user_id = wp_update_user( $userdata );

    $user = new WP_User ($new_user_id);



For handling errors, we replaced the default authentication filters wp_authenticate_username_password and wp_authenticate_email_password, then provided specific messages that suited our needs.

remove_action( 'authenticate', 'wp_authenticate_username_password', 20);

add_action( 'authenticate', 'new_wp_authenticate_username_password', 20, 3);

function new_wp_authenticate_username_password($user, $username, $password) {

    if ( $user instanceof WP_User ) {

        return $user;


    // Validations and error messages


remove_action( 'authenticate', 'wp_authenticate_email_password', 20);

add_action( 'authenticate', 'new_wp_authenticate_email_password', 20, 3);

function new_wp_authenticate_email_password( $user, $email, $password ) {

    if ( $user instanceof WP_User ) {

        return $user;


    // Validations and error messages



For easy usage, we also added a simple settings option page for the plugin to get the Request URL.

Here are some of the resources that helped us put this together:


Author of this post


WordPress Developer