This article describes a pattern for managing the GAM configuration of an application (permissions, roles, and menus) in a declarative way, using a Data Provider as the single source of truth and a Procedure to apply it programmatically.
The goal is to ensure that the GAM metadata of your application is consistent across all environments. By running the initialization Procedure, the target environment (Development, QA, or Production) will always end up with the same configuration of permissions, roles, and menus.
This is especially useful when migrating applications between environments. Instead of manually replicating GAM settings through the GAM Backoffice, you run the initialization Procedure and the configuration is applied automatically.
An XPZ file is attached to this article containing a working example organized under a Folder called GAMInitialization. This example is intended as a starting point; you should import it into your Knowledge Base and adapt it to your application's specific permissions, roles, and menus.
The two main objects are:
- InitGAMMetadata (Data Provider): Declares the full application definition (permissions, roles, and menus) and returns a GAMApplicationDefinition SDT. This is the object you will modify to define your own configuration.
- InitAppGAM (Procedure): Receives the GAMApplicationDefinition SDT and creates or updates the application, permissions, roles, and menus in GAM. This Procedure should not require modifications.
The XPZ file also includes auxiliary Procedures for permission name normalization, package detection, and role-based Home URL resolution.
This is the root SDT returned by the InitGAMMetadata Data Provider. It describes the entire application configuration in a single structure:
- GUID (GAMGUID): Unique identifier for the application.
- Name (GAMDescriptionShort): Application name.
- Description (GAMDescriptionLong): Application description.
- ClientId (GAMClientApplicationId): OAuth 2.0 Client ID.
- ClientSecret (GAMClientApplicationSecret): OAuth 2.0 Client Secret.
- Version (GAMDescriptionShort): Application version.
- HomeObject (Url): Default home object for the application.
- AccountActivationObject (Url): Account activation URL. Use %1 as a placeholder for the activation key.
- RequiresPermission (Boolean) — When True, users need an explicit permission to access the application.
- AccessUniqueByUser (Boolean) — When True, only one active session (token) per user is allowed at a time.
- VirtualDirectory (Url) — Virtual directory for the application. If left empty, it is detected automatically from the HTTP request.
- Permissions — Collection of GAMAppPermissionDefinition.
- Roles — Collection of GAMRoleDefinition.
- Menus — Collection of GAMAppMenuDefinition.
Permissions are defined inside the Permissions collection of the Data Provider. Each permission has a Name, Description, Type, and a special flag called isTRN.
When isTRN = True, the initialization Procedure automatically generates four child permissions linked to the parent permission:
- {entity}_Execute — Access / Execute
- {entity}_Insert — Insert
- {entity}_Update — Update
- {entity}_Delete — Delete
This is designed for Transaction-based entities where you need granular CRUD control. For example, if you define:
Item {
Name = !"Reserves_FullControl"
Description = !"Reserves FullControl"
Type = GAMPermissionAccessType.Restricted
isTRN = True
}
GAM will create the parent permission reserves_FullControl plus four children: reserves_Execute, reserves_Delete, reserves_Insert, and reserves_Update.
When isTRN = False, only the permission itself is created, with no children. Use this for simple access permissions such as granting access to a specific screen or feature:
Item {
Name = !"Monitor_Execute"
Description = !"Monitor de Procesos"
Type = GAMPermissionAccessType.Restricted
isTRN = False
}
Note: The permission name must follow the format Entity_Action (with exactly one underscore). The part before the underscore is used as the prefix for child permissions and is automatically converted to lowercase.
The Type field uses the GAMPermissionAccessType enumeration:
- Restricted — Used when defining permissions at the application level. Indicates that the resource requires authorization.
- Allow — Used when assigning permissions to a role. Indicates that the role is granted access.
Roles are defined inside the Roles collection. Each role has a GUID, Name, Description, SecurityPolicyId, and an optional Home object.
Item {
GUID = MyGUIDs.RoleEmployee
Name = !"Employee"
Description = !"Company Employee"
SecurityPolicyId = 0
Home = !"intranet"
Permissions {
Item {
Name = !"Intranet_Execute"
Type = GAMPermissionAccessType.Allow
}
}
}
Each role can include a Permissions sub-collection listing the permissions granted to that role (with Type = Allow).
The Home field allows you to configure a different landing page for each role. Internally, it is stored as a GAMProperty with Id = "HomeObject".
The GivenRoleIDGetUserRoleHomeURL Procedure resolves this to a full URL by combining the environment settings (host, port, virtual directory, and program package). If the Home value starts with http, it is used as an absolute URL. Otherwise, it is treated as a relative object name.
The role identified by MyGUIDs.RoleSystemAdministrator receives all permissions automatically. You do not need to list individual permissions for this role, as the initialization Procedure assigns every permission to it.
Menus are defined inside the Menus collection. Each menu contains a list of Options.
Menu options can be of two types:
- Simple (GAMMenuOptionType.Simple): Links directly to a resource (via ResourceName or EntityName).
- Menu (GAMMenuOptionType.Menu): Acts as a container that references a submenu via SubMenuID (the ordinal position in which the submenu was loaded).
A menu option can be linked to a permission through the PermissionPrefix field. When set, the prefix is converted to a permission name using the format {prefix_lowercase}_Execute. The option will only be visible to users who have been granted that permission through their role.
Item {
Name = !"Intranet"
Description = !"Intranet"
Type = GAMMenuOptionType.Simple
ResourceName = !"intranet"
PermissionPrefix = !"Intranet"
}
In this example, only users with the intranet_Execute permission will see the "Intranet" menu option.
You can specify the target resource in two ways:
- ResourceName: The URL or object name as-is (e.g. home, contactus).
- EntityName: A GeneXus entity name. The Procedure appends ww to generate the URL (e.g. customer becomes customerww).
MyGUIDs is an Enumerated Domain (Char 40) that centralizes all GUIDs used by the application: the application GUID and the GUIDs for each role.
Using this domain ensures that GUIDs are referenced consistently across all objects. It also provides a single place to update them if needed. The domain includes an EnumerationDescription method that returns the display name for each value, which is used in log messages.
Example values:
- MyGUIDs.MyApp: Application GUID (also used as the base for ClientId and ClientSecret).
- MyGUIDs.RoleSystemAdministrator: System Administrator role.
- MyGUIDs.RoleEnrolled: Member role.
- MyGUIDs.RoleEmployee: Employee role.
The InitAppGAM Procedure receives a GAMApplicationDefinition SDT (the output of the InitGAMMetadata Data Provider) and applies it to GAM. The Procedure follows a delete-and-recreate strategy to ensure the final state matches the definition exactly.
Execution flow:
- Create or update the application. If a GAM Application with the given GUID exists, it is updated. Otherwise, a new one is created. Environment settings (host, port, virtual directory, program package) are detected automatically from the HTTP request.
- Delete all existing permissions from the application, including those assigned to the System Administrator role.
- Recreate permissions as defined in the Data Provider. For each permission with isTRN = True, child permissions are generated. Every permission is assigned to the System Administrator role.
- Clean permissions from all roles (except System Administrator, which was already handled).
- Recreate or update roles and assign the permissions listed in each role's definition.
- Delete all existing menus from the application.
- Recreate menus and menu options as defined, linking options to permissions when a PermissionPrefix is specified.
- Update the MainMenuId of the application (set to the last menu created).
- Clear the GAM cache (GAMRepository.ClearCache()).
Note: Because the Procedure deletes and recreates all permissions, role assignments, and menus, it is safe to run multiple times. The result is always the same: the GAM configuration will match the Data Provider definition exactly. However, any manual changes made directly in the GAM Backoffice will be overwritten.
To use this pattern in your application:
- Create the MyGUIDs Enumerated Domain with a GUID for your application and one for each role.
- Modify the InitGAMMetadata Data Provider to define your application's permissions, roles, and menus.
- Call the InitAppGAM Procedure from a Web Panel or startup process, passing the output of the Data Provider.
// Example call
&GAMApplicationDefinition = InitGAMMetadata()
InitAppGAM(&GAMApplicationDefinition, &isOK)
Run this once per environment after deployment, or include it as part of your application's startup routine.
GAMInitializationExample
GAM Applications
GAM Roles
GAM Permissions
Security Policies