Home/SSO With Freshdesk and Spring Boot Application using JWT

SSO With Freshdesk and Spring Boot Application using JWT

Published On: 13 July 2022.By .
  • General

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

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

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

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

<!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

<!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

<!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

<!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

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

Header:-
{ "alg": "RS256", "typ": "JWT"}
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
signing
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&registration_id=464307824220156643&nonce=7cWMxqcNPR4AJ13j

10)Implement all this fields in given below code

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

We Love Conversations

Say Hello
Go to Top