Affinidi Login with Java
The Affinidi Login is a passwordless authentication solution that verifies user identity using Affinidi Vault as the identity provider managed by the end-user.
In this lab, we will use JAVA 21 and Springboot from the available sample applications to take you through the step-by-step guide for creating a Login Configuration and setting up the application to implement passwordless authentication for end-users.
Before you begin
- Set up Affinidi Vault account. Follow the guide below if you haven’t set it up yet.
Get the Redirect URI of your application for OIDC. This is the URI configured on your Login Configuration to receive the idToken after successful authorisation.
Optionally, Install the Affinidi CLI. Follow the guide below if it hasn’t been installed.
- Install JAVA 21 on your machine if you haven’t installed yet using this guide.
Download Application
You can clone this sample application from our Github and start exploring how to integrate Affinidi Login to provide a passwordless login experience for your end-users.
Important Note
The downloadable sample application is provided only as a guide to quickly explore and learn how to integrate the components of Affinidi Trust Network into your application. This is NOT a Production-ready implementation. Do not deploy this to a production environment.Create Login Configuration
To create a Login Configuration, you can either use Affinidi CLI or Affinidi Portal.
Expand the section below for your preferred method:
Java Springboot App Settings:
Name: Java Springboot App
Redirect URIs: http://localhost:8080/login/oauth2/code/javademo
Expand the section below for your preferred method:
Login Configuration uses the default Presentation Definition (presentationDefinition) and ID Token Mapping (idTokenMapping) that is used to request the user’s email address during the authentication flow.
Learn more about customising the Presentation Definition and ID Token using this guide.
Important
Safeguard the Client ID and Client Secret diligently; you'll need them for setting up your IdP or OIDC-compliant applications. Remember, the Client Secret will be provided only once.
Set up the Sample Application
After creating the Login Configuration required to set up the sample application. Let’s start setting up the Java application by configuring the following settings:
Configure Env Variables
Create the .env file using the following command:
cp .env.example .env
Set the environment variables based on the auth credentials received from the Login Configuration created earlier:
{
"auth": {
"clientId": "<AUTH.CLIENT_ID>",
"clientSecret": "<AUTH.CLIENT_SECRET>",
"issuer": "https://<PROJECT_ID>.apse1.login.affinidi.io"
}
}
Set the following fields in the .env
file
PROVIDER_CLIENT_ID=<AUTH.CLIENT_ID>
PROVIDER_CLIENT_SECRET=<AUTH.CLIENT_SECRET>
PROVIDER_ISSUER=<AUTH.CLIENT_ISSUER>
Note
Do not enclose the above values with double quotes ("") while updating. As an example, below is your .env should look like below.PROVIDER_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxx
PROVIDER_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxx
PROVIDER_ISSUER=https://xxxxxxxxxxxxxxxxxxxxx.apse1.login.affinidi.io
Build and Run
sh mvnw clean
sh mvnw install
sh mvnw spring-boot:run
After successfully running the command, go to http://localhost:8080/ to access the page with the Affinidi Login button.
Key Changes to Sample Application
To enable a seamless passwordless login experience with Affinidi Login, refer to the following key changes were implemented:
- Registered
javademo
as the oauth2 client provider in the./src/main/resources/application.yml
including the client credentials.
spring:
security:
oauth2:
client:
registration:
javademo:
client-name: Affinidi Login
client-id: ${PROVIDER_CLIENT_ID}
client-secret: ${PROVIDER_CLIENT_SECRET}
redirect-uri: http://localhost:8080/login/oauth2/code/javademo
scope: openid,offline_access
client-authentication-method: client_secret_post
provider: afflogin
provider:
afflogin:
issuer-uri: ${PROVIDER_ISSUER}
config:
import:
optional:file:.env[.properties]
logging:
level:
org.springframework: WARN
login.affinidi: INFO
server:
port: 8080
- Implemented the following method in the
./java/login/affinidi/client/controller/UserController.java
:user
method to extract the user claims from the ID Token provided by the Affinidi Login.populateModel
method populates the user model from the ID Token to display on UI.
package login.affinidi.client.controller;
import java.util.ArrayList;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.nimbusds.jose.shaded.gson.internal.LinkedTreeMap;
@Controller
public class UserController {
@GetMapping("/")
public String index(){
return "index";
}
/**
* This method acts as handler for /user endpoint. It extracs details from
* authenticator oidc user for user interface
*
* @param model
* @param oidcUser
* @return
*/
@GetMapping("/user")
public String user(Model model,
@AuthenticationPrincipal OidcUser oidcUser) {
@SuppressWarnings("unchecked")
ArrayList<LinkedTreeMap<String, Object>> customNodeFromToken =
(ArrayList<LinkedTreeMap<String, Object>>)oidcUser.getAttributes().get("custom");
populateModel(customNodeFromToken, model);
return "user";
}
/**
* This method extracts every populated attribute from custom node of idToken
* and adds it to UI model for display
*
* @param customNodeFromToken
* @param model
*/
private void populateModel(ArrayList<LinkedTreeMap<String, Object>> customNodeFromToken, Model model){
for(LinkedTreeMap<String, Object> eachAttribute : customNodeFromToken){
if(eachAttribute != null){
for(String key : eachAttribute.keySet()){
model.addAttribute(key, eachAttribute.get(key));
}
}
}
}
}
Summary
sequenceDiagram actor User participant Java participant Affinidi Login participant Affinidi Vault participant Affinidi Verifier User->>Java: My Login Java->>Affinidi Login: Authenticate user Note over Java, Affinidi Login: login_challenge Affinidi Login->>Affinidi Vault: Verify user identity Note over Affinidi Login, Affinidi Vault: presentationDefinition Affinidi Vault->>User: Request user confirmation to share Email VC User->>Affinidi Vault: User confirmed consent to share Email VC Affinidi Vault->>Affinidi Vault: Generate VP Token from VC Affinidi Vault->>Affinidi Login: Send Email VP Token Affinidi Login->>Affinidi Verifier: Validate VP Token Note over Affinidi Login, Affinidi Verifier: vp_token, presentation_submission, presentation_definition Affinidi Login->>Affinidi Login: Generate idToken Affinidi Login->>Java: Send generated idToken from VP Java->>User: Provide access to the user
Using the Java and Springboot as the sample application, we have configured it to integrate with Affinidi Login as the Auth provider and parse the idToken sent by the Affinidi Login to confirm the user’s successful authentication using the Affinidi Vault.
Glad to hear it! Please tell us how we can improve more.
Sorry to hear that. Please tell us how we can improve.
Thank you for sharing your feedback so we can improve your experience.