Handling profiles and related errors - zowe/zowe-explorer-vscode GitHub Wiki
When using profiles in Zowe Explorer, API calls may sometimes fail with an authentication error. In the event of an authentication error, use the AuthHandler class exposed in Zowe Explorer API (v3.1.0 and above) to lock a profile and prevent further use. Once the profile is re-authenticated, the profile is unlocked and can be used again.
While we recommend using the locking mechanism for profiles, this is an opt-in implementation and profiles can still be used without the locks. However, as the advantages of the locking mechanism outweigh the downsides of not using it, extenders should consider adopting it when necessary. The filesystem currently leverages the locks, so the locking mechanism is not needed when interfacing with Zowe Explorer's FileSystemProvider resources.
Benefits
- Avoids mainframe lockouts by waiting for a profile to be "unlocked" (available) before continuing
- Allows extenders to prompt a user to re-authenticate their profile in event of a 401/authentication error
- Attempts to synchronize profile status between extenders by preventing repeated calls when a profile was used with invalid credentials
Opting in to locks for a profile type
By default, profiles with type zosmf use the locking mechanism. This avoids API calls with invalid credentials, which can occur during asynchronous event/request processing (such as actions fired by VS Code within our filesystem providers).
To opt-in to locks for a specific profile type, call the AuthHandler.enableLocksForType function with the profile type as the parameter:
AuthHandler.enableLocksForType("your-custom-type");
Locking profiles before API calls
We recommend that extenders call the AuthHandler.lockProfile function before making a request with a specific profile. After the operation is completed, call the AuthHandler.unlockProfile function to allow the profile to be used outside of the current context.
await AuthHandler.lockProfile("lpar1.zosmf");
// ... make the API call, then unlock the profile
AuthHandler.unlockProfile("lpar1.zosmf");
Note that AuthHandler.lockProfile is blocking and waits for the lock to be available if it is currently in use. Extenders should ensure that a profile is unlocked after the desired API calls are handled for a profile, so that the profile can be used elsewhere (either by Zowe Explorer or another extender).
Extenders can pass true for the second parameter of AuthHandler.unlockProfile to update "active resources" after unlocking the profile (such as virtual workspaces or active text editors).
Prompt users to authenticate a profile
If an authentication error occurs after locking the profile, call the AuthHandler.promptForAuthentication method with the respective login methods (promptCredentials and ssoLogin) to prompt the user to re-authenticate their profile. Once the profile has been re-authenticated, the profile is unlocked and can be used again.
await AuthHandler.promptForAuthentication(err, profile, {
// This parameter supports a ProfilesCache instance or individual callbacks
authMethods: Constants.PROFILES_CACHE
});
Checking whether a profile is locked
Call the AuthHandler.isProfileLocked function with a profile (either an imperative.IProfileLoaded object or the profile name) to determine whether a profile is locked. The function returns true when the profile is locked and returns false otherwise.
Extenders can call this function to check whether the profile is available before trying to acquire the lock. This prevents busy waiting for the lock, which helps when an extender wants to perform an action with a profile without waiting for the profile to be available.
Checking if a profile uses token-based authentication
To determine whether a profile uses token-based authentication, call the AuthHandler.isUsingTokenAuth method with the service profile's secure properties and the base profile's secure properties.
The function returns true if:
- The service profile's secure properties contains a
tokenValueand does not containuserandpassword - The base profile's secure properties contains a
tokenValue
If either of these conditions are not met, the function returns false.
Logging in and out of an authentication service
Starting with Zowe Explorer v3.7.0, extenders can trigger the same login and logout flows that Zowe Explorer's "Log in to Authentication Service" and "Log out from Authentication Service" tree actions use. Both are exposed in the Zowe Explorer API extender interface.
Pass either the profile name or a loaded profile - only the profile name is used, and it must resolve to a profile that Zowe Explorer has loaded.
const zoweExplorerApi = ZoweVsCodeExtension.getZoweExplorerApi("3.7.0");
const extenderApi = zoweExplorerApi?.getExplorerExtenderApi();
const loggedIn = await extenderApi?.ssoLogin?.("my_profile");
if (loggedIn) {
// token is stored; safe to retry the request that failed with 401
}
Both methods are optional on the interface, so guard the call with ?. (or request "3.7.0" from getZoweExplorerApi) to stay compatible with older Zowe Explorer versions.
What ssoLogin does
ssoLogin looks up the token type reported by the registered MainframeInteractions.ICommon API for the profile's type (getTokenTypeName()) and branches on it:
- API ML token type (
apimlAuthenticationToken): performs an SSO login and prefers storing the token on the base profile. - Any other token type: performs a direct-connect login against the service and stores the token on the service profile.
The user is prompted for credentials or a certificate as needed. On success, Zowe
Explorer shows a confirmation message, fires ZoweVsCodeExtension.onProfileUpdated, and unlocks the profile through AuthHandler.unlockProfile.
If the profile's type does not report a token type, login is not attempted and the method returns false.
What ssoLogout does
ssoLogout revokes the token and removes it from whichever profile holds it (base or service), then fires ZoweVsCodeExtension.onProfileUpdated.
Because there is no tree node involved when calling through this API, active filters on Zowe Explorer's Data Sets, USS, and Jobs trees are not cleared - unlike the tree context-menu action, which clears them. Refresh or clear any state on your side if your extension depends on the session being reset.
Return values and error handling
Both methods resolve to true on success and false on failure. Failures are already
reported to the user by Zowe Explorer with an error message and written to the Zowe
Explorer
log, so avoid showing a second error of your own - branch on the return value instead.
Both methods throw if no profile exists with the given name, so wrap the call in
try/catch if the name comes from user input or persisted state:
try {
if (!(await extenderApi?.ssoLogin?.(profileName))) {
// user cancelled, or login failed; Zowe Explorer already notified them
return;
}
} catch (err) {
// no profile named `profileName` is loaded
}
When to use these
Use ssoLogin when your extension detects an expired or missing token - typically after a 401 response - and you want the user re-authenticated through Zowe Explorer so the refreshed credentials are shared across every extension using the same profile.
Both methods are interactive and may show prompts, so call them in response to a user action or a failed request. Do not call them in a loop, on activation, or on a timer.
If you want Zowe Explorer to own the whole "profile is locked, ask the user, retry" flow instead, prefer
AuthHandler.promptForAuthentication(), which calls into these same login paths and handles the profile lock for you.
Detecting when a profile has been updated
If a profile was re-authenticated through Zowe Explorer, the ZoweVsCodeExtension.onProfileUpdated event is fired with the updated profile object. This allows extenders to subscribe to profile changes and proceed forward once a specific profile was successfully re-authenticated.
Subscribe to the ZoweVsCodeExtension.onProfileUpdated event to detect changes to profile credentials:
ZoweVsCodeExtension.onProfileUpdated(async (profile) => {
Gui.showMessage(`Profile updated: ${profile.name}`);
})