SSO With Freshdesk and Spring Boot Application using JWT
- General
SSO With Freshdesk and Spring Boot Application using JWT
What is SSO?
Single sign-on (SSO) is an authentication scheme that allows a user to login with a single ID to any of several related, yet independent, software systems. True single sign-on allows the user to log in once and access services without re-entering authentication factors.
What is Freshdesk?
Online cloud-based customer service software providing helpdesk support with all smart automations to get things done faster.
What is Spring Boot?
Spring Boot is an open source Java-based framework used to create a micro Service. It is developed by Pivotal Team and is used to build stand-alone and production ready spring applications.
What is JWT?
JSON Web Token is a proposed Internet standard for creating data with optional signature and/or optional encryption whose payload holds JSON that asserts some number of claims. The tokens are signed either using a private secret or a public/private key.
Create Spring Boot Application
1) LoginAppSsoApplication.java
1 2 3 4 5 6 7 8 9 10 11 12 |
package com.LoginAppSso; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class LoginAppSsoApplication { public static void main(String[] args) { SpringApplication.run(LoginAppSsoApplication.class, args); System.out.println("DONE"); } } |
2) LoginController.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
package com.LoginAppSso; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @Controller public class LoginController { @RequestMapping(value = "/", method = RequestMethod.GET) public String login(Model model, @RequestParam("nonce") String nonce, @RequestParam("state") String state) { model.addAttribute("nonce", nonce); model.addAttribute("state", state); return "index"; } @RequestMapping(value = "/doLogin", method = RequestMethod.POST) public String checkLogin(@ModelAttribute("userFormData") LoginDTO formData, BindingResult result, HttpServletRequest request) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException { String email = "praveensanpada@gmail.com"; String password = "Auriga@123"; String email1 = formData.getUsername().toLowerCase(); String password1 = formData.getPassword(); String nonce = formData.getNonce(); String state = formData.getState(); if(email.equals(email1)) { System.out.println("EMAIL"); if(password.equals(password1)) { System.out.println("PASS"); Path path = Paths.get("auriga.key"); byte[] bytes = Files.readAllBytes(path); PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey pvt1 = kf.generatePrivate(ks); long epoch = System.currentTimeMillis()/1000; Claims claims = Jwts.claims(); claims.put("sub", "Praveen1"); claims.put("email",email1); claims.put("iat", epoch); claims.put("nonce", nonce); claims.put("given_name", "Praveen"); claims.put("family_name", "Sanpada"); Map<String, Object> headers = new HashMap<String, Object>(); headers.put("alg", "RS256"); headers.put("typ", "JWT"); String token = Jwts.builder() .setHeaderParams(headers) .setClaims(claims) .signWith(SignatureAlgorithm.RS256, pvt1).compact(); String rUrl = "https://aurigait-464307254473032633.myfreshworks.com/sp/OIDC/464307824220156643/implicit?state="+state+"&id_token="+token; return "redirect:"+rUrl; }else { System.out.println("FAIL PASS"); return "error"; } }else { System.out.println("FAIL EMAIL"); return "error"; } } @RequestMapping(value = "/logout", method = RequestMethod.GET) public String logout(){ return "logout"; } } |
3) LoginDTO.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
package com.LoginAppSso; import java.io.Serializable; public class LoginDTO implements Serializable { private Long id; private String username; private String password; private String nonce; private String state; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public void setUsername(String username) { this.username = username; } public String getNonce() { return nonce; } public void setNonce(String nonce) { this.nonce = nonce; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getUsername() { return username; } public void setPassword(String password) { this.password = password; } public String getPassword() { return password; } } |
4) index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> Login Page </title> <style> Body { font-family: Calibri, Helvetica, sans-serif; background-color: pink; } button { background-color: #4CAF50; width: 100%; color: orange; padding: 15px; margin: 10px 0px; border: none; cursor: pointer; } form { border: 3px solid #f1f1f1; } input[type=text], input[type=password] { width: 100%; margin: 8px 0; padding: 12px 20px; display: inline-block; border: 2px solid green; box-sizing: border-box; } button:hover { opacity: 0.7; } .cancelbtn { width: auto; padding: 10px 18px; margin: 10px 5px; } .container { padding: 25px; background-color: lightblue; } </style> </head> <body> <center> <h1> SSO Login Form </h1> </center> <form action="doLogin" method="POST" modelAttribute="userFormData"> <div class="container"> <label>Username : </label> <input type="text" placeholder="Enter Username" name="username" required> <label>Password : </label> <input type="password" placeholder="Enter Password" name="password" required> <input type="hidden" name="nonce" th:value="${nonce}"> <input type="hidden" name="state" th:value="${state}"> <button type="submit">Login</button> </div> </form> </body> </html> |
5) success.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> Login Page </title> <style> Body { font-family: Calibri, Helvetica, sans-serif; background-color: pink; } button { background-color: #4CAF50; width: 100%; color: orange; padding: 15px; margin: 10px 0px; border: none; cursor: pointer; } form { border: 3px solid #f1f1f1; } input[type=text], input[type=password] { width: 100%; margin: 8px 0; padding: 12px 20px; display: inline-block; border: 2px solid green; box-sizing: border-box; } button:hover { opacity: 0.7; } .cancelbtn { width: auto; padding: 10px 18px; margin: 10px 5px; } .container { padding: 25px; background-color: lightblue; } </style> </head> <body> <center> <h1> Success </h1> </center> <center> <a href="/logout">Logout</a> </center> </body> </html> |
6) logout.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> Login Page </title> <style> Body { font-family: Calibri, Helvetica, sans-serif; background-color: pink; } button { background-color: #4CAF50; width: 100%; color: orange; padding: 15px; margin: 10px 0px; border: none; cursor: pointer; } form { border: 3px solid #f1f1f1; } input[type=text], input[type=password] { width: 100%; margin: 8px 0; padding: 12px 20px; display: inline-block; border: 2px solid green; box-sizing: border-box; } button:hover { opacity: 0.7; } .cancelbtn { width: auto; padding: 10px 18px; margin: 10px 5px; } .container { padding: 25px; background-color: lightblue; } </style> </head> <body> <center> <h1> Logout </h1> </center> <center> <a href="/">Login</a> </center> </body> </html> |
7) error.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <title> Login Page </title> <style> Body { font-family: Calibri, Helvetica, sans-serif; background-color: pink; } button { background-color: #4CAF50; width: 100%; color: orange; padding: 15px; margin: 10px 0px; border: none; cursor: pointer; } form { border: 3px solid #f1f1f1; } input[type=text], input[type=password] { width: 100%; margin: 8px 0; padding: 12px 20px; display: inline-block; border: 2px solid green; box-sizing: border-box; } button:hover { opacity: 0.7; } .cancelbtn { width: auto; padding: 10px 18px; margin: 10px 5px; } .container { padding: 25px; background-color: lightblue; } </style> </head> <body> <center> <h1> Error </h1> </center> <center> <a href="https://aurigait-464307254473032633.myfreshworks.com">Login With FreshDesk SSO !!!</a> </center> </body> </html> |
8) application.properties
1 |
server.port=8889 |
9) Run the Spring Boot Application
Configure Spring Boot Application with Freshdesk
1) Login into Freshdesk Application
2) Go to Admin Part
3) Go to Security Setttings and Activate Freshworks SSO
4) Configure SSO
5) Select JWT Method
6) Paste Login form url of Spring Boot Application in Authorization URL Paste RSA public key in RSA Public Key and Paste logout url of Spring Boot Application in Logout URL.
7) Click on configure SSO
8) Create JWT token
1 2 |
Header:- { "alg": "RS256", "typ": "JWT"} |
1 2 3 4 5 6 7 8 9 |
Payload:- Claims claims = Jwts.claims(); claims.put("sub", "Praveen1"); claims.put("email",email1); claims.put("iat", epoch); claims.put("nonce", nonce); claims.put("given_name", "Praveen"); claims.put("family_name", "Sanpada"); |
Signature:-
Generate
Public Key and Private Key:-
->
https://www.novixys.com/blog/how-to-generate-rsa-keys-java/
-
>
https://www.aurigait.com/blog/xml-signatures-build-a-secure-channel-for-data-exchange-and-communication/
->
https://www.baeldung.com/java-read-pem-file-keys
Use
Private key in Spring boot application for create or sign
ing
token
Use
Public key in FreshDesk Application in Configuration part
9
)
Read nonce and state part from url in Spring Boot Application
From
this url :-
https://sso-auriga-app.herokuapp.com/?response_type=id_token&client_id=464307824220156643&scope=openid%20email%20profile&state=YXVyaWdhaXQtNDY0MzA3MjU0NDczMDMyNjMzLm15ZnJlc2h3b3Jrcy5jb207RTJRaEFldGFRbU9icVMxa25vUHU4OXVZK1l3NTk5K0xQZUl2dGdKbm9Wdz07N2NXTXhxY05QUjRBSjEzag%3D%3D&redirect_uri=https://aurigait-464307254473032633.myfreshworks.com/sp/OIDC/464307824220156643/implicit®istration_id=464307824220156643&nonce=7cWMxqcNPR4AJ13j
10
)
Implement all this fields in given below code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
Path path = Paths.get("auriga.key"); byte[] bytes = Files.readAllBytes(path); PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes); KeyFactory kf = KeyFactory.getInstance("RSA"); PrivateKey pvt1 = kf.generatePrivate(ks); long epoch = System.currentTimeMillis()/1000; Claims claims = Jwts.claims(); claims.put("sub", "Praveen1"); claims.put("email",email1); claims.put("iat", epoch); claims.put("nonce", nonce); claims.put("given_name", "Praveen"); claims.put("family_name", "Sanpada"); Map<String, Object> headers = new HashMap<String, Object>(); headers.put("alg", "RS256"); headers.put("typ", "JWT"); String token = Jwts.builder() .setHeaderParams(headers) .setClaims(claims) .signWith(SignatureAlgorithm.RS256, pvt1).compact(); String rUrl = "https://aurigait-464307254473032633.myfreshworks.com/sp/OIDC/464307824220156643/implicit?state="+state+"&id_token="+token; |
11) Hit the given url
https://aurigait-464307254473032633.myfreshworks.com/
12) Click on SSO Login
13) You will redirect to Spring Boot Application login page
14) Input your login credentials of Spring Boot Application
15) On Successful login you will redirect to dashboard page of freshdesk ( Login Success in FreshDesk )
16) On Successful logout from freshdesk, you will redirect to logout of Spring Boot Application page
Thank You
Related content
Auriga: Leveling Up for Enterprise Growth!
Auriga’s journey began in 2010 crafting products for India’s