Feature suggestion for FluentAuth
The ability to change the default WordPress login URL.
For example: from my-domain.com/wp-login.php to my-domain.com/auth
+1 this would make it impossible for hackers to find if we could change the login admin url.
I use CHANGE FOR EMAIL plug in, it really simple. In order to modify your login page, afin your all set
You can use my snippet to redirect all entries on wp-login pages to FC/FA pages if it will help you. It works also with NextEnd Social login plugin which I use.
function redirect_wp_login() {
$allowed_actions = ['logout', 'lostpassword', 'rp', 'resetpass', 'register'];
$request_uri = $_SERVER['REQUEST_URI'];
// βοΈ PΕidΓ‘me vΓ½jimku pro callback Seznam loginu
if (strpos($request_uri, '/seznam-callback/') !== false) {
return;
}
// Detekce pΕΓstupu na wp-login.php
if (strpos($request_uri, 'wp-login.php') !== false) {
// 1οΈβ£ β PonechΓ‘me pΕΓstup, pokud jde o povolenΓ© akce
if (isset($_GET['action']) && in_array($_GET['action'], $allowed_actions, true)) {
return;
}
// 2οΈβ£ β PonechΓ‘me pΕΓstup, pokud jde o Nextend Social Login (OAuth callback)
$oauth_params = ['loginSocial', 'redirect_to', 'state', 'code', 'scope', 'authuser', 'prompt'];
foreach ($oauth_params as $param) {
if (isset($_GET[$param])) {
return;
}
}
// 3οΈβ£ β Jinak pΕesmΔrujeme na vlastnΓ login
wp_safe_redirect(home_url('/portal/?fcom_action=auth'));
exit;
}
}
add_action('init', 'redirect_wp_login');
Security by obscurity does not work. I've tested this with other plugins that redirected the login page and they always found it. The best thing to do is to have good WAF rules at the edge (like Cloudflare) to block the majority of malicious actors and bots, and then have good authentication policies.
It wouldn't bother me if FluentAuth added this feature, but I wouldn't use it. This is an amateur move that gives a false sense of security and it's easily overcome with a scan. The URL has to be public, so it's available to find and overcome.
William BeemΒ create a dummy admin login and it will keep them busy trying to hack a fake login page and with 100s or 1000s of urls, they won't be able to find the real admin url that is blended in with the rest of the urls. Wannabe hackers are predictable, they will be scanning for admin type urls. A real hacker will try injecting something into wp, he would not be using login anyways.
David ScurlockΒ there are tricks to discover or be redirected to the real wp-admin (login form) so I wouldnt bother hiding the url.
In many cases when a user type url dedicated for logged-in users it is automatically redirecting to the right Login form (all kinds of recovery mode plugins urls can be used to achieve the same)
One of many examples showing how plugins can be used to discover hidden login form:
https://www.sprocketsecurity.com/blog/discovering-wp-admin-urls-in-wordpress-with-gravityforms
Similar logic can be used with query strings like reauth=1 for fluent forms AFAIR - it is just to show the idea
?redirect_to=/wp-admin/admin.php/page/fluent_forms&reauth=1
or
/wp-admin/customize.php
or
/wp-activate
or
have expired fake cookie to force wp to redirect to the login page
or
check CSP header when implemented and look for white listed url in: script-src or form-action
William BeemΒ My suggestion was related to the aesthetics of the URL.
Rafael PitonΒ It's possible, but I'm not sure it's necessary. With FliuentAuth, my login accomplishes the same thing today. Create a page, plop in a shortcode, and you can choose the slug.
Why not create a restricted (access denied) page - jpg of denied access and choose a secret word that would be the wp-admin alternative and if that word isn't typed after your URL (example.com/secretword) then it automatically takes them to that restricted page.
Then you use code within functions.php to make it function.
You can also replace the restricted and just redirect them to the student login homeurl.com/auth/login
Here's a template of what I used. You can easily copy and paste this into chatgpt to have it give you additional code to exclude certain pages from the restriction access if you have certain things built in.
// 02. Access: Admin Masking + Secret Admin Entry
// ======================================
// - Secret entry: /SECRETWORDHERE
// - Access denied page: /restricted
// - Masks /wp-login.php and /wp-admin for logged-out users
// - Keeps Automator/FluentCRM routes & REST working
// - Locks homepage ("/") for guests, so the main link is also restricted (this can be omitted)
// - Bypass request is very important at the top of this code as it prevents the site from having a critical error
// ============================================
if (!function_exists('bypass_request')) {
function bypass_request() {
// Bypass loopbacks/sandbox/AJAX/REST/CLI
if (defined('WP_SANDBOX_SCRAPING') && WP_SANDBOX_SCRAPING) return true;
if (!empty($_GET['wp_scrape_key'])) return true;
if (function_exists('wp_doing_ajax') && wp_doing_ajax()) return true;
if (defined('REST_REQUEST') && REST_REQUEST) return true;
if (defined('WP_CLI') && WP_CLI) return true;
// Allow known webhook entry points (donβt block or redirect these)
$uri = $_SERVER['REQUEST_URI'] ?? '';
if ($uri) {
// Uncanny Automator webhook/API style
if (isset($_GET['automator_api'])) return true;
// FluentCRM router (e.g., ?fluentcrm=1&route=...)
if (isset($_GET['fluentcrm'])) return true;
// REST API (used by plugins)
if (strpos($uri, '/wp-json/') !== false) return true;
}
return false;
}
}
add_action('template_redirect', function () {
if (bypass_request()) return;
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
// Secret admin entry (/SECRETWORDHERE):
// - logged-in β /wp-admin
// - logged-out β set short-lived "SECRETWORDHERE" cookie (10m), then forward to /wp-login.php
if ($path === '/SECRETWORDHERE' || $path === '/SECRETWORDHERE/') {
if (is_user_logged_in()) {
wp_safe_redirect(admin_url());
} else {
setcookie('SECRETWORDHERE', '1', [
'expires' => time() + 600, // 10 minutes
'path' => '/',
'secure' => is_ssl(),
'httponly' => true,
'samesite' => 'Lax'
]);
wp_safe_redirect(wp_login_url()); // /wp-login.php
}
exit;
}
// Lock homepage for guests (hub is admin-only)
if ($path === '/' && !is_user_logged_in()) {
wp_safe_redirect(home_url('/restricted'));
exit;
}
// Mask /wp-admin for guests (allow ajax/post endpoints)
if (preg_match('#^/wp-admin/?#', $path) && !is_user_logged_in()) {
$base = basename($path);
if (!in_array($base, ['admin-ajax.php','admin-post.php'], true)) {
wp_safe_redirect(home_url('/restricted'));
exit;
}
}
});
add_action('init', function () {
if (bypass_request()) return;
$path = parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH) ?: '';
if ($path !== '/wp-login.php') return;
// Logged-out must come via /SECRETWORDHERE (cookie required)
if (!is_user_logged_in()) {
if (empty($_COOKIE['wu_inside'])) {
wp_safe_redirect(home_url('/restricted'));
exit;
}
// Gate cookie present β allow normal wp-login load
return;
}
// Logged-in hitting wp-login.php β go to /wp-admin
wp_safe_redirect(admin_url());
exit;
});
// - Security: Disable XML-RPC
// =============================================================================
// Your plugin set does not require XML-RPC. Remove this brute-force surface.
add_filter('xmlrpc_enabled', '__return_false');
add_action('init', function () {
$uri = $_SERVER['REQUEST_URI'] ?? '';
if ($uri && strpos($uri, 'xmlrpc.php') !== false) {
status_header(403); exit;
}
});
// - Security: Block User Enumeration (REST + ?author=) for guests
// =============================================================================
add_action('template_redirect', function () {
if (is_user_logged_in()) return;
// Classic ?author=123 / author archives
if (isset($_GET['author']) && $_GET['author'] !== '') {
wp_safe_redirect(home_url('/restricted'));
exit;
}
if (function_exists('is_author') && is_author()) {
wp_safe_redirect(home_url('/restricted'));
exit;
}
});
// Block listing of users via REST for unauthenticated requests
add_filter('rest_endpoints', function ($endpoints) {
if (!is_user_logged_in()) {
unset($endpoints['/wp/v2/users']);
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
}
return $endpoints;
});
// Also catch ?rest_route=/wp/v2/users
add_action('init', function () {
if (is_user_logged_in()) return;
$rq = $_GET['rest_route'] ?? '';
if ($rq && stripos($rq, '/wp/v2/users') === 0) {
status_header(403); exit;
}
});
FYI Ripon SarkarΒ
