[{"data":1,"prerenderedAt":570},["ShallowReactive",2],{"post-\u002Frest-api-authentication":3},{"page":4,"translation":455,"nav":457,"related":558,"random":563},{"id":5,"title":6,"body":7,"categories":436,"category":438,"date":439,"description":440,"draft":441,"extension":442,"image":443,"kind":438,"lang":444,"meta":445,"navigation":446,"path":99,"readingTime":447,"seo":448,"slug":449,"stem":449,"tags":450,"translationKey":449,"type":437,"updated":438,"__hash__":454},"posts\u002Frest-api-authentication.md","How to Perform REST API Authentication?",{"type":8,"value":9,"toc":422},"minimark",[10,62,69,124,127,132,135,138,140,144,147,150,153,156,159,161,165,168,171,174,176,180,183,186,189,194,199,202,219,223,226,235,243,245,249,252,255,257,261,264,267,270,283,285,289,387,389,393,396,399,404,406,410,418],[11,12,13,21],"blockquote",{},[14,15,16,17],"p",{},"💡 ",[18,19,20],"strong",{},"TL;DR:",[22,23,24,31],"ul",{},[25,26,27,30],"li",{},[18,28,29],{},"Stateless architecture:"," In a good REST API, the server keeps no session state; every request carries all the information needed to authenticate itself (token, API key, etc.).",[25,32,33,36],{},[18,34,35],{},"Authentication methods:",[22,37,38,44,50,56],{},[25,39,40,43],{},[18,41,42],{},"Basic Auth:"," The simplest but least secure; it sends the username\u002Fpassword Base64-encoded.",[25,45,46,49],{},[18,47,48],{},"Bearer (Token-based):"," A token (usually a JWT) is carried in the request header; the standard for mobile and modern web apps.",[25,51,52,55],{},[18,53,54],{},"API Keys:"," Preferred for third-party service integrations.",[25,57,58,61],{},[18,59,60],{},"OAuth 2.0 \u002F OIDC:"," Used for authorization and external identity providers.",[14,63,64,65,68],{},"This article is part of the ",[18,66,67],{},"RESTful API Design"," series. If you haven't read it yet, I recommend starting with the other articles in the series first.",[22,70,71,78,83,89,95,100,106,112,118],{},[25,72,73],{},[74,75,77],"a",{"href":76},"\u002Frest-api-design","REST API Fundamentals",[25,79,80],{},[74,81,82],{"href":76},"What Should a REST API's Output Format Be?",[25,84,85],{},[74,86,88],{"href":87},"\u002Frest-api-uri-structure","What Should the REST API URI Structure Be?",[25,90,91],{},[74,92,94],{"href":93},"\u002Fwhat-is-hateoas","What is HATEOAS in REST API? (added to the series later)",[25,96,97],{},[74,98,6],{"href":99},"\u002Frest-api-authentication",[25,101,102],{},[74,103,105],{"href":104},"\u002Frest-api-error-handling","How to Perform REST API Error Handling?",[25,107,108],{},[74,109,111],{"href":110},"\u002Frest-api-security","How to Secure a REST API?",[25,113,114],{},[74,115,117],{"href":116},"\u002Frest-api-documentation-and-testing","How to Document and Test a REST API?",[25,119,120],{},[74,121,123],{"href":122},"\u002Ffull-stack-project-development","Sample REST API Project",[125,126],"hr",{},[128,129,131],"h2",{"id":130},"about-the-series-and-likely-questions","About the Series and Likely Questions",[14,133,134],{},"When I started this series, I had no idea it would get this hard. What began as a single post turned into something I realized had to be a multi-part series—and the more I write, the more I see this is really a book-length topic. Whenever I try to simplify it, the explanation comes up short; whenever I dig into the details, the subject branches out and becomes complex.",[14,136,137],{},"I was going to open this topic by saying that a good REST API implementation should be stateless—then I caught myself thinking, \"well, I should first explain what stateless even means.\" It's genuinely hard to cover this without either drifting off-topic or leaving gaps. So if you find anything missing or have questions, please reach out to me on social media.",[125,139],{},[128,141,143],{"id":142},"what-do-stateful-and-stateless-mean","What Do STATEFUL and STATELESS Mean?",[14,145,146],{},"The best way to explain \"stateless\" is to explain what \"stateful\" is. Both terms come from the word \"state.\"",[14,148,149],{},"Stateful and stateless aren't relevant only to REST APIs or software—they're important concepts for DevOps and server systems too.",[14,151,152],{},"State describes the condition of a system at a given moment. (After all, the literal meaning of \"state\" is just that—a condition.) For example, the lamp in your room has two states: on or off. For a piece of code controlling that lamp to be stateless, it must not know the lamp's state at any given moment. A stateful system is the opposite: at any moment, it knows whether the lamp is on or off.",[14,154,155],{},"Let's imagine a virtual system. In this system, everyone has their own room. Hundreds of thousands of people turn their room's light on or off whenever they like. If we build the system to be stateless, the server won't know whether any given room's light is currently on or off. Each client is responsible for knowing the latest state of its own room. It sends the server a \"turn the light on\" or \"turn the light off\" request. That way, we don't track whether hundreds of thousands of rooms' lights are on or off on the server side. Otherwise, not only would we have to store that information, we also wouldn't know when it had become irrelevant.",[14,157,158],{},"I don't want to drag this out and turn it into a post about stateful versus stateless, but (exceptions aside) most of the time, building a stateless architecture—when it's possible—is the smoother and more correct solution.",[125,160],{},[128,162,164],{"id":163},"what-does-it-mean-for-a-rest-api-to-be-stateless","What Does It Mean for a REST API to Be Stateless?",[14,166,167],{},"By definition, a good REST API should be stateless and must not keep session state on the server. All the information needed to understand and authenticate a request must be sent to the server by the client. This constraint doesn't mean there's no information on the server side, or that every piece of data used for an operation has to be sent by the client. It means the server doesn't hold any memory of the session or of a previous state.",[14,169,170],{},"Pagination is a good example to make this clearer. If the client is going to send a query, it must specify which page of that query it wants. The server doesn't keep track of \"page 5 was served on the previous request, so page 6 is next.\"",[14,172,173],{},"Likewise, the server doesn't store the fact that the current connection comes from the user with ID 123. The server has to be able to determine, from the request itself, that the request is coming from user ID 123. But how?",[125,175],{},[128,177,179],{"id":178},"and-finally-the-authentication-part","And Finally, the Authentication Part",[14,181,182],{},"After all that necessary—and not so necessary—background, we've arrived at how to actually authenticate: how to say \"ID=123\" or \"username=evrenbal\" in the request we send. This is, of course, usually not that easy (the HTTP Basic Authentication method aside).",[14,184,185],{},"Whichever method you use, it's important to use it over HTTPS. The first thing to say about security in REST API design is probably to use HTTPS.",[14,187,188],{},"Let's look at the four most commonly used methods:",[190,191,193],"h3",{"id":192},"_1-http-authentication","1. HTTP Authentication",[195,196,198],"h5",{"id":197},"basic-authentication","Basic Authentication",[14,200,201],{},"The oldest and most basic method in the HTTP protocol. It's the easiest of the available methods, but perhaps also the least secure. It relies on sending a Base64-encoded username and password in the request header. Since Base64 isn't an encryption method, we can treat the credentials as being sent in the clear.",[203,204,209],"pre",{"className":205,"code":206,"language":207,"meta":208,"style":208},"language-http shiki shiki-themes github-light github-dark","Authorization: Basic ZXZyZW46YmFs\n","http","",[210,211,212],"code",{"__ignoreMap":208},[213,214,217],"span",{"class":215,"line":216},"line",1,[213,218,206],{},[195,220,222],{"id":221},"bearer-token","Bearer Token",[14,224,225],{},"\"Bearer\" means \"the one who carries\u002Fholds.\" It's a bit like saying, \"the person carrying this code is a guest of mine—you can let them in.\" The Bearer method is structurally similar to Basic Authentication in how the request is sent; the difference is that a 'token' is sent instead of a username and password.",[203,227,229],{"className":205,"code":228,"language":207,"meta":208,"style":208},"Authorization: Bearer \u003Ctoken>\n",[210,230,231],{"__ignoreMap":208},[213,232,233],{"class":215,"line":216},[213,234,228],{},[14,236,237,238,242],{},"When you pair the Bearer method with JWT (JSON Web Token) for creating and validating tokens, you get a fast and practical solution. I think this duo is sufficient for most applications that don't require advanced security. But if you're going to use JWT, I recommend reading my earlier post, \"",[74,239,241],{"href":240},"\u002Ftr\u002Fjwt-guvenli-mi-guvenlik-acigi-olusturmayin","Don't Create a Security Hole While Calling JWT Secure",".\"",[125,244],{},[190,246,248],{"id":247},"_2-api-keys","2. API Keys",[14,250,251],{},"This method is useful for third-party integrations or machine-to-machine (M2M) communication rather than end-user applications. Sending the request to the server is similar to the Bearer method. The difference lies in how the API key is generated and stored on the client side. You generate a unique API key that lets the consumer use your service, and you ask them to configure that key in their own system\u002Fcode. For example, for this blog, I enter various services' API keys into the relevant fields in the WordPress admin panel so my blog can use those services.",[14,253,254],{},"For a consumer-facing mobile application, however, we have to manage processes like obtaining the token from the server, storing it on the client, and sending it in the request header via the Bearer method.",[125,256],{},[190,258,260],{"id":259},"_3-oauth-20-and-openid-connect-oidc","3. OAuth 2.0 and OpenID Connect (OIDC)",[14,262,263],{},"OAuth 2.0 is an access authorization protocol more than an authentication one. For example, when you connect your Facebook account to a website, you approve Facebook granting that site \"permission to access your name and profile picture\"—in other words, you tell Facebook to \"issue an access token so this site can reach the following information.\"",[14,265,266],{},"If your API also needs to integrate and work with other sites, you can solve that with an OAuth 2.0 implementation. If your goal is to authenticate directly between your server and the client, you should solve that with OpenID Connect, which is built on top of OAuth 2.0.",[14,268,269],{},"OpenID Connect lets an authentication server verify the client. There's still an extra server between your application and the client, but this server's job is to authenticate the client and share the necessary basic information with your application.",[14,271,272,273,282],{},"For OpenID authentication, you can use a third-party OpenID Provider, or build your own verification solution with the various ",[74,274,281],{"href":275,"rel":276,"target":280},"https:\u002F\u002Fopenid.net\u002Fdevelopers\u002Flibraries\u002F",[277,278,279],"nofollow","noopener","noreferrer","_blank","libraries"," on the OpenID website.",[125,284],{},[190,286,288],{"id":287},"comparing-rest-api-authentication-methods","Comparing REST API Authentication Methods",[290,291,292,312],"table",{},[293,294,295],"thead",{},[296,297,298,303,306,309],"tr",{},[299,300,302],"th",{"align":301},"left","Method",[299,304,305],{"align":301},"Example Header Usage",[299,307,308],{"align":301},"Security Level",[299,310,311],{"align":301},"Best-Fit Scenario",[313,314,315,334,351,369],"tbody",{},[296,316,317,323,328,331],{},[318,319,320],"td",{"align":301},[18,321,322],{},"Basic Auth",[318,324,325],{"align":301},[210,326,327],{},"Authorization: Basic ZXZ...",[318,329,330],{"align":301},"Low (HTTPS only)",[318,332,333],{"align":301},"Simple internal services, quick prototypes",[296,335,336,340,345,348],{},[318,337,338],{"align":301},[18,339,222],{},[318,341,342],{"align":301},[210,343,344],{},"Authorization: Bearer \u003Ctoken>",[318,346,347],{"align":301},"High (with JWT \u002F TLS)",[318,349,350],{"align":301},"Mobile apps, modern SPA web applications",[296,352,353,358,363,366],{},[318,354,355],{"align":301},[18,356,357],{},"API Keys",[318,359,360],{"align":301},[210,361,362],{},"X-API-Key: abc123xyz",[318,364,365],{"align":301},"Medium–High",[318,367,368],{"align":301},"B2B integrations, third-party developer access",[296,370,371,376,381,384],{},[318,372,373],{"align":301},[18,374,375],{},"OAuth 2.0 \u002F OIDC",[318,377,378],{"align":301},[210,379,380],{},"Authorization: Bearer \u003Coauth_token>",[318,382,383],{"align":301},"Very High",[318,385,386],{"align":301},"Third-party authorization, Single Sign-On (SSO)",[125,388],{},[128,390,392],{"id":391},"which-method-should-we-choose","Which Method Should We Choose?",[14,394,395],{},"Just as there's no single correct method among these, there's no wrong one either. Which method you use will vary based on your usage and security needs. If you look closely, each method serves a different need.",[14,397,398],{},"In the next part of the series, we'll look at how error handling should be done.",[14,400,401],{},[74,402,403],{"href":104},"REST API Error Handling",[125,405],{},[195,407,409],{"id":408},"changelog","Changelog",[22,411,412,415],{},[25,413,414],{},"2022-05-11: Revised the article summary.",[25,416,417],{},"2026-06-20: Standardized REST API terminology, fixed typos, and added the TL;DR summary and the method comparison table.",[419,420,421],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":208,"searchDepth":423,"depth":423,"links":424},2,[425,426,427,428,435],{"id":130,"depth":423,"text":131},{"id":142,"depth":423,"text":143},{"id":163,"depth":423,"text":164},{"id":178,"depth":423,"text":179,"children":429},[430,432,433,434],{"id":192,"depth":431,"text":193},3,{"id":247,"depth":431,"text":248},{"id":259,"depth":431,"text":260},{"id":287,"depth":431,"text":288},{"id":391,"depth":423,"text":392},[437],"technical",null,"2026-06-20","Stateful vs stateless authentication for REST APIs, and how HTTP Basic, Bearer tokens, API keys, and OAuth 2.0 compare.",false,"md","\u002Fimages\u002Fhero\u002Frest-api-auth.avif","en",{},true,8,{"title":6,"description":440},"rest-api-authentication",[451,452,453],"api","authentication","rest","xzADCfFJ3RLQYS5islynUSunmhIB4kQH52eH7n_78Og",{"path":456},"\u002Ftr\u002Frest-api-kimlik-dogrulama-nasil-yapilir",{"prev":458,"next":459,"others":461,"lucky":557,"readingTime":447},{"path":122,"title":123},{"path":76,"title":460},"REST API Design: Principles and Output Format",[462,463,464,465,466,467,468,471,474,477,480,483,486,489,492,495,498,501,504,507,510,513,516,519,522,525,528,531,534,537,540,543,546,549,551,554],{"path":122,"title":123},{"path":76,"title":460},{"path":116,"title":117},{"path":104,"title":105},{"path":110,"title":111},{"path":87,"title":88},{"path":469,"title":470},"\u002Ftroubleshooting-cyberpanel-inaccessibility-after-ubuntu-release-upgrade","Troubleshooting CyberPanel Inaccessibility After Ubuntu Release Upgrade",{"path":472,"title":473},"\u002Freset-wordpress-admin-password-using-wp-cli","Reset WordPress Admin Password Using WP-CLI",{"path":475,"title":476},"\u002Fgraphql-vs-rest-api-which-is-the-best-choice-for-headless-wordpress","GraphQL vs REST API: Which is the Best Choice for Headless WordPress?",{"path":478,"title":479},"\u002Fgrow-your-business-in-turkey-with-expert-wordpress-plugin-and-theme-localization-and-support-services","Grow Your Business in Turkey with Expert WordPress Plugin and Theme Localization and Support Services",{"path":481,"title":482},"\u002Fgetting-started-with-devops-understanding-the-principles-and-adopting-the-tools","Getting Started with DevOps: Understanding the Principles and Adopting the Tools",{"path":484,"title":485},"\u002Fphp-graphql-development-advanced-techniques-for-optimizing-your-apis","PHP GraphQL Development: Advanced Techniques for Optimizing Your APIs",{"path":487,"title":488},"\u002Fadvanced-techniques-for-dependency-injection-in-php-tips-code-samples-and-faqs","Advanced Techniques for Dependency Injection in PHP: Tips, Code Samples, and FAQs",{"path":490,"title":491},"\u002Fmaximize-the-potential-of-headless-wordpress-with-graphql","Maximize the Potential of Headless WordPress with GraphQL",{"path":493,"title":494},"\u002Fwriting-clean-modular-and-reusable-code-in-php","Best Practices for Writing Clean, Modular, and Reusable Code in PHP",{"path":496,"title":497},"\u002Fheadless-cmss-an-overview-of-popular-alternatives-to-contentful-and-wordpress","Headless CMSs: An Overview of Popular Alternatives to Contentful and WordPress",{"path":499,"title":500},"\u002Fci-cd-for-php-a-comprehensive-guide","CI\u002FCD for PHP: A Comprehensive Guide",{"path":502,"title":503},"\u002Fintroduction-to-php-namespaces-a-beginners-guide-to-structuring-your-code","Introduction to PHP Namespaces: A Beginner's Guide to Structuring Your Code",{"path":505,"title":506},"\u002Fwhat-is-graylog-a-powerful-tool-for-collecting-indexing-and-analyzing-log-data","What is Graylog? A Powerful Tool for Collecting, Indexing, and Analyzing Log Data",{"path":508,"title":509},"\u002Felevate-your-turkish-audience-experience-with-professional-wordpress-plugin-and-theme-translation","Elevate Your Turkish Audience Experience with Professional WordPress Plugin and Theme Translation",{"path":511,"title":512},"\u002Fhow-to-set-up-a-self-hosted-api-gateway-a-comprehensive-guide","How to Set Up a Self-Hosted API Gateway: A Comprehensive Guide",{"path":514,"title":515},"\u002Fdifference-between-generators-and-iterators-in-php","The Key Differences Between PHP Generators and Iterators",{"path":517,"title":518},"\u002Fphp-and-machine-learning-a-winning-combination-with-php-ml","PHP and Machine Learning: A Winning Combination with PHP-ML",{"path":520,"title":521},"\u002Fphp-generators-a-beginners-guide-to-iteration","PHP Generators: A Beginner's Guide to Iteration",{"path":523,"title":524},"\u002Fmastering-closures-in-javascript-a-beginners-guide","Mastering Closures in JavaScript: A Beginner's Guide",{"path":526,"title":527},"\u002Fthe-top-php-certification-programs-for-developers","The Top PHP Certification Programs for Developers",{"path":529,"title":530},"\u002Fhow-to-revalidate-next-js-isr-cache-on-demand-cache-regeneration","How to Revalidate Next.js ISR Cache? On-Demand Cache Regeneration",{"path":532,"title":533},"\u002Ftips-for-translating-a-wordpress-plugin-wordpress-theme-to-turkish","Tips for Translating a WordPress Plugin \u002F WordPress Theme to Turkish",{"path":535,"title":536},"\u002Fall-about-headless-wordpress","All About Headless WordPress",{"path":538,"title":539},"\u002Finstall-composer-on-ubuntu","How to Install Composer on Ubuntu \u002F Linux",{"path":541,"title":542},"\u002Fwhat-is-an-api-gateway","What is an API Gateway? Should You Use It?",{"path":544,"title":545},"\u002Fis-jwt-safe-or-is-it-vulnerable","Is JWT Safe or Is It Vulnerable?",{"path":547,"title":548},"\u002Ftailwind-css-to-use-or-not-to-use-that-is-the-question","Tailwind CSS! To use? Or not to use? That is the question.",{"path":93,"title":550},"What is HATEOAS?",{"path":552,"title":553},"\u002Fhello-world","Hello World: A New Multilingual Journey",{"path":555,"title":556},"\u002Fwhat-is-ecmascript","What is ECMAScript? What is not?",{"path":475,"title":476},[559,560,561,562],{"path":122,"title":123,"date":439},{"path":76,"title":460,"date":439},{"path":116,"title":117,"date":439},{"path":104,"title":105,"date":439},[564,566,568],{"path":502,"title":503,"date":565},"2023-01-13",{"path":93,"title":550,"date":567},"2022-05-12",{"path":490,"title":491,"date":569},"2023-01-17",1782141976353]