{"id":44785023,"url":"https://github.com/remotiq/wa2fa-meta","last_synced_at":"2026-02-21T14:00:56.301Z","repository":{"id":338649118,"uuid":"1158535111","full_name":"RemotiQ/wa2fa-meta","owner":"RemotiQ","description":"Meta WhatsApp 2FA plugin for Keycloak (Java): OTP login step, phone verification required action, QR verify flow, and login security alerts.","archived":false,"fork":false,"pushed_at":"2026-02-16T07:32:18.000Z","size":156,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-16T15:21:23.257Z","etag":null,"topics":["2fa","keycloak","saml","security","sso","whatsapp"],"latest_commit_sha":null,"homepage":"https://www.remotiq.com.au/projects/wa2fa","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/RemotiQ.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-15T14:37:49.000Z","updated_at":"2026-02-16T07:25:18.000Z","dependencies_parsed_at":"2026-02-17T10:01:53.363Z","dependency_job_id":null,"html_url":"https://github.com/RemotiQ/wa2fa-meta","commit_stats":null,"previous_names":["remotiq/wa2fa-meta"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/RemotiQ/wa2fa-meta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemotiQ%2Fwa2fa-meta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemotiQ%2Fwa2fa-meta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemotiQ%2Fwa2fa-meta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemotiQ%2Fwa2fa-meta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RemotiQ","download_url":"https://codeload.github.com/RemotiQ/wa2fa-meta/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RemotiQ%2Fwa2fa-meta/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29539974,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-17T08:11:05.436Z","status":"ssl_error","status_checked_at":"2026-02-17T08:09:38.860Z","response_time":100,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2fa","keycloak","saml","security","sso","whatsapp"],"created_at":"2026-02-16T09:15:48.091Z","updated_at":"2026-02-18T11:00:59.723Z","avatar_url":"https://github.com/RemotiQ.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# wa2fa — WhatsApp 2FA for Keycloak (Meta Cloud API)\n\n`wa2fa` is a Keycloak 26.x provider bundle that adds WhatsApp-based authentication features using the Meta WhatsApp Cloud API.\n\n## What this plugin provides\n\n1. WhatsApp OTP as a login step (`Authenticator`)\n2. Phone verification flow (`Required Action`)\n3. Login alerts on successful sign-in (`Event Listener`)\n4. Optional QR scan verification with webhook callback (`Realm Resource Provider`)\n5. Optional HTTP SMS fallback when WhatsApp delivery fails\n\nSupported UI/message languages: `en`, `hi`, `es`, `fr`, `de`, `ar`, `pt`.\n\n## Scope in v1.1\n\nVersion `1.1` is Meta-only.\n\n## Compatibility\n\n- Keycloak: `26.x` (Quarkus distribution)\n- Java: `17+`\n- Maven: `3.9+`\n\n## Quick Start (Docker)\n\n1. Copy and edit env file:\n\n```bash\ncp .env.example .env\n```\n\n2. Start stack:\n\n```bash\ndocker compose up --build\n```\n\n3. Open Keycloak:\n\n- URL: `http://localhost:8080`\n- Admin user: `admin`\n- Admin password: `admin`\n\n## Build and Install Manually\n\n1. Build JAR:\n\n```bash\nmvn clean package\n```\n\n2. Copy provider:\n\n```bash\ncp target/wa2fa-1.1.jar /opt/keycloak/providers/\n```\n\n3. Rebuild Keycloak and start:\n\n```bash\n/opt/keycloak/bin/kc.sh build\n/opt/keycloak/bin/kc.sh start\n```\n\n## Registered Keycloak Providers\n\n- `AuthenticatorFactory`: `WhatsApp OTP (wa2fa)`\n- `RequiredActionFactory`: `Verify Phone Number via WhatsApp (wa2fa)`\n- `EventListenerProviderFactory`: `wa2fa-login-notification`\n- `RealmResourceProviderFactory`: `wa2fa`\n\nRuntime service registrations are in:\n\n- `src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory`\n- `src/main/resources/META-INF/services/org.keycloak.authentication.RequiredActionFactory`\n- `src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory`\n- `src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory`\n\n## Meta Setup Requirements\n\nYou need these from Meta Business / WhatsApp Manager:\n\n- Access Token\n- Phone Number ID\n- Approved template for OTP (default: `otp_message`)\n- Approved template for login alerts (default: `login_notification`)\n\n### Template parameters expected\n\n- OTP template: OTP code parameter\n- Login notification template: `username`, `timestamp`, `ip`, `browser`\n\n## Keycloak Configuration\n\n### 1) Browser Flow (OTP)\n\n1. Go to `Authentication -\u003e Flows`\n2. Duplicate `Browser` flow (recommended)\n3. Add execution: `WhatsApp OTP (wa2fa)`\n4. Set requirement to `REQUIRED`\n5. Configure authenticator settings\n\nRecommended structure:\n\n```text\nBrowser flow\n  Username Password Form (REQUIRED)\n  OTP sub-flow (REQUIRED)\n    WhatsApp OTP (wa2fa) (REQUIRED)\n```\n\nDo not keep a `Condition - user configured` gate in this OTP sub-flow if you want WhatsApp OTP consistently enforced.\n\n### 2) Required Action (phone verification)\n\n1. Go to `Authentication -\u003e Required Actions`\n2. Enable: `Verify Phone Number via WhatsApp (wa2fa)`\n\nThis flow writes/uses these user attributes:\n\n- `phoneNumber`\n- `phoneNumberVerified`\n- `phoneNumberVerifiedValue`\n\n### 3) Event Listener (login alert)\n\n1. Go to `Realm Settings -\u003e Events`\n2. Add listener: `wa2fa-login-notification`\n\n## Authenticator Config Fields\n\nConfigured in the execution settings for `WhatsApp OTP (wa2fa)`:\n\n- `wa2fa.accessToken`\n- `wa2fa.phoneNumberId`\n- `wa2fa.apiVersion`\n- `wa2fa.otpLength`\n- `wa2fa.otpExpiry`\n- `wa2fa.templateOtp`\n- `wa2fa.templateLogin`\n- `wa2fa.templateLoginLayout`\n- `wa2fa.defaultLanguage`\n- `wa2fa.defaultCountryCode`\n- `wa2fa.smsFallbackUrl`\n- `wa2fa.smsFallbackMethod`\n- `wa2fa.qrEnabled`\n- `wa2fa.otpEnabled`\n- `wa2fa.businessPhone`\n- `wa2fa.webhookVerifyToken`\n- `wa2fa.appSecret`\n- `wa2fa.maxResend`\n- `wa2fa.qrAckVerified`\n- `wa2fa.qrAckMismatch`\n- `wa2fa.qrAckExpired`\n- `wa2fa.qrAckNoMatch`\n\n## QR Verification Endpoints\n\nExposed under the realm resource provider `wa2fa`:\n\n- `GET /realms/{realm}/wa2fa/webhook` (Meta webhook verification)\n- `POST /realms/{realm}/wa2fa/webhook` (incoming message callback)\n- `GET /realms/{realm}/wa2fa/qr-status?token=...` (polling endpoint)\n\nIf `WA2FA_APP_SECRET` / `wa2fa.appSecret` is set, webhook payload signature (`X-Hub-Signature-256`) is verified.\n\n## Environment Variables\n\nCore env vars (also available in `.env.example`):\n\n- `WA2FA_ACCESS_TOKEN`\n- `WA2FA_PHONE_NUMBER_ID`\n- `WA2FA_API_VERSION`\n- `WA2FA_TEMPLATE_OTP`\n- `WA2FA_TEMPLATE_LOGIN`\n- `WA2FA_DEFAULT_LANGUAGE`\n- `WA2FA_DEFAULT_COUNTRY_CODE`\n- `WA2FA_OTP_EXPIRY`\n- `WA2FA_LOGIN_NOTIFICATION_ENABLED`\n- `WA2FA_LOGIN_NOTIFICATION_ASYNC`\n- `WA2FA_SMS_FALLBACK_URL`\n- `WA2FA_SMS_FALLBACK_METHOD`\n- `WA2FA_QR_ENABLED`\n- `WA2FA_BUSINESS_PHONE`\n- `WA2FA_WEBHOOK_VERIFY_TOKEN`\n- `WA2FA_APP_SECRET`\n\n## Notes on Fallback and Delivery\n\n- Delivery is attempted via WhatsApp first.\n- If configured, SMS fallback is attempted on WhatsApp failure.\n- Event details include channel/failure metadata for auditing.\n\n## Project Layout\n\n```text\nsrc/main/java/com/wa2fa/\n  action/               # Required action (phone verification)\n  authenticator/        # WhatsApp OTP authenticator\n  event/                # Login notification listener\n  qr/                   # Webhook + QR status resource\n  ...shared services/utilities\n\nsrc/main/resources/\n  META-INF/services/    # SPI registrations\n  theme-resources/      # FTL templates + i18n bundles + QR JS\n```\n\n## Troubleshooting\n\n1. Provider not visible in Keycloak:\n- Ensure JAR is in `/opt/keycloak/providers/`\n- Run `/opt/keycloak/bin/kc.sh build`\n- Restart Keycloak\n\n2. OTP not sent:\n- Verify token/phone-id values\n- Verify template exists and is approved\n- Check Keycloak logs for WhatsApp API errors\n\n3. QR flow not completing:\n- Ensure webhook URL points to `/realms/{realm}/wa2fa/webhook`\n- Ensure verify token matches\n- Set `WA2FA_APP_SECRET` for signed webhook validation\n\n4. Phone rejected:\n- Number is validated with libphonenumber\n- Use E.164 (`+...`) or set `WA2FA_DEFAULT_COUNTRY_CODE`\n\n## Development\n\nCompile only:\n\n```bash\nmvn -DskipTests compile\n```\n\nPackage:\n\n```bash\nmvn clean package\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremotiq%2Fwa2fa-meta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fremotiq%2Fwa2fa-meta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fremotiq%2Fwa2fa-meta/lists"}