Skip to content

Conversation

@imesh94
Copy link
Contributor

@imesh94 imesh94 commented Nov 28, 2025

[OB4] Add SMS OTP verification for the consent flow

Explain in a few lines the purpose of this pull request

Issue link: required

Doc Issue: Optional, link issue from documentation repository

Applicable Labels: Spec, product, version, type (specify requested labels)


Development Checklist

  1. Build complete solution with pull request in place.
  2. Ran checkstyle plugin with pull request in place.
  3. Ran Findbugs plugin with pull request in place.
  4. Ran FindSecurityBugs plugin and verified report.
  5. Formatted code according to WSO2 code style.
  6. Have you verified the PR doesn't commit any keys, passwords, tokens, usernames, or other secrets?
  7. Migration scripts written (if applicable).
  8. Have you followed secure coding standards in WSO2 Secure Engineering Guidelines?

Testing Checklist

  1. Written unit tests.
  2. Verified tests in multiple database environments (if applicable).
  3. Tested with BI enabled (if applicable).

@coderabbitai
Copy link

coderabbitai bot commented Nov 28, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment on lines +144 to +152
// Store userId in session for OTP verification (extracted from consent retrieval response)
// The userId (SCIM ID) is now added to the response JSON by ConsentAuthorizeEndpoint
if (dataSet.has(Constants.USER_ID)) {
String userId = dataSet.getString(Constants.USER_ID);
session.setAttribute(Constants.USER_ID, userId);
log.debug("Stored userId in session: " + userId);
} else {
log.warn("userId not found in consent data response");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 1

Suggested change
// Store userId in session for OTP verification (extracted from consent retrieval response)
// The userId (SCIM ID) is now added to the response JSON by ConsentAuthorizeEndpoint
if (dataSet.has(Constants.USER_ID)) {
String userId = dataSet.getString(Constants.USER_ID);
session.setAttribute(Constants.USER_ID, userId);
log.debug("Stored userId in session: " + userId);
} else {
log.warn("userId not found in consent data response");
}
// The userId (SCIM ID) is now added to the response JSON by ConsentAuthorizeEndpoint
if (dataSet.has(Constants.USER_ID)) {
String userId = dataSet.getString(Constants.USER_ID);
session.setAttribute(Constants.USER_ID, userId);
if (log.isDebugEnabled()) {
log.debug("Stored userId in session for OTP verification");
}
} else {
log.warn("userId not found in consent data response");
}

Comment on lines +112 to +116
session.setAttribute(SESSION_USER_ID, userId);

try {

GenerationResponseDTO otpResponse = smsotpService.generateSMSOTP(userId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 2

Suggested change
session.setAttribute(SESSION_USER_ID, userId);
try {
GenerationResponseDTO otpResponse = smsotpService.generateSMSOTP(userId);
try {
GenerationResponseDTO otpResponse = smsotpService.generateSMSOTP(userId);
log.info("OTP generation initiated for user ID: {}", userId);
String transactionId = otpResponse.getTransactionId();

Comment on lines +142 to +145
}

try {
ValidationResponseDTO validationResponse = smsotpService.validateSMSOTP(transactionId, userId, providedOtp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 3

Suggested change
}
try {
ValidationResponseDTO validationResponse = smsotpService.validateSMSOTP(transactionId, userId, providedOtp);
ValidationResponseDTO validationResponse = smsotpService.validateSMSOTP(transactionId, userId, providedOtp);
if (validationResponse.isValid()) {
log.info("OTP verified successfully for user ID: {}", userId);
session.removeAttribute(SESSION_OTP_TRANSACTION_ID);

Comment on lines +12 to +16
import java.nio.charset.StandardCharsets;

/**
* HTTP client for calling the SMS OTP service.
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 4

Suggested change
import java.nio.charset.StandardCharsets;
/**
* HTTP client for calling the SMS OTP service.
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* HTTP client for calling the SMS OTP service.
*/
public class OTPAPIClient {
private static final Log log = LogFactory.getLog(OTPAPIClient.class);

Comment on lines +22 to +34
public static JSONObject generateOtp(String userId) throws IOException {
JSONObject payload = new JSONObject();
payload.put("userId", userId);

CloseableHttpClient client = HTTPClientUtils.getHttpsClient();
HttpPost post = new HttpPost(GENERATE_URL);
post.setHeader("Content-Type", "application/json");
post.setEntity(new StringEntity(payload.toString()));

try (CloseableHttpResponse response = client.execute(post)) {
String json = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
return new JSONObject(json);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 5

Suggested change
public static JSONObject generateOtp(String userId) throws IOException {
JSONObject payload = new JSONObject();
payload.put("userId", userId);
CloseableHttpClient client = HTTPClientUtils.getHttpsClient();
HttpPost post = new HttpPost(GENERATE_URL);
post.setHeader("Content-Type", "application/json");
post.setEntity(new StringEntity(payload.toString()));
try (CloseableHttpResponse response = client.execute(post)) {
String json = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
return new JSONObject(json);
}
public static JSONObject generateOtp(String userId) throws IOException {
if (log.isDebugEnabled()) {
log.debug("Generating OTP for user: " + userId);
}
JSONObject payload = new JSONObject();
payload.put("userId", userId);
CloseableHttpClient client = HTTPClientUtils.getHttpsClient();
HttpPost post = new HttpPost(GENERATE_URL);
post.setHeader("Content-Type", "application/json");
post.setEntity(new StringEntity(payload.toString()));
try (CloseableHttpResponse response = client.execute(post)) {
int statusCode = response.getStatusLine().getStatusCode();
String json = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
if (statusCode == 200) {
log.info("OTP generated successfully for user: " + userId);
} else {
log.error("Failed to generate OTP. Status code: " + statusCode);
}
return new JSONObject(json);
}

Comment on lines 233 to +241
ConsentUtils.setCommonDataToResponse(consentData, jsonObject);

// Add userId (SCIM ID) to the response JSON for OTP verification
if (sensitiveDataMap.containsKey(ConsentConstants.LOGGED_IN_USER)) {
String userId = (String) sensitiveDataMap.get(ConsentConstants.LOGGED_IN_USER);
if (userId != null && !userId.isEmpty()) {
jsonObject.put(ConsentExtensionConstants.USER_ID, userId);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 6

Suggested change
ConsentUtils.setCommonDataToResponse(consentData, jsonObject);
// Add userId (SCIM ID) to the response JSON for OTP verification
if (sensitiveDataMap.containsKey(ConsentConstants.LOGGED_IN_USER)) {
String userId = (String) sensitiveDataMap.get(ConsentConstants.LOGGED_IN_USER);
if (userId != null && !userId.isEmpty()) {
jsonObject.put(ConsentExtensionConstants.USER_ID, userId);
}
}
ConsentUtils.setCommonDataToResponse(consentData, jsonObject);
// Add userId (SCIM ID) to the response JSON for OTP verification
if (sensitiveDataMap.containsKey(ConsentConstants.LOGGED_IN_USER)) {
String userId = (String) sensitiveDataMap.get(ConsentConstants.LOGGED_IN_USER);
if (userId != null && !userId.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug("Adding userId to consent response for OTP verification");
}
jsonObject.put(ConsentExtensionConstants.USER_ID, userId);

Copy link
Contributor

@wso2-engineering wso2-engineering bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Agent Log Improvement Checklist

⚠️ Warning: AI-Generated Review Comments

  • The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
  • Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.

✅ Before merging this pull request:

  • Review all AI-generated comments for accuracy and relevance.
  • Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
Comment Accepted (Y/N) Reason
#### Log Improvement Suggestion No: 1
#### Log Improvement Suggestion No: 2
#### Log Improvement Suggestion No: 3
#### Log Improvement Suggestion No: 4
#### Log Improvement Suggestion No: 5
#### Log Improvement Suggestion No: 6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant