{"id":8843,"date":"2026-08-22T10:05:00","date_gmt":"2026-08-22T08:05:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=8843"},"modified":"2026-10-09T22:54:38","modified_gmt":"2026-10-09T20:54:38","slug":"secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/","title":{"rendered":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints"},"content":{"rendered":"\r\n<h2 class=\"wp-block-heading\">Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Integrating WordPress with external SaaS platforms, serverless data pipelines, or automated deployment agents requires exposing robust, high-performance API interfaces. Relying on default WordPress REST API endpoints or basic Application Passwords often grants excessive privileges across the entire Content Management System. Designing secure, enterprise-grade integration layers requires implementing OAuth 2.0 authorization flows alongside purpose-built custom REST endpoints with granular access restrictions.<\/p>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">1. Moving Beyond Application Passwords: The Power of OAuth 2.0<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Standard WordPress Application Passwords authenticate requests using Basic Authentication over HTTPS. While functional for simple scripts, this model inherits the full administrative capabilities of the associated user account. In complex architectures, OAuth 2.0 provides superior cryptographic separation and security governance:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>Strict Scope Limitation:<\/strong> OAuth 2.0 access tokens can be limited to specific read or write scopes. For example, a token could allow updates to particular custom database tables without granting access to user management or plugin settings.<\/li>\r\n\r\n\r\n\r\n<li><strong>Short-Lived Tokens &amp; Revocation:<\/strong> Access tokens expire automatically after a predefined lifecycle, utilizing refresh token rotation to minimize exposure if an external SaaS integration is compromised.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<figure class=\"lw-diagram\">\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/hand-restapi-en.png\" width=\"1120\" height=\"660\" alt=\"A request passing four gates \u2014 bearer header, token validity, payload schema and rate limit \u2014 before the WordPress REST handler is executed\">\n<figcaption>Every check happens before the handler, not inside it: the permission callback decides who gets in, the argument schema decides what may come in, and the rate limit decides how often.<\/figcaption>\n<\/figure>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">2. Architecting Custom REST API Endpoints with Minimal Attack Surface<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">To prevent unauthorized export of data or unintended database changes, register custom endpoints with <code>register_rest_route()<\/code>. Define input validation, sanitization and strict permission callbacks explicitly.<\/p>\r\n\r\n\r\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"php\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">PHP<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-php\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\">\/\/ Example: Secure custom REST API endpoint with strict OAuth \/ token validation<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">add_action<\/span>(<span class=\"cbb-string\">'rest_api_init'<\/span>, <span class=\"cbb-keyword\">function<\/span> () {\n<\/span><span class=\"cbb-line\">    <span class=\"cbb-function\">register_rest_route<\/span>(<span class=\"cbb-string\">'lw-solutions\/v1'<\/span>, <span class=\"cbb-string\">'\/ingest-telemetry'<\/span>, &#91;\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-string\">'methods'<\/span>             <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-string\">'POST'<\/span>,\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-string\">'callback'<\/span>            <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-string\">'lw_handle_telemetry_ingestion'<\/span>,\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-string\">'permission_callback'<\/span> <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-keyword\">function<\/span> (<span class=\"cbb-variable\">$request<\/span>) {\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-comment\">\/\/ Validate OAuth bearer token or custom JWT HMAC signature<\/span>\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-variable\">$auth_header<\/span> = <span class=\"cbb-variable\">$request<\/span><span class=\"cbb-operator\">-&gt;<\/span><span class=\"cbb-function\">get_header<\/span>(<span class=\"cbb-string\">'authorization'<\/span>);\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-keyword\">if<\/span> (!<span class=\"cbb-variable\">$auth_header<\/span> || !<span class=\"cbb-function\">str_starts_with<\/span>(<span class=\"cbb-variable\">$auth_header<\/span>, <span class=\"cbb-string\">'Bearer '<\/span>)) {\n<\/span><span class=\"cbb-line\">                <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-keyword\">new<\/span> <span class=\"cbb-type\">WP_Error<\/span>(<span class=\"cbb-string\">'rest_forbidden'<\/span>, <span class=\"cbb-string\">'Missing authorization token'<\/span>, &#91;<span class=\"cbb-string\">'status'<\/span> <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-number\">401<\/span>&#93;);\n<\/span><span class=\"cbb-line\">            }\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-variable\">$token<\/span> = <span class=\"cbb-function\">substr<\/span>(<span class=\"cbb-variable\">$auth_header<\/span>, <span class=\"cbb-number\">7<\/span>);\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-function\">lw_verify_api_token<\/span>(<span class=\"cbb-variable\">$token<\/span>); <span class=\"cbb-comment\">\/\/ Must return true or WP_Error<\/span>\n<\/span><span class=\"cbb-line\">        },\n<\/span><span class=\"cbb-line\">        <span class=\"cbb-string\">'args'<\/span>                <span class=\"cbb-operator\">=&gt;<\/span> &#91;\n<\/span><span class=\"cbb-line\">            <span class=\"cbb-string\">'payload_hash'<\/span> <span class=\"cbb-operator\">=&gt;<\/span> &#91;\n<\/span><span class=\"cbb-line\">                <span class=\"cbb-string\">'required'<\/span>          <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-constant\">true<\/span>,\n<\/span><span class=\"cbb-line\">                <span class=\"cbb-string\">'type'<\/span>              <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-string\">'string'<\/span>,\n<\/span><span class=\"cbb-line\">                <span class=\"cbb-string\">'validate_callback'<\/span> <span class=\"cbb-operator\">=&gt;<\/span> <span class=\"cbb-keyword\">function<\/span>(<span class=\"cbb-variable\">$param<\/span>) {\n<\/span><span class=\"cbb-line\">                    <span class=\"cbb-keyword\">return<\/span> <span class=\"cbb-type\">(bool)<\/span> <span class=\"cbb-function\">preg_match<\/span>(<span class=\"cbb-string\">'\/^&#91;a-f0-9&#93;{64}$\/i'<\/span>, <span class=\"cbb-variable\">$param<\/span>);\n<\/span><span class=\"cbb-line\">                }\n<\/span><span class=\"cbb-line\">            &#93;\n<\/span><span class=\"cbb-line\">        &#93;\n<\/span><span class=\"cbb-line\">    &#93;);\n<\/span><span class=\"cbb-line\">});<\/span><\/code><\/pre><\/figure>\r\n\r\n\r\n<h2 class=\"wp-block-heading\">3. Hardening Best Practices for API Integrations<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Exposing REST endpoints to external automation scripts necessitates several defensive engineering practices:<\/p>\r\n\r\n\r\n\r\n<ul class=\"wp-block-list\">\r\n<li><strong>Rate Limiting &amp; Throttling:<\/strong> Implementing Redis-based or server-level request throttling prevents Denial-of-Service (DoS) vectors against resource-intensive endpoints.<\/li>\r\n\r\n\r\n\r\n<li><strong>Payload Schema Enforcement:<\/strong> Relying on strict JSON schema validation within the endpoint registration rules ensures that malformed payloads are rejected at the REST server level before executing any PHP backend logic.<\/li>\r\n\r\n\r\n\r\n<li><strong>Default Endpoint Disabling:<\/strong> Unused default routes (such as <code>\/wp\/v2\/users<\/code>) should be programmatically restricted or stripped from unauthenticated requests to prevent username enumeration.<\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<h2 class=\"wp-block-heading\">Summary<\/h2>\r\n\r\n\r\n\r\n<p class=\"wp-block-paragraph\">Secure REST API architecture in WordPress requires abandoning over-privileged basic authentication in favor of scoped OAuth 2.0 token workflows. Combining rigorous <code>permission_callback<\/code> validations, strict regex-based argument checks, and dedicated integration routes ensures seamless automation without expanding the CMS attack surface.<\/p>\r\n\n\n<div class=\"lw-faq\">\n<h2>Questions and answers<\/h2>\n\n<h3>REST requests run through PHP anyway. Does a rate limiter at plugin level achieve anything?<\/h3>\n<p>The two layers protect different parts of the system. That is why both exist, and why choosing just one is usually the wrong decision.<\/p>\n<p>A limiter inside the application protects the database and the expensive work behind the endpoint, and it can count per token rather than per address \u2014 which is the only way to catch a single legitimate client that has started misbehaving. What it cannot do is prevent the cost of getting there: by the time the code runs, the process has been allocated, WordPress has bootstrapped and the request has already consumed most of what it was going to consume.<\/p>\n<p>A limiter in front of PHP, in the web server or a proxy, is the one that survives volume, because it rejects before any of that happens. It counts per address, which is the right unit for a flood and the wrong unit for a single noisy client behind a shared network.<\/p>\n<p>So the useful arrangement is both, with different thresholds and different units: the proxy stops the flood, the application stops the client. Building only the second is the common case, and it holds until the first real attempt, at which point the site falls over while the limiter reports that it is working.<\/p>\n<\/div>\n\n<div class=\"lw-quellen\">\n<h2>Sources<\/h2>\n<ul>\n<li><a href=\"https:\/\/developer.wordpress.org\/rest-api\/\" target=\"_blank\" rel=\"noopener noreferrer\">WordPress REST API handbook<\/a><\/li>\n<li><a href=\"https:\/\/owasp.org\/www-project-top-ten\/\" target=\"_blank\" rel=\"noopener noreferrer\">OWASP Top 10<\/a><\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Technical guide on securing WordPress REST API integrations: implementing OAuth 2.0 scopes, registering custom authorized endpoints, and enforcing strict schema validation.<\/p>\n","protected":false},"author":1,"featured_media":14103,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[148],"tags":[91093,91392,91219,91115,91096],"class_list":["post-8843","post","type-post","status-publish","format-standard","hentry","category-web-development","tag-php","tag-rest-api","tag-tutorial","tag-web-security","tag-wordpress"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"Secure WordPress REST integrations: OAuth scopes, custom endpoints, permission checks and input-schema validation.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"Secure WordPress REST integrations: OAuth scopes, custom endpoints, permission checks and input-schema validation.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-22T08:05:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-09T20:54:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints\",\"datePublished\":\"2026-08-22T08:05:00+00:00\",\"dateModified\":\"2026-10-09T20:54:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/\"},\"wordCount\":608,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png\",\"keywords\":[\"PHP\",\"REST API\",\"Tutorial\",\"Web Security\",\"WordPress\"],\"articleSection\":[\"Web Development\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/\",\"name\":\"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png\",\"datePublished\":\"2026-08-22T08:05:00+00:00\",\"dateModified\":\"2026-10-09T20:54:38+00:00\",\"description\":\"Secure WordPress REST integrations: OAuth scopes, custom endpoints, permission checks and input-schema validation.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/09\\\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png\",\"width\":1200,\"height\":630,\"caption\":\"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints | Lukas Wojcik","description":"Secure WordPress REST integrations: OAuth scopes, custom endpoints, permission checks and input-schema validation.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/","og_locale":"en_US","og_type":"article","og_title":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints | Lukas Wojcik","og_description":"Secure WordPress REST integrations: OAuth scopes, custom endpoints, permission checks and input-schema validation.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-08-22T08:05:00+00:00","article_modified_time":"2026-10-09T20:54:38+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints","datePublished":"2026-08-22T08:05:00+00:00","dateModified":"2026-10-09T20:54:38+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/"},"wordCount":608,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png","keywords":["PHP","REST API","Tutorial","Web Security","WordPress"],"articleSection":["Web Development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/","name":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png","datePublished":"2026-08-22T08:05:00+00:00","dateModified":"2026-10-09T20:54:38+00:00","description":"Secure WordPress REST integrations: OAuth scopes, custom endpoints, permission checks and input-schema validation.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/09\/hero-8843-secure-wordpress-rest-api-oauth-cust-g.png","width":1200,"height":630,"caption":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/secure-wordpress-rest-api-oauth-2-0-and-custom-authorized-endpoints\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Secure WordPress REST API: OAuth 2.0 and Custom Authorized Endpoints"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/8843","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=8843"}],"version-history":[{"count":5,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/8843\/revisions"}],"predecessor-version":[{"id":21965,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/8843\/revisions\/21965"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/14103"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=8843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=8843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=8843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}