{"id":29576018,"url":"https://github.com/mesutpiskin/keycloak-2fa-email-authenticator","last_synced_at":"2026-05-16T09:17:55.275Z","repository":{"id":62700900,"uuid":"554948576","full_name":"mesutpiskin/keycloak-2fa-email-authenticator","owner":"mesutpiskin","description":"🔒  Keycloak Authentication Provider implementation to get a two factor authentication with a OTP/code/token send via Email (through SMTP)","archived":false,"fork":false,"pushed_at":"2025-10-20T10:07:31.000Z","size":256,"stargazers_count":228,"open_issues_count":22,"forks_count":130,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-10-20T12:12:47.037Z","etag":null,"topics":["email-otp","keycloak","keycloak-spi","two-factor-authentication"],"latest_commit_sha":null,"homepage":"https://medium.com/@mesutpiskin/two-factor-authentication-via-email-in-keycloak-custom-auth-spi-935bbb3952a8","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mesutpiskin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"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":"2022-10-20T17:22:17.000Z","updated_at":"2025-10-20T10:07:35.000Z","dependencies_parsed_at":"2024-05-20T22:59:29.817Z","dependency_job_id":"ab6ff721-7d62-46f3-9e77-97dea363c7e8","html_url":"https://github.com/mesutpiskin/keycloak-2fa-email-authenticator","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/mesutpiskin/keycloak-2fa-email-authenticator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesutpiskin%2Fkeycloak-2fa-email-authenticator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesutpiskin%2Fkeycloak-2fa-email-authenticator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesutpiskin%2Fkeycloak-2fa-email-authenticator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesutpiskin%2Fkeycloak-2fa-email-authenticator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mesutpiskin","download_url":"https://codeload.github.com/mesutpiskin/keycloak-2fa-email-authenticator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mesutpiskin%2Fkeycloak-2fa-email-authenticator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28573281,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T15:45:05.669Z","status":"ssl_error","status_checked_at":"2026-01-19T15:44:23.317Z","response_time":67,"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":["email-otp","keycloak","keycloak-spi","two-factor-authentication"],"created_at":"2025-07-19T12:00:46.023Z","updated_at":"2026-05-16T09:17:55.266Z","avatar_url":"https://github.com/mesutpiskin.png","language":"Java","funding_links":[],"categories":["Java","Community Extensions","安全"],"sub_categories":["语音合成"],"readme":"# 🔒 Keycloak 2FA Email Authenticator\n\nA professional Keycloak Authentication Provider implementation for two-factor authentication (2FA) using One-Time Passwords (OTP) delivered via email. Supports multiple email providers (Keycloak SMTP, SendGrid, AWS SES, Mailgun).\n\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.mesutpiskin/keycloak-2fa-email-authenticator.svg)](https://central.sonatype.com/artifact/io.github.mesutpiskin/keycloak-2fa-email-authenticator)\n[![Keycloak Version](https://img.shields.io/badge/Keycloak-26.5.0-blue.svg)](https://www.keycloak.org/)\n[![Java Version](https://img.shields.io/badge/Java-21-orange.svg)](https://adoptium.net/)\n[![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)\n\n---\n\n## 📋 Table of Contents\n\n- [Overview](#-overview)\n- [Features](#-features)\n- [Prerequisites](#-prerequisites)\n- [Deployment](#-deployment)\n  - [Local Build \u0026 Deployment](#-local-build--deployment)\n  - [Docker/Podman Deployment](#-dockerpodman-deployment)\n- [Configuration](#-configuration)\n  - [Email Configuration](#email-configuration)\n  - [Authentication Flow Setup](#authentication-flow-setup)\n- [Local Testing](#-local-testing)\n- [Development](#-development)\n- [Resources](#-resources)\n- [Localization](#-localization)\n  - [Supported Languages](#supported-languages)\n  - [How to Add a New Language](#how-to-add-a-new-language)\n- [Contributing](#-contributing)\n- [License](#-license)\n\n---\n\n## 🎯 Overview\n\nThis Keycloak extension enables email-based two-factor authentication by sending a verification code (OTP) to the user's registered email address during login. The authenticator integrates seamlessly with Keycloak's authentication flow system.\n\n**Key Capabilities:**\n- Send OTP codes via multiple email providers (Keycloak SMTP, SendGrid, AWS SES, Mailgun)\n- Flexible provider selection with automatic fallback support\n- Customizable email templates\n- Conditional authentication support\n- Integration with Keycloak's authentication flow builder\n\n---\n\n## ✨ Features\n\n- ✅ Email-based OTP authentication\n- ✅ **Multiple email provider support** (Keycloak SMTP, SendGrid, AWS SES)\n- ✅ **Automatic fallback** to Keycloak SMTP if primary provider fails\n- ✅ **SendGrid integration** with API key authentication\n- ✅ **AWS SES integration** with IAM credentials and regional support\n- ✅ Customizable email templates\n- ✅ Conditional authentication flows\n- ✅ Multi-stage Docker build support\n- ✅ Compatible with Keycloak 26.x\n- ✅ Easy integration with existing authentication flows\n\n\\* *Mailgun support coming soon*\n\n---\n\n## 📦 Prerequisites\n\n### For Local Build:\n- **Java 21** or higher ([Download](https://adoptium.net/))\n- **Maven 3.9+** ([Download](https://maven.apache.org/download.cgi))\n\n### For Docker/Podman Build:\n- **Docker** ([Download](https://www.docker.com/)) or **Podman** ([Download](https://podman.io/))\n- (Optional) Docker Compose or Podman Compose\n\n---\n\n## 🚀 Deployment\n\n### Maven Central\n\nThe easiest way to get the JAR is via Maven Central. Pick the version matching your Keycloak installation:\n\n**Maven:**\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.mesutpiskin\u003c/groupId\u003e\n  \u003cartifactId\u003ekeycloak-2fa-email-authenticator\u003c/artifactId\u003e\n  \u003cversion\u003e26.3.0-KC26.6.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n**Gradle:**\n```groovy\nimplementation 'io.github.mesutpiskin:keycloak-2fa-email-authenticator:26.3.0-KC26.6.1'\n```\n\n\u003e Version format: `\u003cplugin-version\u003e-KC\u003ckeycloak-version\u003e` — e.g. `26.3.0-KC26.5.3` for Keycloak 26.5.3.\n\u003e All available versions: [Maven Central](https://central.sonatype.com/artifact/io.github.mesutpiskin/keycloak-2fa-email-authenticator)\n\n---\n\n### 🖥 Local Build \u0026 Deployment\n\n#### 1. Clone the Repository\n\n```bash\ngit clone https://github.com/mesutpiskin/keycloak-2fa-email-authenticator.git\ncd keycloak-2fa-email-authenticator\n```\n\n#### 2. Verify Prerequisites\n\nCheck your Java and Maven versions:\n\n```bash\njava -version  # Should show Java 21+\nmvn -version   # Should show Maven 3.9+\n```\n\n#### 3. Build the Project\n\n```bash\nmvn clean package\n```\n\nThis creates `target/keycloak-2fa-email-authenticator-v26.0.0-SNAPSHOT.jar`.\n\n\u003e **Note:** If tests fail due to Java version compatibility, use:\n\u003e ```bash\n\u003e mvn clean package -DskipTests\n\u003e ```\n\n#### 4. Deploy to Keycloak\n\n**For Standard Keycloak Installation:**\n\n```bash\ncp target/keycloak-2fa-email-authenticator-*.jar \u003cKEYCLOAK_HOME\u003e/providers/\n```\n\n**For Dockerized Keycloak:**\n\n```bash\ncp target/keycloak-2fa-email-authenticator-*.jar /opt/keycloak/providers/\n```\n\n#### 5. Rebuild Keycloak\n\n```bash\n\u003cKEYCLOAK_HOME\u003e/bin/kc.sh build\n```\n\n---\n\n### 🐳 Docker/Podman Deployment\n\nThis project includes a **multi-stage Dockerfile** for streamlined containerized deployment.\n\n#### Build the Container Image\n\n**Using Docker:**\n\n```bash\ndocker build -t keycloak-2fa-email:latest .\n```\n\n**Using Podman:**\n\n```bash\npodman build --tls-verify=false -t keycloak-2fa-email:latest .\n```\n\n\u003e **Note:** The `--tls-verify=false` flag may be needed with Podman if you encounter certificate verification issues.\n\n#### Run the Container\n\n**Using Docker:**\n\n```bash\ndocker run -p 8080:8080 \\\n  -e KEYCLOAK_ADMIN=admin \\\n  -e KEYCLOAK_ADMIN_PASSWORD=admin \\\n  keycloak-2fa-email:latest \\\n  start-dev\n```\n\n**Using Podman:**\n\n```bash\npodman run -p 8080:8080 \\\n  -e KEYCLOAK_ADMIN=admin \\\n  -e KEYCLOAK_ADMIN_PASSWORD=admin \\\n  keycloak-2fa-email:latest \\\n  start-dev\n```\n\n#### Using Docker Compose\n\nThe project includes a `docker-compose.yml` file for simplified deployment:\n\n```bash\ndocker-compose up\n```\n\n**Or with Podman:**\n\n```bash\npodman-compose up\n```\n\nAfter starting the container, Keycloak will be available at **http://localhost:8080**.\n\n#### Multi-Stage Build Process\n\nThe Dockerfile uses a two-stage build approach:\n\n| Stage | Base Image | Purpose |\n|-------|------------|---------|\n| **Builder** | `maven:3.9-eclipse-temurin-21` | Compiles the project with Maven and creates the provider JAR |\n| **Runtime** | `quay.io/keycloak/keycloak:26.0.0` | Copies the provider JAR and registers it with Keycloak |\n\n**Build Steps:**\n1. Maven compiles the source code (`mvn clean package -DskipTests`)\n2. JAR is copied to `/opt/keycloak/providers/`\n3. Keycloak configuration is updated (`kc.sh build`)\n\n---\n\n## ⚙️ Configuration\n\n### Email Configuration\n\nConfigure SMTP settings in your Keycloak realm to enable email delivery:\n\n1. **Login** as admin to your Keycloak installation\n2. **Switch** to your target realm\n3. Navigate to **Realm Settings** → **Email** tab\n4. Configure your SMTP server settings:\n   - SMTP Host\n   - SMTP Port\n   - From Email Address\n   - Authentication credentials (if required)\n   - Enable SSL/TLS (recommended)\n\n### Authentication Flow Setup\n\nCreate a custom authentication flow with email OTP:\n\n1. Navigate to **Authentication** → **Flows**\n2. **Create** a new browser flow (or copy the existing one)\n3. Add **Email OTP** authenticator after the **Username Password Form**\n4. Set the execution requirement to **Required** or **Alternative**\n5. **Bind** the new flow to the browser flow\n\n**Example Flow Configuration:**\n\n![Authentication Flow Example](docs/img/otp-form.png)\n\n### Email Provider Configuration\n\nThe authenticator supports multiple email service providers for enhanced flexibility and reliability.\n\n#### Supported Providers\n\n| Provider | Description | Requirements |\n|----------|-------------|--------------|\n| **Keycloak SMTP** (Default) | Uses Keycloak's built-in SMTP configuration | Realm SMTP settings configured |\n| **SendGrid** | SendGrid cloud email service | SendGrid API key and from email |\n| **AWS SES** | Amazon Simple Email Service | AWS credentials, region, and verified sender |\n| **Mailgun** | Mailgun email delivery service | *Coming soon* |\n\n---\n\n## 🎨 Template Customization\n\nYou can fully customize both the visual appearance (HTML) and the text content of the emails sent by this authenticator.\n\n### 1. Customizing the HTML Layout\n\nCustomizing the email's visual design (logo, colors, layout):\n\n**File:** `src/main/resources/theme-resources/templates/html/code-email.ftl`\n\nYou can replace the default FreeMarker template with your own HTML structure.\n\n**Example HTML Template:**\n\n```html\n\u003chtml\u003e\n\u003cbody style=\"font-family: Arial, sans-serif; padding: 20px; color: #333;\"\u003e\n    \u003cdiv style=\"background-color: #f5f5f5; padding: 30px; border-radius: 8px; text-align: center;\"\u003e\n        \u003c!-- Add your logo here --\u003e\n        \u003cimg src=\"https://your-domain.com/logo.png\" alt=\"Logo\" style=\"height: 50px; margin-bottom: 20px;\" /\u003e\n\n        \u003ch2 style=\"color: #007bff;\"\u003eVerification Code\u003c/h2\u003e\n\n        \u003cdiv style=\"background-color: white; padding: 20px; margin: 20px 0; border: 1px solid #ddd;\"\u003e\n            \u003ch1 style=\"font-size: 36px; letter-spacing: 5px; margin: 0;\"\u003e${code}\u003c/h1\u003e\n        \u003c/div\u003e\n\n        \u003cp\u003eThis code will expire in \u003cstrong\u003e${ttl}\u003c/strong\u003e seconds.\u003c/p\u003e\n        \u003cp style=\"font-size: 12px; color: #888;\"\u003eIf you did not request this code, please ignore this email.\u003c/p\u003e\n    \u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### 2. Customizing Text Content (Localization)\n\nChanging the subject line and body text for different languages:\n\n**File:** `src/main/resources/theme-resources/messages/messages_\u003clang\u003e.properties`\n\n**Available placeholders:**\n- `{0}` : The generated OTP code\n- `{1}` : Time-to-live (expiration time) in seconds/minutes\n\n**Example (`messages_en.properties`):**\n\n```properties\n# Custom Subject\nemailCodeSubject=Your Secure Login Code: {0}\n\n# Custom Body Text (supports \\n for new lines)\nemailCodeBody=Here is your one-time password: {0}.\\n\\nIt is valid for {1} minutes. Do not share this code.\n```\n\n\u003e **Important:** After making changes to templates or properties, you must **rebuild and redeploy** the project (`mvn clean package`) for changes to take effect.\n\n\n#### Configure Email Provider in Authentication Flow\n\n1. Navigate to **Authentication** → **Flows**\n2. Select your custom flow containing the **Email OTP** authenticator\n3. Click the **⚙️ (gear/settings)** icon next to **Email OTP**\n4. Configure the provider settings:\n\n**Option 1: Use Keycloak SMTP (Default)**\n```\nEmail Provider: KEYCLOAK\nEnable Fallback to Keycloak SMTP: true\n```\nNo additional configuration needed. Uses realm SMTP settings.\n\n**Option 2: Use SendGrid**\n```\nEmail Provider: SENDGRID\nSendGrid API Key: SG.xxxxxxxxxxxxxxxxxxxx\nSendGrid From Email: noreply@yourdomain.com\nSendGrid From Name: Your Company Name  (optional)\nEnable Fallback to Keycloak SMTP: true  (recommended)\n```\n\n**Option 3: Use AWS SES**\n```\nEmail Provider: AWS_SES\nAWS SES Region: us-east-1\nAWS Access Key ID: AKIAIOSFODNN7EXAMPLE\nAWS Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\nAWS SES From Email: noreply@yourdomain.com\nAWS SES From Name: Your Company Name  (optional)\nEnable Fallback to Keycloak SMTP: true  (recommended)\n```\n\n#### SendGrid Setup\n\n1. **Get SendGrid API Key:**\n   - Sign up at [SendGrid](https://sendgrid.com/)\n   - Navigate to **Settings** → **API Keys** → **Create API Key**\n   - Select **Full Access** or **Restricted Access** with **Mail Send** permissions\n   - Copy the API key (starts with `SG.`)\n\n2. **Verify Sender Identity:**\n   - Navigate to **Settings** → **Sender Authentication**\n   - Either verify a single sender email address OR\n   - Set up domain authentication for your sending domain\n\n3. **Configure in Keycloak:**\n   - Enter the API key in **SendGrid API Key** field\n   - Enter your verified sender email in **SendGrid From Email**\n   - Optionally set a friendly display name\n\n#### AWS SES Setup\n\n1. **Create IAM User with SES Permissions:**\n   - Go to AWS IAM Console → Users → Create User\n   - Attach policy: `AmazonSESFullAccess` (or create custom policy with `ses:SendEmail` permission)\n   - Create access keys and save the Access Key ID and Secret Access Key\n\n2. **Verify Sender Email or Domain:**\n   - Go to AWS SES Console → Verified identities\n   - Click **Create identity**\n   - For testing: Verify a single email address\n   - For production: Verify your domain (requires DNS configuration)\n   - Follow email/DNS verification steps\n\n3. **Request Production Access (if needed):**\n   - By default, AWS SES starts in **Sandbox mode**\n   - In Sandbox, you can only send to verified addresses\n   - To send to any email: Request production access in SES Console\n\n4. **Choose AWS Region:**\n   - SES is available in specific regions (e.g., us-east-1, eu-west-1)\n   - Choose region close to your users for lower latency\n   - Note: Verified identities are region-specific\n\n5. **Configure in Keycloak:**\n   - Select `AWS_SES` from Email Provider dropdown\n   - Enter AWS region (e.g., `us-east-1`)\n   - Enter IAM access key ID\n   - Enter IAM secret access key\n   - Enter verified sender email\n   - Optionally set sender display name\n\n#### Fallback Mechanism\n\nWhen **Enable Fallback to Keycloak SMTP** is enabled (recommended):\n- If the primary provider fails, the system automatically falls back to Keycloak's SMTP\n- Ensures email delivery reliability even if 3rd party service is unavailable\n- Fallback events are logged for monitoring\n\n---\n\n## 💻 Development\n\n### Running Tests\n\n```bash\nmvn test\n```\n\n\u003e **Note:** Tests may fail on Java 25+ due to Mockito/ByteBuddy compatibility. Use Java 21 for development.\n\n---\n\n## 🧪 Local Testing\n\nFor detailed instructions on testing this authenticator locally with Podman or Docker, see:\n\n**[📖 Local Testing Guide](docs/LOCAL_TESTING.md)**\n\nQuick start:\n```bash\n# Build and run with Podman\npodman build -t keycloak-email-auth:latest .\npodman run -d --name keycloak-test \\\n  -p 8080:8080 \\\n  -e KEYCLOAK_ADMIN=admin \\\n  -e KEYCLOAK_ADMIN_PASSWORD=admin \\\n  keycloak-email-auth:latest start-dev\n```\n\nAccess admin console at: http://localhost:8080/admin\n\n---\n\n## 📚 Resources\n\n- [Keycloak Server Development Documentation](https://www.keycloak.org/docs/latest/server_development/index.html)\n- [Keycloak Official Website](https://www.keycloak.org/)\n\n---\n\n## 🌍 Localization\n\nThis project supports multiple languages for a better user experience across different regions.\n\n### Supported Languages\n\n| Language | Code | File | Status |\n|----------|------|------|--------|\n| 🇬🇧 English | `en` | `messages_en.properties` | ✅ Complete |\n| 🇹🇷 Turkish | `tr` | `messages_tr.properties` | ✅ Complete |\n| 🇫🇷 French | `fr` | `messages_fr.properties` | ✅ Complete |\n| 🇮🇹 Italian | `it` | `messages_it.properties` | ✅ Complete |\n| 🇪🇸 Spanish | `es` | `messages_es.properties` | ✅ Complete |\n| 🇩🇰 Danish | `da` | `messages_da.properties` | ✅ Complete |\n| 🇩🇪 German | `de` | `messages_de.properties` | ✅ Complete |\n| 🇷🇺 Russian | `ru` | `messages_ru.properties` | ✅ Complete |\n| 🇦🇿 Azerbaijani | `az` | `messages_az.properties` | ✅ Complete |\n| 🇸🇦 Arabic | `ar` | `messages_ar.properties` | ✅ Complete |\n| 🇹🇼 Chinese (Traditional) | `zh_TW` | `messages_zh_TW.properties` | ✅ Complete |\n\n### How to Add a New Language\n\nWe welcome contributions for additional language support! Here's how you can add a new language:\n\n1. **Navigate to the messages directory:**\n   ```bash\n   cd src/main/resources/theme-resources/messages/\n   ```\n\n2. **Create a new properties file:**\n   ```bash\n   cp messages_en.properties messages_\u003clanguage_code\u003e.properties\n   ```\n   Replace `\u003clanguage_code\u003e` with the appropriate ISO 639-1 language code (e.g., `de` for German, `es` for Spanish, `ja` for Japanese).\n\n3. **Translate the content:**\n   Open the new file and translate all text values while keeping the keys unchanged:\n   ```properties\n   # Example for German (messages_de.properties)\n   resendCode=Code erneut senden\n   emailOtpForm=Bitte geben Sie den sechsstelligen Code ein, der an Ihre E-Mail gesendet wurde.\n   ```\n\n4. **Test your translation:**\n   - Build the project: `mvn clean package`\n   - Deploy to Keycloak\n   - Switch your browser/Keycloak to the new language\n   - Verify all messages display correctly\n\n5. **Submit a Pull Request:**\n   - Fork the repository\n   - Create a feature branch: `git checkout -b add-\u003clanguage\u003e-translation`\n   - Commit your changes: `git commit -m \"Add \u003clanguage\u003e translation\"`\n   - Push to your fork and submit a PR\n\n### Translation Keys Reference\n\nHere are the main translation keys used in this authenticator:\n\n```properties\nresendCode=Resend Code\nemailOtpForm=Please enter the six digit code...\nemailCodeSubject={0} access code\nemailCodeBody=Access code: {0}...\nemail-authenticator-display-name=Email Authenticator\nemail-authenticator-help-text=Receive a one-time verification code...\nemail-authenticator-setup-title=Set up Email Authenticator\nemail-authenticator-setup-description=Use this option to receive...\nemail-authenticator-setup-button=Enable Email Authenticator\nemail-authenticator-setup-cancelled=Email authenticator setup cannot...\nemail-authenticator-setup-error=We couldn't enable Email Authenticator...\nemail-authenticator-setup-missing-email=Add an email address...\nemail-authenticator-resend-cooldown=Please wait {0} seconds...\n```\n\n\u003e **Note:** Text inside curly braces like `{0}`, `{1}` are placeholders for dynamic values. Do not translate these.\n\n---\n\n## 🤝 Contributing\n\nContributions are welcome! Here's how you can help:\n\n### Ways to Contribute\n\n1. **🌍 Add New Translations** - Follow the [localization guide](#how-to-add-a-new-language) above\n2. **🐛 Report Bugs** - Open an issue with details about the problem\n3. **✨ Suggest Features** - Share your ideas via GitHub issues\n4. **🔧 Submit Pull Requests** - Fix bugs or implement new features\n\n### Contribution Guidelines\n\n1. **Fork** the repository\n2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)\n3. **Commit** your changes (`git commit -m 'Add amazing feature'`)\n4. **Push** to the branch (`git push origin feature/amazing-feature`)\n5. **Open** a Pull Request\n\n### Code Standards\n\n- Follow existing code style and conventions\n- Add comments for complex logic\n- Update documentation when needed\n- Test your changes thoroughly\n\n---\n\n## 📄 License\n\nThis project is licensed under the Apache License 2.0. See the [LICENSE](LICENSE) file for details.\n\n---\n\n**Made with ❤️ for the Keycloak community**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmesutpiskin%2Fkeycloak-2fa-email-authenticator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmesutpiskin%2Fkeycloak-2fa-email-authenticator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmesutpiskin%2Fkeycloak-2fa-email-authenticator/lists"}