Sanjay Kumar
+3
Apr 1, 2026
visibility 581
star star star star star
(3 votes)

Fixing “Published By” After OKTA SSO in Optimizely CMS

Enabling Okta SSO significantly strengthened our authentication and security model in Optimizely CMS. However, like many real-world implementations, it also introduced an unexpected challenge in the CMS authoring experience, as the system now stores the Okta ID as the username.

Problem:

After switching to SSO, we observed a change in how user identities were stored:

  • The “Published By” field displayed Okta ID
  • Instead of names or emails, editors saw technical IDs



Impact on Editorial Exp.

This created friction for content teams:

  • Author attribution became unclear
  • Content review was harder to follow
  • Auditing lost its human-readable context

For non-technical users, this was a noticeable drop in usability.

Solution:

To address this, we introduced a custom transformation:

👉 PublishedByTransform

This transform maps the stored Okta identifier to a friendly display value, such as:

  • Author name
  • Email address
  • Or any readable identity field

Instead of exposing raw Okta IDs, the CMS now resolves and displays meaningful user information.

 [ServiceConfiguration(typeof(IModelTransform), Lifecycle = ServiceInstanceScope.Singleton)]
 public class PublishedByTransform : ContentDataStoreModelTransform
 {
     private readonly EPiServer.Logging.ILogger _logger;
     private readonly IUserService _userService;
     private readonly IPrincipalAccessor _principalAccessor;
     private readonly IContentVersionRepository _contentVersionRepository;

     public PublishedByTransform(
         IUserService userService,
         IPrincipalAccessor principalAccessor,
         IContentVersionRepository contentVersionRepository)
     {
         _userService = userService ?? throw new ArgumentNullException(nameof(userService));
         _principalAccessor = principalAccessor ?? throw new ArgumentNullException(nameof(principalAccessor));
         _contentVersionRepository = contentVersionRepository ?? throw new ArgumentNullException(nameof(contentVersionRepository));
         _logger = LogManager.GetLogger(typeof(PublishedByTransform));
     }

     public override void TransformInstance(IContent source, ContentDataStoreModel target, IModelTransformContext context)
     {
         base.TransformInstance(source, target, context);
         ContentVersion contentVersion1 = this._contentVersionRepository.Load(source.ContentLink);
         ContentVersion contentVersion2 = _contentVersionRepository.LoadPublished(source.ContentLink, source.LanguageBranch());

         if (contentVersion1 != null)
         {
             var versionCreatedBy = string.IsNullOrEmpty(contentVersion1.StatusChangedBy) ? contentVersion1.SavedBy : contentVersion1.StatusChangedBy;
             target.VersionCreatedBy = ResolvePublishedBy(versionCreatedBy);
         }

         if (contentVersion2 != null)
         {
             var publishedBy = !string.IsNullOrWhiteSpace(contentVersion2.StatusChangedBy)
                 ? contentVersion2.StatusChangedBy
                 : contentVersion2.SavedBy;

             target.PublishedBy = ResolvePublishedBy(publishedBy);
         }
     }

     private string? ResolvePublishedBy(string? publishedBy)
     {
         if (string.IsNullOrWhiteSpace(publishedBy))
             return publishedBy;

         try
         {
             var user = _userService.GetUserByName(publishedBy);
             if (user == null)
                 return publishedBy;

             var claimsPrincipal = _principalAccessor.Principal as ClaimsPrincipal;
             var currentUserEmail = claimsPrincipal?.FindFirst("email")?.Value ?? claimsPrincipal?.FindFirst(ClaimTypes.Email)?.Value;
             if (!string.IsNullOrWhiteSpace(currentUserEmail)
                 && !string.IsNullOrWhiteSpace(user.Email)
                 && string.Equals(currentUserEmail, user.Email, StringComparison.OrdinalIgnoreCase))
             {
                 return "you";
             }

             return !string.IsNullOrWhiteSpace(user.Email) ? user.Email : user.UserName;
         }
         catch (Exception ex)
         {
             _logger.Error($"PublishedByTransform failed to resolve PublishedBy for value '{publishedBy}'. Error: {ex}");
             return publishedBy;
         }
     }
 }

Result:

With this small but impactful enhancement, we achieved the best of both worlds:

  • Secure SSO via Okta remains fully in place
  • “Published By” now shows clear, readable author names


Thank you for reading the blog. Cheers!

Apr 01, 2026

Comments

Praful Jangid
Praful Jangid Apr 9, 2026 07:05 AM

Thanks for sharing.

error Please login to comment.
Latest blogs
From SDK to Core: Modernizing Optimizely Configured Commerce for .NET 8 and .NET 10

The .NET Framework 4.8 clock is running out for Configured Commerce customizations. Handled well, this deadline is not a chore it is the cleanest...

Vaibhav | Jul 29, 2026

Parallel Development in Optimizely CMS SaaS: Shifting to a Schema Migration Mindset

  Part 3 of the Parallel Development series. The branch-scoped push script from Part 1 works. Run it on a feature branch where you've touched a...

Vipin Banka | Jul 25, 2026

From AI Agents to AI Workflow with Opal

Introduction In the first article in this series , we talked about AI agents in Optimizely Opal and walked through the process of creating a...

Igor Safonov | Jul 23, 2026

Building Your First Optimizely Opal AI Agent: a Hands-On Walkthrough

Introduction There's a common assumption that building an AI agent is something only engineers or developers can do. It isn't. At the Optimizely AN...

Igor Safonov | Jul 23, 2026