Skip to content

IAMDevBox/forgerock-am-email-otp-node

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

forgerock-am-email-otp-node

Production-ready HOTP-based Email OTP authentication node for ForgeRock Access Management (AM) 7.x.

MIT License Java 11+ RFC 4226


What This Repo Contains

File Purpose
HOTPGenerator.java RFC 4226–compliant HMAC-SHA1 OTP generator with test vectors
EmailOTPNode.java Full two-phase AM auth node (send → verify) with rate-limit protection
OTPEmailService.java SMTP delivery service with TLS, auth, and structured logging
EmailOTPNodePlugin.java AM plugin registration + Guice SMTP config bindings
HOTPGeneratorTest.java JUnit 5 tests validating all RFC 4226 Appendix D test vectors
pom.xml Maven build producing a deployable shaded JAR

📖 Full tutorial: Building an Email OTP Node in ForgeRock AM


How It Works

The node implements a two-phase authentication flow inside a ForgeRock AM tree:

[ Identify User ] → [ Profile Attribute Node ] → [ Email OTP Node ] → [ Success/Failure ]
                                                       │
                          ┌────────────────────────────┘
                          ▼
              1. SEND:  generateHOTP(secret, counter) → email OTP
              2. VERIFY: compare submitted OTP with stored value
              3. LOCK:  after N failed attempts → go to Failure outcome

HOTP generates time-independent OTPs based on:

  • A shared secret (stored as a Base64-encoded LDAP attribute hotpSecret)
  • An incrementing counter (stored in AM shared state, incremented after each send)

Prerequisites

  • ForgeRock AM 7.x (tested on 7.3, 7.4)
  • Java 11+ (JDK)
  • Maven 3.8+
  • ForgeRock Backstage account (for Maven dependencies)
  • An SMTP server (Gmail, SendGrid, SES, or corporate relay)

Quick Start

1. Clone and Build

git clone https://github.com/IAMDevBox/forgerock-am-email-otp-node.git
cd forgerock-am-email-otp-node

# Configure ForgeRock Maven credentials (one-time setup)
# Add to ~/.m2/settings.xml:
# <server><id>forgerock-releases</id><username>YOUR_EMAIL</username><password>YOUR_TOKEN</password></server>

mvn clean package -DskipTests

The deployable JAR is at target/forgerock-am-email-otp-node-1.0.0-deploy.jar.

2. Run Tests

mvn test
# All RFC 4226 Appendix D test vectors must pass

3. Deploy to ForgeRock AM

# Copy the shaded JAR to AM's custom node directory
cp target/forgerock-am-email-otp-node-1.0.0-deploy.jar \
   /path/to/am/WEB-INF/lib/

# Set SMTP environment variables (or use AM Secret Store)
export SMTP_HOST=smtp.example.com
export SMTP_PORT=587
export SMTP_USERNAME=noreply@example.com
export SMTP_PASSWORD=changeme
export SMTP_TLS=true
export SMTP_FROM=noreply@example.com

# Restart AM (Tomcat or container)

4. Configure in AM Console

  1. Navigate to Realms → Authentication → Trees
  2. Create a new tree or edit an existing one
  3. Drag Email OTP Node from the node panel
  4. Connect it after a Profile Attribute Node (to populate email in shared state)
  5. Configure node settings:
    • Max Attempts: 3 (recommended)
    • Look-Ahead Window: 1 (allow one counter step of tolerance)
    • Email Subject/Body: Customize for your branding

Shared State Requirements

Before the Email OTP Node runs, ensure these values are present in AM shared state:

Key Source Description
username Set by Identify User node The user's AM username
email Set by Profile Attribute Node (attribute: mail) Delivery address
hotpSecret Set by Profile Attribute Node (attribute: hotpSecret) Base64-encoded HOTP secret

Storing the HOTP Secret

Each user needs a unique Base64-encoded HOTP secret stored in their LDAP profile:

# Generate a 20-byte random secret (per RFC 4226 recommendation)
SECRET=$(openssl rand -base64 20)

# Store it in the user's LDAP entry (example: cn=jdoe,ou=people,dc=example,dc=com)
ldapmodify -h ldap.example.com -p 389 -D "cn=Directory Manager" -w changeme <<EOF
dn: uid=jdoe,ou=people,dc=example,dc=com
changetype: modify
replace: hotpSecret
hotpSecret: $SECRET
EOF

Configuration Reference

Config Field Default Description
maxAttempts 3 Failed attempts before the node returns False outcome
lookAheadWindow 1 Counter window tolerance for clock skew
emailSubject "Your one-time password for {realm}" Supports {realm} placeholder
emailBodyTemplate "Your one-time password is: {otp}…" Supports {otp} placeholder

SMTP config via environment variables:

Env Var Default Description
SMTP_HOST smtp.example.com SMTP server hostname
SMTP_PORT 587 SMTP port (587 for STARTTLS, 465 for SSL)
SMTP_USERNAME SMTP authentication username
SMTP_PASSWORD SMTP authentication password
SMTP_TLS true Enable STARTTLS
SMTP_FROM noreply@example.com From address

Security Considerations

  • Secret storage: Never log or expose hotpSecret. Mask emails in logs (see maskEmail() in EmailOTPNode.java).
  • Counter replay protection: Each OTP is valid for exactly one use. The counter increments on every send.
  • Rate limiting: The maxAttempts config prevents brute-force OTP enumeration.
  • TLS: Always enable SMTP_TLS=true in production. Never send OTPs over plaintext SMTP.
  • Secret rotation: Rotate hotpSecret periodically or on suspected compromise.

Related IAMDevBox Resources


License

MIT — see LICENSE.


Created and maintained by IAMDevBox.com — practical IAM tutorials for ForgeRock, Keycloak, and beyond.

About

Production-ready HOTP-based Email OTP authentication node for ForgeRock AM 7.x — RFC 4226 compliant with rate limiting and SMTP delivery

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages