{"id":18780511,"url":"https://github.com/wunderwerkio/drupal-magic-code","last_synced_at":"2025-12-18T20:30:40.854Z","repository":{"id":182861455,"uuid":"623870732","full_name":"wunderwerkio/drupal-magic-code","owner":"wunderwerkio","description":"Implements a Magic Code Verification Provider for the Drupal Verification API.","archived":false,"fork":false,"pushed_at":"2023-07-21T17:06:33.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"1.0.x","last_synced_at":"2024-12-29T10:44:08.723Z","etag":null,"topics":["decoupled-drupal","drupal","drupal-10-module","drupal-9-module","drupal-module"],"latest_commit_sha":null,"homepage":"https://www.drupal.org/project/magic_code","language":"PHP","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/wunderwerkio.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":null,"support":null,"governance":null}},"created_at":"2023-04-05T09:09:20.000Z","updated_at":"2023-04-06T12:41:38.000Z","dependencies_parsed_at":"2023-07-21T22:28:12.315Z","dependency_job_id":"c8d96343-1312-47a1-8a6c-cc44be42887a","html_url":"https://github.com/wunderwerkio/drupal-magic-code","commit_stats":null,"previous_names":["wunderwerkio/drupal-magic-code"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wunderwerkio%2Fdrupal-magic-code","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wunderwerkio%2Fdrupal-magic-code/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wunderwerkio%2Fdrupal-magic-code/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wunderwerkio%2Fdrupal-magic-code/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wunderwerkio","download_url":"https://codeload.github.com/wunderwerkio/drupal-magic-code/tar.gz/refs/heads/1.0.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239696358,"owners_count":19682222,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["decoupled-drupal","drupal","drupal-10-module","drupal-9-module","drupal-module"],"created_at":"2024-11-07T20:26:43.224Z","updated_at":"2025-12-18T20:30:35.091Z","avatar_url":"https://github.com/wunderwerkio.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Important Notice\n\nThe version control was moved to Drupal's GitLab instance!  \nSee https://www.drupal.org/project/magic_code for more info!\n\n---\n\n# Magic Code\n\n[![Lint \u0026 Test](https://github.com/wunderwerkio/drupal-magic-code/actions/workflows/main.yml/badge.svg)](https://github.com/wunderwerkio/drupal-magic-code/actions/workflows/main.yml)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=wunderwerkio_drupal-magic-code\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=wunderwerkio_drupal-magic-code)\n\nThe Magic Code Drupal module integrates with the [Verification API](https://github.com/wunderwerkio/drupal-verification) and adds a `VerificationProvider` that handles verification via so-called **Magic Codes** (short, alphanumeric codes that the user may also type manually).\n\n**Table of Contents:**\n\n- [Motivation](#motivation)\n- [How it works](#how-it-works)\n  - [Code value](#code-value)\n  - [The magic code entity](#the-magic-code-entity)\n  - [Request Verification Data](#request-verification-data)\n  - [Security Considerations](#security-considerations)\n- [Usage](#usage)\n  - [Generate a magic code](#generate-a-magic-code)\n  - [Verify a magic code](#verify-a-magic-code)\n  - [Use Magic Codes in E-Mail Templates](#use-magic-codes-in-e-mail-templates)\n    - [Caveats](#caveats)\n\n## Motivation\n\nUsing magic codes for verification (e.g. like Slack does it) is a popular and convenient way for users to verify a given operation or a passwordless login.\n\nThis module handles the creation, verification, and invalidation of those codes.\n\n## How it works\n\nA basic flow of how to use magic codes looks something like this:\n\n1. Create a Magic Code for a given user and operation\n2. Code is being sent to the user via E-Mail\n3. User inputs this code somewhere (e.g. Verification form)\n4. The code is then being validated by the Controller of the given operation\n5. If the code is correct, it is invalidated and the operation is permitted to continue\n\n### Code value\n\nThe code value consists of six uppercase alphanumeric characters that are separated by a dash in the middle.\n\nE.g. `D3C-57X`\n\n**The characters `0` and `O` are excluded to avoid user confusion.**\n\nThis length was chosen to find a sweet spot between convenience and security.\n\n### The magic code entity\n\nThe magic code entity has the following important fields:\n\n- `auth_user_id` The user who is eligible to use this magic code.\n- `client` The consumer client that this magic code can be used with.\n- `email` The email address the code was generated for. This may be different from the user's email address, when e.g. validating a new email address for the user.\n- `operation` The operation this magic code verifies.\n- `expired` When this magic code expires.\n- `login_allowed` Whether this magic code can be used to log in the user before executing the `operation`.\n- `status` Whether this magic code can be used or not.\n\nIn summary, a magic code can only be used to verify an operation if the following parameters are true:\n\n- The code is being used by the same consumer client it was generated for.\n- The request includes the same email address that this magic code was generated with.\n- The target operation must match the operation this magic code can verify.\n- The magic code must not be expired.\n- The magic code's status must be `true`.\n- For logins, the magic code must allow a login.\n\n### Request Verification Data\n\nThe `MagicCode` verification provider expects a request to contain the verification data as an HTTP header:\n\n`X-Verification-Magic-Code: ABC-123`\n\n### Security Considerations\n\nA magic code ultimately enables anyone who gets a hold of it to obtain an access token or even change the victims' password, etc.\n\nTo minimize the attack surface, the following precautions have been made:\n\n- A magic code should be short-lived. The default TTL is 30 minutes.\n- Using the Drupal core `flood` module, brute-forcing magic-codes is severely limited.\n  The defaults are 50 attempts per IP-Address within an hour and 5 attempts per user within an hour.\n- If a magic code allows a login for an operation, the login can only be made once.\n- When a user entity gets updated, all magic codes for that user will be invalidated\n\n## Usage\n\n### Generate a magic code\n\nThe `magic_code.manager` service can be used to generate magic codes.\n\n```php\n\u003c?php\n\n$manager = \\Drupal::service('magic_code.manager');\n\n$operation = `my-operation`;\n$user = User::load(1); // Get your desired user somehow.\n$client = Consumer::load(1); // Get your desired consumer somehow.\n\n// Code is the magic code entity.\n$code = $manager-\u003ecreateNew($operation, $user, $client);\n\n$codeValue = $code-\u003egetCodeValue();\n```\n\n### Verify a magic code\n\nA magic code can also be manually verified (when not using the Verification API).\n\n**If the magic code was generated with an email address that differs from the email address of the user, the email must be passed to the `verify` method as the last argument.**\n\n```php\n\u003c?php\n\n$manager = \\Drupal::service('magic_code.manager');\n\n$code = 'ABC-123';\n$operation = `my-operation`;\n$user = User::load(1); // Get your desired user somehow.\n$client = Consumer::load(1); // Get your desired consumer somehow.\n\n// Can be either\n// - MagicCodeManagerInterface::VERIFY_MODE_OPERATION\n// - MagicCodeManagerInterface::VERIFY_MODE_LOGIN\n$mode = MagicCodeManagerInterface::VERIFY_MODE_OPERATION;\n\n// @see \\Drupal\\magic_code\\MagicCodeResult\n$result = $manager-\u003everify($code, $operation, $user, $client);\n```\n\n### Use Magic Codes in E-Mail Templates\n\nSeveral tokens are provided to use magic codes in account emails.\n\n**For security reasons, the tokens are only available in account emails!**\n\nFor each individual operation, a custom token must be used.\n\nThe module provides several built-in tokens to generate magic codes for the following operations:\n\n|Token|Operation|\n|-|-|\n|`[user:magic-code-login]`|login|\n|`[user:magic-code-register]`|register|\n|`[user:magic-code-set-password]`|set-password|\n|`[user:magic-code-cancel-account]`|cancel-account|\n\nTo make your custom operations available as tokens, you can use the `hook_magic_code_user_mail_token_operations_alter()` hook:\n\n```php\n\u003c?php\n\n/**\n * Implement hook_magic_code_user_mail_token_operations_alter().\n */\nfunction my_module_magic_code_user_mail_token_operations_alter(\u0026$operations) {\n  $operations[] = 'added-operation';\n}\n```\n\n#### Caveats\n\nPlease beware that for each token used in an email, a magic code is being generated.\n\nE.g. when two tokens are used in the email template, two unique magic codes will be generated!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwunderwerkio%2Fdrupal-magic-code","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwunderwerkio%2Fdrupal-magic-code","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwunderwerkio%2Fdrupal-magic-code/lists"}