Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Release Date

## Release Version

- [patch] MOEN-44062: Added jwt support

# 07-04-2026

## 6.8.2
Expand Down
1 change: 1 addition & 0 deletions Sources/MoEngagePluginBase/MoEngagePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ extension MoEngagePlugin: MoEngageModule.Item {
MoEngageLogger.logDefault(message: "MoEngagePluginMessageDelegateHandler is unavailable for tvOS 🛑")
#else
_ = MoEngagePluginMessageDelegateHandler(identifier: identifier)
_ = MoEngagePluginAuthenticationListenerHandler(identifier: identifier)
#endif
MoEngagePluginBaseHandler.initializePluginBridge(className: MoEngagePluginConstants.ExternalPluginBase.cardsBridge)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// MoEngagePluginAuthenticationListenerHandler.swift
// MoEngagePlugin
//

import Foundation
import MoEngageSDK


@available(iOSApplicationExtension, unavailable)
final class MoEngagePluginAuthenticationListenerHandler: NSObject, MoEngageAuthenticationError.Listener {

private let identifier: String

private var messageHandler: MoEngagePluginMessageHandler? {
return MoEngagePluginMessageDelegate.fetchMessageQueueHandler(identifier: identifier)
}

init(identifier: String) {
self.identifier = identifier
super.init()
registerListenerInSDK()
}

private func registerListenerInSDK() {
MoEngageSDKCore.sharedInstance.registerAuthenticationListener(self, workspaceId: identifier)
}

func onError(_ error: MoEngageAuthenticationError) {
if let message = MoEngagePluginUtils.authenticationErrorToJSON(error: error) {
messageHandler?.flushMessage(
eventName: MoEngagePluginConstants.CallBackEvents.authenticationError,
message: message
)
}
}
}

17 changes: 17 additions & 0 deletions Sources/MoEngagePluginBase/MoEngagePluginBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,23 @@ import MoEngageInApps
#endif
}

@objc public func passAuthenticationDetails(_ authenticationDetails: [String: Any]) {
if let identifier = MoEngagePluginUtils.fetchIdentifierFromPayload(attribute: authenticationDetails),
Comment thread
RakshithaAcharya marked this conversation as resolved.
let authDetails = MoEngagePluginUtils.authPayloadToNativeModel(payload: authenticationDetails) {
MoEngageSDKCore.sharedInstance.passAuthenticationDetails(authDetails, workspaceId: identifier)

MoEngageLogger.logDefault(
logLevel: .verbose,
message: "Authentication details passed for identifier: \(identifier)"
)
} else {
MoEngageLogger.logDefault(
logLevel: .error,
message: "Failed to map Authentication details unsupported type or missing AppID"
)
}
}

// MARK: Other
@objc public func validateSDKVersion() -> Bool {
if MoEngagePluginConstants.SDKVersions.currentVersion >= MoEngagePluginConstants.SDKVersions.minimumVersion && MoEngagePluginConstants.SDKVersions.currentVersion < MoEngagePluginConstants.SDKVersions.maximumVersion {
Expand Down
20 changes: 20 additions & 0 deletions Sources/MoEngagePluginBase/MoEngagePluginConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ public struct MoEngagePluginConstants {
static let screenName = "screenName"
static let clickedAction = "clickedAction"
}

public struct Authentication {
public static let authType = "authenticationType"
public static let errorCode = "code"
public static let errorMessage = "message"
public static let token = "token"
public static let userIdentifier = "userIdentifier"
public static let jwt = "JWT"
public struct Error {
public static let timeConstraintFailure = "TIME_CONSTRAINT_FAILURE"
public static let decryptionFailed = "DECRYPTION_FAILED"
public static let headerTypeIncompatible = "HEADER_TYPE_INCOMPATIBLE"
public static let tokenPayloadContentMissing = "PAYLOAD_CONTENT_MISSING"
public static let invalidSignature = "INVALID_SIGNATURE"
public static let identifierMismatch = "IDENTIFIER_MISMATCH"
public static let tokenNotAvailable = "TOKEN_NOT_AVAILABLE"
public static let unknown = "UNKNOWN"
}
}

// Callback
public struct CallBackEvents {
Expand All @@ -120,6 +139,7 @@ public struct MoEngagePluginConstants {
public static let pushTokenGenerated = "MoEPushTokenGenerated"
public static let pushClicked = "MoEPushClicked"
public static let logOutCompleted = "MoELogoutComplete"
public static let authenticationError = "MoEAuthenticationError"
}

struct ExternalPluginBase {
Expand Down
73 changes: 68 additions & 5 deletions Sources/MoEngagePluginBase/MoEngagePluginUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public class MoEngagePluginUtils {
static func mapSelfHandledCampaignDataToJSON(campaignData: MoEngageInAppSelfHandledData) -> [String: Any] {
let accountMeta = campaignData.accountMeta
let accountPaylaod = createAccountPayload(identifier: accountMeta.appID)

let campaignsPayload = campaignData.campaigns.map { campaign in
let selfHandledPayload = mapSelfHandledCampaignToJSON(campaign)
return [MoEngagePluginConstants.General.platform: MoEngagePluginConstants.General.iOS,
Expand All @@ -150,17 +150,17 @@ public class MoEngagePluginUtils {
MoEngagePluginConstants.InApp.screenName: rules.screenName,
MoEngagePluginConstants.InApp.contexts: rules.contexts]
}

static func mapSelfHandledCampaignToJSON(_ campaign: MoEngageInAppSelfHandledCampaign) -> [String: Any] {
var campaignPayload = campaign.fetchInAppPaylaod()

var selfHandledPayload = [String: Any]()
selfHandledPayload[MoEngagePluginConstants.General.payload] = campaign.campaignContent
selfHandledPayload[MoEngagePluginConstants.InApp.dismissInterval] = campaign.autoDismissInterval
selfHandledPayload[MoEngagePluginConstants.InApp.displayRules] = mapDisplayRulesToJSON(campaign.displayRules)

campaignPayload[MoEngagePluginConstants.InApp.selfHandled] = selfHandledPayload

return campaignPayload
}

Expand All @@ -169,6 +169,69 @@ public class MoEngagePluginUtils {
MoEngagePluginConstants.General.accountMeta: createAccountPayload(identifier: identifier)
]
}

static func authenticationErrorToJSON(error: MoEngageAuthenticationError) -> [String: Any]? {
let accountMeta = createAccountPayload(identifier: error.accountMeta.appID)
var dataPayload = [String: Any]()

guard let jwtError = error as? MoEngageJwtAuthenticationError else {
MoEngageLogger.logDefault(message: "Other type of authentication is not supported in the sdk")
return nil

}
dataPayload[MoEngagePluginConstants.Authentication.authType] = MoEngagePluginConstants.Authentication.jwt
dataPayload[MoEngagePluginConstants.Authentication.errorCode] = jwtErrorCodeString(for: jwtError)
dataPayload[MoEngagePluginConstants.General.message] = jwtError.details.message ?? ""
dataPayload[MoEngagePluginConstants.Authentication.token] = jwtError.details.token ?? ""
dataPayload[MoEngagePluginConstants.Authentication.userIdentifier] = jwtError.details.identifier ?? ""
return [
MoEngagePluginConstants.General.accountMeta: accountMeta,
MoEngagePluginConstants.General.platform: MoEngagePluginConstants.General.iOS,
MoEngagePluginConstants.General.data: dataPayload
Comment thread
RakshithaAcharya marked this conversation as resolved.
]
}

private static func jwtErrorCodeString(for jwtError: MoEngageJwtAuthenticationError) -> String {

switch jwtError.details.code {
case .timeConstraintFailure:
return MoEngagePluginConstants.Authentication.Error.timeConstraintFailure
case .decryptionFailed:
return MoEngagePluginConstants.Authentication.Error.decryptionFailed
case .headerTypeIncompatible:
return MoEngagePluginConstants.Authentication.Error.headerTypeIncompatible
case .tokenPayloadContentMissing:
return MoEngagePluginConstants.Authentication.Error.tokenPayloadContentMissing
case .invalidSignature:
return MoEngagePluginConstants.Authentication.Error.invalidSignature
case .identifierMismatch:
return MoEngagePluginConstants.Authentication.Error.identifierMismatch
case .tokenNotAvailable:
return MoEngagePluginConstants.Authentication.Error.tokenNotAvailable
case .unknown:
return MoEngagePluginConstants.Authentication.Error.unknown
}
}
static func authPayloadToNativeModel(payload: [String: Any]) -> MoEngageAuthenticationDetails? {
guard let authData = payload[MoEngagePluginConstants.General.data] as? [String: Any],
let authType = authData[MoEngagePluginConstants.Authentication.authType] as? String
else {
MoEngageLogger.logDefault(logLevel: .error, message: "Authentication details missing 'data' or 'authType'")
return nil
}
if authType == MoEngagePluginConstants.Authentication.jwt {
guard let token = authData[MoEngagePluginConstants.Authentication.token] as? String,
let userIdentifier = authData[MoEngagePluginConstants.Authentication.userIdentifier] as? String
else {
MoEngageLogger.logDefault(logLevel: .error, message: "JWT Authentication details missing token or identifier")
return nil
}
return MoEngageJwtAuthenticationDetails(token: token, identifier: userIdentifier)
} else {
MoEngageLogger.logDefault(logLevel: .error, message: "Authentication type '\(authType)' is not supported.")
return nil
}
}
}

extension MoEngageInAppCampaign {
Expand Down
Loading