Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
A 3D shield icon representing secure session monitoring to detect Login As in Apex code.
Apex

Detect Login As in Apex: Is SubstituteUser Reliable?

Whether the SubstituteUser session type is a dependable way to detect 'Login As', what it cannot tell you, and which platform objects to pair it with for real auditing.

Key takeaways Treat the SubstituteUser flag as a secondary check. It is accurate for detecting active impersonation within a request, and it is not a primary security mechanism. For logging and audit compliance, rely on platform-native objects like LoginEvent, where LoginType identifies 'Delegated' logins. Wrap the check in a dedicated service class so your code stays maintainable if session metadata formats evolve. Session attributes are request-bound. They do not propagate to background processes, so keep your audit logic in the synchronous context where the session is still active.

The challenge of identity delegation

"Login As" lets an administrator take on another user's identity to reproduce a problem that only happens for that one person. If you are building custom logging, auditing, or anything security-sensitive, you need to know when that delegation is happening. The usual candidate for detecting it is Auth.SessionManagement.getCurrentSession().get('SessionType') == 'SubstituteUser'. The question is how far that check actually takes you.

Understanding Auth.SessionManagement and SessionType

The Auth.SessionManagement class returns metadata about the current user's session. Call getCurrentSession() and Salesforce hands back a Map<String, String> of key-value pairs describing the state of your connection to the server.

One of those keys is SessionType. When an administrator logs in as another user, the platform creates a special session context, and the value 'SubstituteUser' does get injected into that session metadata.

The basic implementation

To check for it in Apex, you might write a small utility method:

public with sharing class SecurityUtils {
    public static Boolean isUserBeingImpersonated() {
        Map<String, String> sessionInfo = Auth.SessionManagement.getCurrentSession();
        return sessionInfo.get('SessionType') == 'SubstituteUser';
    }
}

It is native, it needs no extra SOQL queries, and it runs inside the current request, so it looks like the whole answer. The catch is what "reliability" means in Salesforce development. It means the platform guarantees the behavior across every context and every future release, which is a much higher bar than the code running today.

The reliability verdict

SubstituteUser is reliable for internal platform identification. It is not a substitute for audit logging.

SessionType == 'SubstituteUser' is documented in Salesforce's internal session management paradigms, and it is still an implementation detail that platform-level updates can change. It is also not a comprehensive security control. It tells you the current state of the session. It does not tell you who the delegating admin is, and it leaves no historical trail of the impersonation.

Limitations to consider

The check only exists inside the session context. Move the work into a @future method or a Queueable and that context may be different or lost, which makes the check useless there.

You can inspect the value, but you cannot build deep auditing on it without pairing it with other platform logs.

Comparing strings out of a system metadata map carries its own small risk: should Salesforce reformat the session metadata structure in a major release, your code breaks silently.

If your goal is to record or restrict actions during an impersonated session, one Apex check will not carry the weight on its own. Layer it, defense in depth.

1. Augment with event monitoring

For enterprise-grade auditing, use the LoginEvent object. It is the record of login activity, 'Login As' events included.

// Querying for login history to confirm impersonation
List<LoginEvent> logs = [SELECT SourceIp, LoginType, LoginKey 
                         FROM LoginEvent 
                         WHERE UserId = :UserInfo.getUserId() 
                         AND LoginType = 'Delegated' 
                         ORDER BY LoginTime DESC LIMIT 1];

Checking LoginType = 'Delegated' gives you a persistent record of the event that outlives the session. That is far more reliable than reading the session type in real time.

2. Guarding sensitive actions

To stop Apex-driven actions from running while a user is being impersonated, pair the session check with a permission-based override. Administrators can still push through a critical fix, while your standard automated processes stay blocked from triggering updates that could be destructive.

public void executeSensitiveProcess() {
    Boolean isDelegated = Auth.SessionManagement.getCurrentSession().get('SessionType') == 'SubstituteUser';
    Boolean isAdminOverride = FeatureManagement.checkPermission('Allow_Admin_Override');

    if (isDelegated && !isAdminOverride) {
        throw new SecurityException('Process cannot be run during impersonation.');
    }
    
    // Proceed with logic
}

Best practices for developer implementations

Never let SubstituteUser be your only security gate. It is an auditing and diagnostic aid, and it does not replace Profile or Permission Set security.

Keep the Auth.SessionManagement logic inside a service class. If the platform ever changes how it exposes session data, there is one place to fix.

When you spot an impersonated session, log a record to a custom Audit_Log__c object instead of only blocking the action. That is the paper trail compliance asks for, and the session map alone cannot produce one.

getCurrentSession() is lightweight, but do not call it inside a tight loop in a large bulk transaction. Read it once at the start of the request and cache the result in a static variable.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment