<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>BeamFoundry Rays Web Security</title><link>https://rays.bfdy.dev/rays-web-security/</link><description>Recent content on BeamFoundry Rays Web Security</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://rays.bfdy.dev/rays-web-security/index.xml" rel="self" type="application/rss+xml"/><item><title>1. Introduction</title><link>https://rays.bfdy.dev/rays-web-security/docs/1-introduction/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/1-introduction/</guid><description>&lt;h1 id="introduction--architecture"&gt;Introduction &amp;amp; Architecture&lt;a class="anchor" href="#introduction--architecture"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Securing enterprise applications often leads to messy, scattered middleware across various routers.&#10;Rays Web Security centralizes this logic into declarative &lt;strong&gt;Security Filter Chains&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;h2 id="core-architectural-features"&gt;Core Architectural Features&lt;a class="anchor" href="#core-architectural-features"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Declarative Authorization:&lt;/strong&gt; Define endpoint security rules using a highly expressive &lt;code&gt;HttpSecurityBuilder&lt;/code&gt;&#10;rather than imperative &lt;code&gt;if/else&lt;/code&gt; blocks inside your handlers.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Pluggable Authentication:&lt;/strong&gt; Easily swap out how users are authenticated by implementing the&#10;&lt;code&gt;AuthenticationProvider&lt;/code&gt; or &lt;code&gt;UserDetailsService&lt;/code&gt; interfaces.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;ThreadLocal Context:&lt;/strong&gt; Web Security utilizes &lt;code&gt;github.com/timandy/routine&lt;/code&gt; to store the currently&#10;authenticated user in a ThreadLocal &lt;code&gt;SecurityContext&lt;/code&gt;. Your deeper service layers can retrieve the&#10;user without needing the HTTP request object passed down.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;IoC Native Auto-Configuration:&lt;/strong&gt; The framework provides default security implementations out of&#10;the box, which you can easily override by defining your own Beams.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="-package-structure--imports"&gt;📦 Package Structure &amp;amp; Imports&lt;a class="anchor" href="#-package-structure--imports"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;To prevent circular dependencies and maintain clean boundaries, Rays Web Security is split into distinct packages:&lt;/p&gt;</description></item><item><title>Basic Authentication</title><link>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/1-basic-auth/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/1-basic-auth/</guid><description>&lt;h1 id="basic-authentication"&gt;Basic Authentication&lt;a class="anchor" href="#basic-authentication"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;For APIs and simple services without a frontend interface, you will typically use &lt;strong&gt;Basic Authentication&lt;/strong&gt; (passing credentials via the HTTP &lt;code&gt;Authorization&lt;/code&gt; header).&lt;/p&gt;&#10;&lt;p&gt;You can enable this by calling the &lt;code&gt;Basic()&lt;/code&gt; method on the &lt;code&gt;HttpSecurityBuilder&lt;/code&gt; before building the final security configuration.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;configurations&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; . &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/BeamFoundry/rays-web-security/pkg/config&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; . &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/BeamFoundry/rays/pkg/core&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;BasicSecurityConfig&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Configuration&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// The HttpSecurity Beam provider. &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;this&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BasicSecurityConfig&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;HttpSecurity&lt;/span&gt;() &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HttpSecurity&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; (&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;HttpSecurityBuilder&lt;/span&gt;{}).&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;AuthorizedHTTPRequests&lt;/span&gt;().&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Paths&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;/api/public/**&amp;#34;&lt;/span&gt;).&lt;span style="color:#a6e22e"&gt;PermitAll&lt;/span&gt;().&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;AnyRequest&lt;/span&gt;().&lt;span style="color:#a6e22e"&gt;Authenticated&lt;/span&gt;().&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;And&lt;/span&gt;().&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Basic&lt;/span&gt;(). &lt;span style="color:#75715e"&gt;// Secure all authenticated endpoints via BasicAuth&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Build&lt;/span&gt;()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;_&lt;/span&gt; = &lt;span style="color:#66d9ef"&gt;any&lt;/span&gt;(&lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;BasicSecurityConfig&lt;/span&gt;{}).(&lt;span style="color:#a6e22e"&gt;Stereotype&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>UserDetails Interface</title><link>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/1-user-details/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/1-user-details/</guid><description>&lt;h1 id="1-the-userdetails-interface"&gt;1. The &lt;code&gt;UserDetails&lt;/code&gt; Interface&lt;a class="anchor" href="#1-the-userdetails-interface"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;First, adapt your domain model to fulfill the framework&amp;rsquo;s &lt;code&gt;UserDetails&lt;/code&gt; interface, located in &lt;code&gt;pkg/core&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;Note that the framework provides a convenient &lt;code&gt;Authority&lt;/code&gt; string alias to easily generate &lt;code&gt;GrantedAuthority&lt;/code&gt; slice elements.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;models&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; . &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/BeamFoundry/rays-web-security/pkg/core&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;User&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ID&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;uint&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Email&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;PasswordHash&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Role&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Implement the UserDetails interface&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;GetUsername&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Email&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;GetPassword&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;PasswordHash&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;GetAuthorities&lt;/span&gt;() []&lt;span style="color:#a6e22e"&gt;GrantedAuthority&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; []&lt;span style="color:#a6e22e"&gt;GrantedAuthority&lt;/span&gt;{ &lt;span style="color:#a6e22e"&gt;Authority&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;ROLE_&amp;#34;&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;u&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Role&lt;/span&gt;) }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// These return false when the account is active and unrestricted&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;IsExpired&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;IsCredentialExpired&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;IsDisabled&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;u&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;User&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;IsLocked&lt;/span&gt;() &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>2. Quickstart &amp; Setup</title><link>https://rays.bfdy.dev/rays-web-security/docs/2-quickstart/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/2-quickstart/</guid><description>&lt;h1 id="quickstart--setup"&gt;Quickstart &amp;amp; Setup&lt;a class="anchor" href="#quickstart--setup"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;To secure your application, you need to construct an &lt;code&gt;HttpSecurity&lt;/code&gt; Beam. This tells the framework which endpoints require authentication and which are public.&lt;/p&gt;&#10;&lt;h2 id="-installation"&gt;📦 Installation&lt;a class="anchor" href="#-installation"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;go get github.com/BeamFoundry/rays-web-security&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="the-minimal-security-configuration"&gt;The Minimal Security Configuration&lt;a class="anchor" href="#the-minimal-security-configuration"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Here is a basic configuration that uses &lt;strong&gt;Basic Authentication&lt;/strong&gt; and secures all endpoints except for the public login and health-check routes.&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;Note: The framework automatically provisions a default &lt;code&gt;PasswordEncoder&lt;/code&gt;, so you don&amp;rsquo;t even need to define one to get started!&lt;/em&gt;&lt;/p&gt;</description></item><item><title>Form Login</title><link>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/2-form-login/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/2-form-login/</guid><description>&lt;h1 id="form-login--remember-me"&gt;Form Login &amp;amp; Remember Me&lt;a class="anchor" href="#form-login--remember-me"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;If you are building a traditional web application with server-rendered HTML views (instead of a stateless API), you will likely want to use &lt;strong&gt;Form Login&lt;/strong&gt; instead of Basic Authentication.&lt;/p&gt;&#10;&lt;p&gt;The &lt;code&gt;FormLogin()&lt;/code&gt; builder exposes several methods to fully customize the authentication flow.&lt;/p&gt;&#10;&lt;h3 id="configuration-defaults"&gt;Configuration Defaults&lt;a class="anchor" href="#configuration-defaults"&gt;&lt;/a&gt;&lt;/h3&gt;&#10;&lt;p&gt;If you call &lt;code&gt;.FormLogin()&lt;/code&gt; without any additional chained configuration, the framework applies the following defaults automatically:&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;Method&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;Default Value&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;Description&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;Username()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;username&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The HTML form field name for the user&amp;rsquo;s username.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;Password()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;password&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The HTML form field name for the user&amp;rsquo;s password.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;LoginPath()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;/login&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The path where the login hook is registered.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;LogoutPath()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;/logout&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The path where the logout hook is registered.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;ViewName()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;login&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The template view name rendered for the login form.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;DefaultSuccessURL()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;/&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The default URL to redirect to upon successful login.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;You can selectively override any of these defaults, serve a specific login view, and optionally integrate a &lt;code&gt;RememberMeService&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>UserDetailsService</title><link>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/2-user-details-service/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/2-user-details-service/</guid><description>&lt;h1 id="2-implementing-userdetailsservice"&gt;2. Implementing &lt;code&gt;UserDetailsService&lt;/code&gt;&lt;a class="anchor" href="#2-implementing-userdetailsservice"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Next, create a Service that implements &lt;code&gt;UserDetailsService&lt;/code&gt;. The framework will automatically detect this Beam and use it during the login process.&lt;/p&gt;&#10;&lt;p&gt;If the user cannot be found, you simply return &lt;code&gt;nil&lt;/code&gt;, and the framework will handle the failed authentication safely.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;package&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;security&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; . &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/BeamFoundry/rays-web-security/pkg/core&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; . &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/BeamFoundry/rays/pkg/core&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; . &lt;span style="color:#e6db74"&gt;&amp;#34;github.com/BeamFoundry/rays/pkg/lang&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;type&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;DomainUserDetailsService&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;userRepo&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;UserRepository&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`@:&amp;#34;Inject&amp;#34;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; (&lt;span style="color:#a6e22e"&gt;s&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;DomainUserDetailsService&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;LoadUserByUsername&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;username&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;) &lt;span style="color:#a6e22e"&gt;UserDetails&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;userOpt&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;s&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;userRepo&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;FindByEmail&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;username&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Return the user if found&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ok&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;userOpt&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Get&lt;/span&gt;(); &lt;span style="color:#a6e22e"&gt;ok&lt;/span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;user&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Return nil if the user does not exist&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>Password Encoding</title><link>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/3-password-encoding/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/3-password-encoding/</guid><description>&lt;h1 id="3-password-encoding"&gt;3. Password Encoding&lt;a class="anchor" href="#3-password-encoding"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Never store plain-text passwords. When you boot the application, &lt;code&gt;internal/autoconfig&lt;/code&gt; automatically registers a highly secure, upgradeable default &lt;code&gt;PasswordEncoder&lt;/code&gt;.&lt;/p&gt;&#10;&lt;h2 id="the-delegating-password-encoder"&gt;The Delegating Password Encoder&lt;a class="anchor" href="#the-delegating-password-encoder"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;To support seamless algorithm migrations over time (a best practice from Spring Security), the default encoder is a &lt;code&gt;DelegatingPasswordEncoder&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;It automatically wraps a &lt;code&gt;BCryptPasswordEncoder&lt;/code&gt; (with a cost of 10) mapped to the &amp;ldquo;bcrypt&amp;rdquo; prefix. This means your hashed passwords will automatically be formatted with a prefix, looking something like this:&#10;&lt;code&gt;{bcrypt}$2a$10$wN1FzZ2...&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Stateless APIs</title><link>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/3-stateless/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/3-stateless/</guid><description>&lt;h1 id="stateless-vs-stateful-sessions"&gt;Stateless vs. Stateful Sessions&lt;a class="anchor" href="#stateless-vs-stateful-sessions"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;By default, Rays Web Security assumes you are building a stateful web application (using session cookies). If you are building a modern API (e.g., React, Vue, Mobile App) that uses stateless tokens, you must tell the framework to operate in a stateless manner.&lt;/p&gt;&#10;&lt;p&gt;You can do this by using the &lt;code&gt;Csrf().Disable()&lt;/code&gt; and &lt;code&gt;SessionCreationPolicy()&lt;/code&gt; builder methods.&lt;/p&gt;&#10;&lt;h2 id="session-creation-policies"&gt;Session Creation Policies&lt;a class="anchor" href="#session-creation-policies"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The &lt;code&gt;SessionCreationPolicy()&lt;/code&gt; builder provides several options to control when the framework provisions a session:&lt;/p&gt;</description></item><item><title>Custom Filters</title><link>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/4-custom-filters/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/4-security-chains/4-custom-filters/</guid><description>&lt;h1 id="custom-filters"&gt;Custom Filters&lt;a class="anchor" href="#custom-filters"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;While Rays Web Security provides robust out-of-the-box mechanisms like Form Login and Basic Authentication, you may occasionally need to implement proprietary authentication flows (e.g., verifying a specific API key header, an internal SSO token, or an OAuth JWT).&lt;/p&gt;&#10;&lt;p&gt;You can inject your own security logic directly into the request lifecycle using the &lt;code&gt;AddCustomFilter()&lt;/code&gt; method on the builder.&lt;/p&gt;&#10;&lt;blockquote class='book-hint '&gt;&#10;&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Custom filters are always evaluated &lt;strong&gt;before&lt;/strong&gt; global filters (like BasicAuth or FormLogin).&lt;/p&gt;</description></item><item><title>Remember Me</title><link>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/4-remember-me/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/3-authentication/4-remember-me/</guid><description>&lt;h1 id="4-remember-me-services"&gt;4. Remember Me Services&lt;a class="anchor" href="#4-remember-me-services"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;To keep users logged in across browser sessions without relying solely on long-lived session cookies, you can leverage the &lt;code&gt;RememberMeService&lt;/code&gt; interface.&lt;/p&gt;&#10;&lt;p&gt;The framework provides a &lt;code&gt;TokenBasedRememberMeService&lt;/code&gt; in &lt;code&gt;pkg/rememberme&lt;/code&gt;. For a robust enterprise configuration, you should avoid hardcoding secrets and instead use Rays&amp;rsquo; &lt;code&gt;ConfigurationProperties&lt;/code&gt; to load your configuration from YAML.&lt;/p&gt;&#10;&lt;h2 id="configuration-options--defaults"&gt;Configuration Options &amp;amp; Defaults&lt;a class="anchor" href="#configuration-options--defaults"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The &lt;code&gt;TokenBasedRememberMeService&lt;/code&gt; provides several fluent builder methods to customize its behavior:&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;Method&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;Default Value&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;Description&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;WithParameter()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;remember-me&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The HTML form input checked to determine if the cookie should be set.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;WithCookieName()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;ldquo;remember-me&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The name of the cookie sent to the browser.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;WithCookieDomain()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&amp;quot;&amp;quot;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;The domain restriction for the cookie.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;WithCookieSecure()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;false&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;Whether the secure (HTTPS-only) bit should be set on the cookie.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;&lt;code&gt;WithValidity()&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;1209600 (14 days)&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;How long, in seconds, the cookie will be valid.&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="example-externalized-configuration"&gt;Example: Externalized Configuration&lt;a class="anchor" href="#example-externalized-configuration"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;First, define your YAML configuration. We explicitly provide the default values here for reference:&lt;/p&gt;</description></item><item><title>5. Security Context</title><link>https://rays.bfdy.dev/rays-web-security/docs/5-security-context/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/5-security-context/</guid><description>&lt;h1 id="the-security-context"&gt;The Security Context&lt;a class="anchor" href="#the-security-context"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;One of the biggest challenges in Go web development is accessing the authenticated user deep within your service layer. Often, developers resort to passing the user object or the HTTP Request context through dozens of function calls.&lt;/p&gt;&#10;&lt;p&gt;Rays Web Security solves this using &lt;code&gt;github.com/timandy/routine&lt;/code&gt; to establish a &lt;strong&gt;ThreadLocal SecurityContext&lt;/strong&gt; within its internal implementations.&lt;/p&gt;&#10;&lt;h2 id="accessing-the-authenticated-user"&gt;Accessing the Authenticated User&lt;a class="anchor" href="#accessing-the-authenticated-user"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;Whenever an authenticated request is being processed, the framework automatically binds the &lt;code&gt;Authentication&lt;/code&gt; object to the current goroutine.&lt;/p&gt;</description></item><item><title>6. Testing</title><link>https://rays.bfdy.dev/rays-web-security/docs/6-testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://rays.bfdy.dev/rays-web-security/docs/6-testing/</guid><description>&lt;h1 id="testing"&gt;Testing&lt;a class="anchor" href="#testing"&gt;&lt;/a&gt;&lt;/h1&gt;&#10;&lt;p&gt;Testing secured applications often requires mocking the user database so you don&amp;rsquo;t have to spin up a real database just to test authorization logic. To complement the core Rays testing framework, Rays Web Security provides a &lt;code&gt;pkg/testing&lt;/code&gt; package containing in-memory implementations.&lt;/p&gt;&#10;&lt;h2 id="the-inmemoryuserdetailsmanager"&gt;The InMemoryUserDetailsManager&lt;a class="anchor" href="#the-inmemoryuserdetailsmanager"&gt;&lt;/a&gt;&lt;/h2&gt;&#10;&lt;p&gt;The &lt;code&gt;InMemoryUserDetailsManager&lt;/code&gt; allows you to rapidly configure a &lt;code&gt;UserDetailsService&lt;/code&gt; populated with test users. It automatically encodes the plaintext passwords you provide using the injected &lt;code&gt;PasswordEncoder&lt;/code&gt;.&lt;/p&gt;&#10;&lt;p&gt;These users are stored as &lt;code&gt;InMemoryUser&lt;/code&gt; structs, which fully implement the &lt;code&gt;UserDetails&lt;/code&gt; interface.&lt;/p&gt;</description></item></channel></rss>