{"result":{"depiction_url":null,"edges":{"observes":{"objects":[{"created":"2026-09-09T13:47:40Z","object_id":{"id":1436,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_identity_password_match","title":"observe_identity_password_match\/2","uri":"https:\/\/zotonic.com\/id\/1436"},"seq":1},{"created":"2026-09-09T13:47:40Z","object_id":{"id":1438,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_identity_verified","title":"observe_identity_verified\/2","uri":"https:\/\/zotonic.com\/id\/1438"},"seq":2},{"created":"2026-09-09T13:47:40Z","object_id":{"id":1466,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_admin_menu","title":"observe_admin_menu\/3","uri":"https:\/\/zotonic.com\/id\/1466"},"seq":3},{"created":"2026-09-09T13:47:40Z","object_id":{"id":1982,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_search_query","title":"observe_search_query\/2","uri":"https:\/\/zotonic.com\/id\/1982"},"seq":4},{"created":"2026-09-09T13:47:40Z","object_id":{"id":2052,"is_a":["text","documentation","reference","notification"],"name":"doc_notification_rsc_update","title":"observe_rsc_update\/3","uri":"https:\/\/zotonic.com\/id\/2052"},"seq":5}],"predicate":{"id":2550,"is_a":["meta","predicate"],"name":"observes","title":{"_type":"trans","tr":{"en":"Observes"}},"uri":"https:\/\/zotonic.com\/id\/observes"}},"references":{"objects":[{"created":"2020-05-30T05:48:08Z","object_id":{"id":2045,"is_a":["text","documentation","userguide"],"name":"doc_userguide_user_management","title":"User management","uri":"https:\/\/zotonic.com\/id\/2045"},"seq":1000000}],"predicate":{"id":332,"is_a":["meta","predicate"],"name":"references","title":{"_type":"trans","tr":{"en":"References"}},"uri":"https:\/\/zotonic.com\/id\/references"}},"subject":{"objects":[{"created":"2026-09-09T13:47:40Z","object_id":{"id":2555,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_reference","title":"Reference","uri":"https:\/\/zotonic.com\/id\/2555"},"seq":1},{"created":"2026-09-09T13:47:40Z","object_id":{"id":2562,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_site_administrator","title":"Site administrator","uri":"https:\/\/zotonic.com\/id\/2562"},"seq":2},{"created":"2026-09-09T13:47:40Z","object_id":{"id":2589,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_identity_and_accounts","title":"Identity and accounts","uri":"https:\/\/zotonic.com\/id\/2589"},"seq":3},{"created":"2026-09-09T13:47:40Z","object_id":{"id":2590,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_authentication","title":"Authentication","uri":"https:\/\/zotonic.com\/id\/2590"},"seq":4},{"created":"2026-09-09T13:47:40Z","object_id":{"id":2635,"is_a":["categorization","keyword","keyword_architecture"],"name":"zotonic_topic_module","title":"Module","uri":"https:\/\/zotonic.com\/id\/2635"},"seq":5},{"created":"2026-09-09T13:47:40Z","object_id":{"id":2638,"is_a":["categorization","keyword","keyword_task"],"name":"zotonic_topic_edit","title":"Edit","uri":"https:\/\/zotonic.com\/id\/2638"},"seq":6}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"id":1434,"is_a":["text","documentation","reference","module"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1434"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_module_mod_admin_identity","page_url":{"en":"https:\/\/zotonic.com\/docs\/1434\/mod_admin_identity","x-default":"https:\/\/zotonic.com\/docs\/1434\/mod_admin_identity"},"preview_url":null,"resource":{"version":3330,"pivot_location_lat":null,"title":"mod_admin_identity","is_authoritative":true,"body":"<p>Provides identity management in the admin - for example the storage of usernames and passwords.<\/p>\n<p>It provides a user interface where you can create new users for the admin system. There is also an option to send these\nnew users an e-mail with their password.<\/p>\n<h2>Create new users<\/h2>\n<p>See the <a href=\"\/id\/doc_userguide_user_management#guide-user-management\">User management<\/a> chapter in the User Guide for more\ninformation about the user management interface.<\/p>\n<h3>Configure new user category<\/h3>\n<p>To configure the category that new users will be placed in, set the <code>mod_admin_identity.new_user_category<\/code> configuration\nparameter to that category’s unique name.<\/p>\n<h2>Password Complexity Rules<\/h2>\n<p>By default Zotonic only enforces that your password is not blank. However, if you, your clients or your business require\nthe enforcement of Password Complexity Rules Zotonic provides it.<\/p>\n<h3>Configuring Password Rules<\/h3>\n<p>After logging into the administration interface of your site, go to the Config section and click Make a new config\nsetting. In the dialog box, enter <code>mod_admin_identity<\/code> for Module, <code>password_regex<\/code> for Key and your password rule\nregular expression for Value.<\/p>\n<p>After saving, your password complexity rule will now be enforced on all future password changes.<\/p>\n<h3>Advice on Building a Password Regular Expression<\/h3>\n<p>A typical password_regex should start with ^.* and end with .*$. This allows everything by default and allows you\nto assert typical password rules like:<\/p>\n<ul><li>must be at least 8 characters long (?=.{8,})<\/li><li>must have at least one number (?=.*[0-9])<\/li><li>must have at least one lower-case letter (?=.*[a-z])<\/li><li>must have at least one upper-case letter (?=.*[A-Z])<\/li><li>must have at least one special character (?=.*[@#$%^&amp;+=])<\/li><\/ul>\n<p>Putting those rules all together gives the following password_regex:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-none\">^.*(?=.{8,})(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&amp;+=]).*$\n<\/code><\/pre>\n<p>To understand the mechanics behind this regular expression see <a href=\"http:\/\/www.zorched.net\/2009\/05\/08\/password-strength-validation-with-regular-expressions\/\">Password validation with regular expressions<\/a>.<\/p>\n<h3>Migrating from an older password hashing scheme<\/h3>\n<p>When you migrate a legacy system to Zotonic, you might not want your users to re-enter their password before they can\nlog in again.<\/p>\n<p>By implementing the <code>identity_password_match<\/code> notification, you can have your legacy passwords stored in a custom hashed\nformat, and notify the system that it needs to re-hash the password to the Zotonic-native format. The notification has\nthe following fields:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-none\">-record(identity_password_match, {rsc_id, password, hash}).\n<\/code><\/pre>\n<p>Your migration script might have set the <code>username_pw<\/code> identity with a marker tuple which contains a password in MD5 format:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">m_identity:set_by_type(AccountId, username_pw, Email, {hash, md5, MD5Password}, Context),\n<\/code><\/pre>\n<p>Now, in Zotonic when you want users to log on using this MD5 stored password, you implement <code>identity_password_match<\/code>\nand do the md5 check like this:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-erlang\">observe_identity_password_match(#identity_password_match{password=Password, hash={hash, md5, Hash}}, _Context) -&gt;\n  case binary_to_list(erlang:md5(Password)) =:= z_utils:hex_decode(Hash) of\n      true -&gt;\n          {ok, rehash};\n      false -&gt;\n          {error, password}\n  end;\nobserve_identity_password_match(#identity_password_match{}, _Context) -&gt;\n  undefined. %% fall through\n<\/code><\/pre>\n<p>This checks the password against the old MD5 format. The <code>{ok, rehash}<\/code> return value indicates that the user’s password hash will be updated by Zotonic, and as such, this method is\nonly called once per user, as the next time the password is stored using Zotonic’s internal hashing scheme.<\/p>\n<h2>Accepted Events<\/h2>\n<p>This module handles the following notifier callbacks:<\/p>\n<ul><li><code>observe_admin_menu<\/code>: Add identity and account-management entries to the admin menu.<\/li><li><code>observe_identity_password_match<\/code>: Validate legacy admin-password hashes during password checks.<\/li><li><code>observe_identity_verified<\/code>: Mark matching identities as verified after successful confirmation flows.<\/li><li><code>observe_rsc_update<\/code>: Apply admin identity updates from posted form values to resource-linked identities.<\/li><li><code>observe_search_query<\/code>: Add identity-based search query clauses for admin user lookups.<\/li><\/ul>\n<p>Delegate callbacks:<\/p>\n<ul><li><code>event\/2<\/code> with <code>postback<\/code> messages: <code>identity_add<\/code>, <code>identity_delete<\/code>, <code>identity_delete_confirm<\/code>, <code>identity_verify<\/code>, <code>identity_verify_check<\/code>, <code>identity_verify_confirm<\/code>, <code>identity_verify_preferred<\/code>.<\/li><\/ul>","slug":"mod_admin_identity","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"ae39fd0031a49d8383691a0fc0c34555025600838e7399bcabeba435e8a881ed","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":320,"is_a":["meta","category"],"name":"module","title":"Modules","uri":"https:\/\/test.zotonic.com\/id\/320"},"doc_source_path":"apps\/zotonic_mod_admin_identity\/src\/mod_admin_identity.erl","publication_start":"2023-01-30T19:24:00Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/apps\/zotonic_mod_admin_identity\/src\/mod_admin_identity.erl","pivot_location_lng":null,"doc_source_kind":"module","name":"doc_module_mod_admin_identity","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2020-05-30T05:47:22Z","uri":null,"doc_status":"current","is_dependent":false,"erlang_app":"zotonic_mod_admin_identity","publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"66cb145eae7002b184e7d8c4c7bba5e53e8248e5\n","creator_id":{"id":336,"is_a":["person","robot"],"name":"gitbot","title":"Git","uri":"https:\/\/zotonic.com\/id\/336"},"modified":"2026-10-02T12:40:18Z","title_slug":"mod_admin_identity"},"uri":"https:\/\/zotonic.com\/id\/1434","uri_template":"https:\/\/zotonic.com\/id\/:id","websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/1434"}},"status":"ok"}