Sanjay Kumar
Apr 1, 2026
  37
(1 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

Please login to comment.
Latest blogs
OptiPowerTools.Hangfire: A Drop-in Hangfire Integration for Optimizely CMS 12

Back in 2024, I wrote a post on Adding Hangfire to Episerver/Optimizely CMS 12, walking through each step of integrating Hangfire into an Optimizel...

Stanisław Szołkowski | Mar 31, 2026 |

Upgrade Guide: Commerce 14 to Commerce 15 preview

This document provides step-by-step instructions to upgrade a Commerce site from Commerce 14/CMS 12 to Commerce 15/CMS 13 preview.   Overview   Thi...

Viet Anh Nguyen | Mar 31, 2026

Prove what your experimentation program is worth with Holdouts

Running experiments is one thing. Knowing whether your experimentation program is moving the business forward?  That's  the harder question.   Most...

Sarah Ager | Mar 30, 2026