{"id":1952,"date":"2019-10-04T12:00:00","date_gmt":"2019-10-04T10:00:00","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/spring-security-tutorial-4-create-your-own-login-form\/"},"modified":"2026-07-05T03:24:39","modified_gmt":"2026-07-05T01:24:39","slug":"spring-security-tutorial-4-create-your-own-login-form","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/spring-security-tutorial-4-create-your-own-login-form\/","title":{"rendered":"Spring Security Tutorial 4 \u2013 Create Your Own Login Form"},"content":{"rendered":"<p>In this Tutorial, would see how to add custom Login Form. So instead of using the generated form we&#8217;ll build one. You can find Tutorials 1 to 3 below<\/p>\n<ul>\n<li><a href=\"https:\/\/kindsonthegenius.com\/tempsite\/introduction-to-spring-security-a-practical-tutorial\/\">Tutorial 1 &#8211; Introduction to Spring Security\u00a0<\/a><\/li>\n<li><a href=\"https:\/\/kindsonthegenius.com\/tempsite\/spring-security-tutorial-storing-user-credential-in-mysql-database\/\">Tutorial 2 &#8211; Storing Login Details in MySQL<\/a><\/li>\n<li><a href=\"https:\/\/kindsonthegenius.com\/tempsite\/spring-security-tutorial-3-encoding-your-password\/\">Tutorial 3 &#8211; Using BCrypt Password Encoder<\/a><\/li>\n<li><a href=\"https:\/\/kindsonthegenius.com\/tempsite\/spring-security-tutorial-4-create-your-own-login-form\/\">Tutorial 4 &#8211; Custom Login Form<\/a><\/li>\n<\/ul>\n<p>We would cover the following 4 topics;<\/p>\n<ol>\n<li><a href=\"#t1\">Add Login and Logout Pages<\/a><\/li>\n<li><a href=\"#t2\">Modify the AppSecurityConfig File<\/a><\/li>\n<li><a href=\"#t3\">Write the Methods for Login and Logout<\/a><\/li>\n<li><a href=\"#t4\">Add Logout Link to the Home Page<\/a><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<h5><strong id=\"t1\">1. Add Login and Logout Pages<\/strong><\/h5>\n<p>Follow the steps below to add custom login and logout pages<\/p>\n<p><strong>Step 1:<\/strong> Create a html page (for login) inside the templates folder. Name it login.html. The content of the body section be as shown below. Note the action of the form. Also note the th: prefix as we are using thymeleaf<\/p>\n<p>Finally, see that the span displays message for invalid credentials<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;h1&gt;<\/span>Login<span style=\"color: #007700;\">&lt;\/h1&gt;<\/span>\n<span style=\"color: #007700;\">&lt;span<\/span> <span style=\"color: #0000cc;\">th:if=<\/span><span style=\"background-color: #fff0f0;\">\"${session[SPRING_SECURITY_LAST_EXCEPTION] != null and session[SPRING_SECURITY_LAST_EXCEPTION].message != null}\"<\/span> <span style=\"color: #0000cc;\">th:text=<\/span><span style=\"background-color: #fff0f0;\">\"${session[SPRING_SECURITY_LAST_EXCEPTION].message}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Invalid credentials<span style=\"color: #007700;\">&lt;\/span&gt;<\/span>\n<span style=\"color: #007700;\">\n&lt;form<\/span> <span style=\"color: #0000cc;\">th:action=<\/span><span style=\"background-color: #fff0f0;\">\"@{\/login}\"<\/span> <span style=\"color: #0000cc;\">method=<\/span><span style=\"background-color: #fff0f0;\">\"post\"<\/span><span style=\"color: #007700;\">&gt;<\/span>\n<span style=\"color: #007700;\">&lt;table&gt;<\/span>\n<span style=\"color: #007700;\">&lt;tr&gt;<\/span>\n\t<span style=\"color: #007700;\">&lt;td&gt;<\/span>Username:<span style=\"color: #007700;\">&lt;\/td&gt;<\/span>\n\t<span style=\"color: #007700;\">&lt;td&gt;&lt;input<\/span> <span style=\"color: #0000cc;\">type=<\/span><span style=\"background-color: #fff0f0;\">\"text\"<\/span> <span style=\"color: #0000cc;\">name=<\/span><span style=\"background-color: #fff0f0;\">\"username\"<\/span> <span style=\"color: #0000cc;\">value=<\/span><span style=\"background-color: #fff0f0;\">\"\"<\/span><span style=\"color: #007700;\">&gt;&lt;\/td&gt;<\/span>\n<span style=\"color: #007700;\">&lt;\/tr&gt;<\/span>\n<span style=\"color: #007700;\">&lt;tr&gt;<\/span>\n\t<span style=\"color: #007700;\">&lt;td&gt;<\/span>Password:<span style=\"color: #007700;\">&lt;\/td&gt;<\/span>\n\t<span style=\"color: #007700;\">&lt;td&gt;&lt;input<\/span> <span style=\"color: #0000cc;\">type=<\/span><span style=\"background-color: #fff0f0;\">\"text\"<\/span> <span style=\"color: #0000cc;\">name=<\/span><span style=\"background-color: #fff0f0;\">\"password\"<\/span><span style=\"color: #007700;\">&gt;&lt;\/td&gt;<\/span>\n<span style=\"color: #007700;\">&lt;\/tr&gt;<\/span>\n<span style=\"color: #007700;\">&lt;tr&gt;<\/span>\n\t<span style=\"color: #007700;\">&lt;td&gt;&lt;input<\/span> <span style=\"color: #0000cc;\">name=<\/span><span style=\"background-color: #fff0f0;\">\"submit\"<\/span> <span style=\"color: #0000cc;\">type=<\/span><span style=\"background-color: #fff0f0;\">\"submit\"<\/span> <span style=\"color: #0000cc;\">value=<\/span><span style=\"background-color: #fff0f0;\">\"submit\"<\/span><span style=\"color: #007700;\">&gt;<\/span> <span style=\"color: #007700;\">&lt;\/td&gt;<\/span>\n<span style=\"color: #007700;\">&lt;\/tr&gt;<\/span>\n<span style=\"color: #007700;\">&lt;\/table&gt;<\/span>\n<span style=\"color: #007700;\">&lt;\/form&gt;<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Step 2:<\/strong> Create another html page. Name it logout.html. The content of the body section is as shown below<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;h1&gt;<\/span>Logout Home<span style=\"color: #007700;\">&lt;\/h1&gt;<\/span>\n<span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:href =<\/span><span style=\"background-color: #fff0f0;\">\"@{\/home}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Home<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<h5><strong id=\"t2\">2. Modify the AppSecurityConfig File<\/strong><\/h5>\n<p><strong>Step 3:<\/strong> Open the AppSecurityConfig file and override the configure(HttpSecurity http) method<\/p>\n<p><strong>Step 4<\/strong>: Write the following code inside the method<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #555555; font-weight: bold;\">@Override<\/span>\n<span style=\"color: #008800; font-weight: bold;\">protected<\/span> <span style=\"color: #333399; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">configure<\/span><span style=\"color: #333333;\">(<\/span>HttpSecurity http<span style=\"color: #333333;\">)<\/span> <span style=\"color: #008800; font-weight: bold;\">throws<\/span> Exception <span style=\"color: #333333;\">{<\/span>\n\thttp\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">csrf<\/span><span style=\"color: #333333;\">().<\/span><span style=\"color: #0000cc;\">disable<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">authorizeRequests<\/span><span style=\"color: #333333;\">().<\/span><span style=\"color: #0000cc;\">antMatchers<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/login\"<\/span><span style=\"color: #333333;\">).<\/span><span style=\"color: #0000cc;\">permitAll<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">anyRequest<\/span><span style=\"color: #333333;\">().<\/span><span style=\"color: #0000cc;\">authenticated<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">and<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">formLogin<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">loginPage<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/login\"<\/span><span style=\"color: #333333;\">).<\/span><span style=\"color: #0000cc;\">permitAll<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">and<\/span><span style=\"color: #333333;\">()<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">logout<\/span><span style=\"color: #333333;\">().<\/span><span style=\"color: #0000cc;\">invalidateHttpSession<\/span><span style=\"color: #333333;\">(<\/span><span style=\"color: #008800; font-weight: bold;\">true<\/span><span style=\"color: #333333;\">)<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">clearAuthentication<\/span><span style=\"color: #333333;\">(<\/span><span style=\"color: #008800; font-weight: bold;\">true<\/span><span style=\"color: #333333;\">)<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">logoutRequestMatcher<\/span><span style=\"color: #333333;\">(<\/span><span style=\"color: #008800; font-weight: bold;\">new<\/span> AntPathRequestMatcher<span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/logout\"<\/span><span style=\"color: #333333;\">))<\/span>\n\t<span style=\"color: #333333;\">.<\/span><span style=\"color: #0000cc;\">logoutSuccessUrl<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/logout-success\"<\/span><span style=\"color: #333333;\">).<\/span><span style=\"color: #0000cc;\">permitAll<\/span><span style=\"color: #333333;\">();<\/span>\n<span style=\"color: #333333;\">}<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Before I move on to the next step, let me explain to you the meaning of some of the codes in the above snippet<\/p>\n<p><strong>.csrf().disable()<em>:<\/em> <\/strong>this line disables cross-site-request-forgery security<\/p>\n<p><strong>.authorizeRequests().andMatchers(&#8220;\/login&#8221;).permitAll()<\/strong>: indicates that request must the authorized except for &#8220;\/login&#8221;<\/p>\n<p><strong>.formLogin():<\/strong> this is the main part. It allows you to use a custom login form<\/p>\n<p><strong>.logout().invalidateHttpSession(true):<\/strong> destroy the session once the user logs out<\/p>\n<p><strong>.clearAuthentication(true)<\/strong>: this plays similar role\u00a0 as the preceding line above<\/p>\n<p><strong>.logoutRequestMatcher(new AntPathRequestMatcher(&#8220;\/logout&#8221;))<\/strong>: specify path to the logout page<\/p>\n<p><strong>.logoutSuccessUrl(&#8220;\/logout-success&#8221;).permitAll():<\/strong> the url to call on logout<\/p>\n<p>&nbsp;<\/p>\n<h5><strong id=\"t3\">3. Write Methods for Login and Logout<\/strong><\/h5>\n<p>Now, we are going to write methods to call when login and logout requests are made.<\/p>\n<p><strong>Step 1:<\/strong> Open the HomeController File<\/p>\n<p><strong>Step 2:<\/strong> Write the method below to handle login requests<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #555555; font-weight: bold;\">@RequestMapping<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/login\"<\/span><span style=\"color: #333333;\">)<\/span>\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> String <span style=\"color: #0066bb; font-weight: bold;\">loginPage<\/span><span style=\"color: #333333;\">()<\/span> <span style=\"color: #333333;\">{<\/span>\n\t<span style=\"color: #008800; font-weight: bold;\">return<\/span> <span style=\"background-color: #fff0f0;\">\"login\"<\/span><span style=\"color: #333333;\">;<\/span>\n<span style=\"color: #333333;\">}<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Step 3:<\/strong> Write the following method to handle logout request<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #555555; font-weight: bold;\">@RequestMapping<\/span><span style=\"color: #333333;\">(<\/span><span style=\"background-color: #fff0f0;\">\"\/logout-success\"<\/span><span style=\"color: #333333;\">)<\/span>\t\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> String <span style=\"color: #0066bb; font-weight: bold;\">logoutPage<\/span><span style=\"color: #333333;\">()<\/span> <span style=\"color: #333333;\">{<\/span>\n\t<span style=\"color: #008800; font-weight: bold;\">return<\/span> <span style=\"background-color: #fff0f0;\">\"logout\"<\/span><span style=\"color: #333333;\">;<\/span>\n<span style=\"color: #333333;\">}<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<p>At this point, we have completed the neccessary configuration.<\/p>\n<p><strong>Step 4:<\/strong> Fire up the application. Visit http:\/\/localhost\/home.\u00a0 You will be prompted for a username and password. Enter the username and password and click on login. If it works, then congratulations! Otherwise, watch the video<\/p>\n<p>&nbsp;<\/p>\n<h5><strong id=\"t4\">4. Add Logout Link to the Home page<\/strong><\/h5>\n<p>Open the home page (index.html) and add the code to make a logout request. Add the code below the &#8216;Subscribe &lt;br&gt;. This is shown below<\/p>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;br&gt;<\/span>\n<span style=\"color: #007700;\">&lt;a<\/span> <span style=\"color: #0000cc;\">th:href =<\/span><span style=\"background-color: #fff0f0;\">\"@{\/logout}\"<\/span><span style=\"color: #007700;\">&gt;<\/span>Logout<span style=\"color: #007700;\">&lt;\/a&gt;<\/span>\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Now, relaunch the application. Try to login. Then try to logout and make sure everything works.<\/p>\n<p>In the next lesson, we would try to implement the OAuth 2.0 using existing user accounts.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this Tutorial, would see how to add custom Login Form. So instead of using the generated form we&#8217;ll build one. You can find Tutorials &hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[414],"tags":[],"class_list":["post-1952","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=1952"}],"version-history":[{"count":1,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1952\/revisions"}],"predecessor-version":[{"id":2120,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/1952\/revisions\/2120"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=1952"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=1952"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=1952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}