diff --git a/otpmanagermdl/otpmanagermdl.go b/otpmanagermdl/otpmanagermdl.go
new file mode 100644
index 0000000000000000000000000000000000000000..704418302bb8cdba538f85516655a5baee9abba0
--- /dev/null
+++ b/otpmanagermdl/otpmanagermdl.go
@@ -0,0 +1,109 @@
+package otpmanagermdl
+
+import (
+	"errors"
+	"time"
+
+	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
+
+	"corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/cachemdl"
+)
+
+// Entry is a data to be stored against a key.
+type Entry struct {
+	Data       gjson.Result `json:"data,omitempty"`
+	Expiration int64        `json:"expiration,omitempty"`
+	ExpiredAT  int64        `json:"expiredAt,omitempty"`
+}
+
+const (
+	// keys for the entry object
+	KEY_DATA       = "data"
+	KEY_EXPIREDAT  = "expiredAt"
+	KEY_EXPIRATION = "expiration"
+)
+
+var store cachemdl.Cacher
+
+var ErrOtpNotFound = errors.New("OTP_NOT_FOUND")
+var ErrInvalidDataType = errors.New("INVALID_DATA_Type")
+
+// Init initializes otp manager with provided cache. Subsequent calls will not have any effect after first initialization.
+func Init(cache cachemdl.Cacher) {
+	if store != nil {
+		return
+	}
+
+	store = cache
+}
+
+// NewEntry prepares the object required to store data in session.
+//
+// The `exp` field interprets time in seconds. Ex. For 5 seconds, set `5`
+func NewOTPEntry(val gjson.Result, exp int64) Entry {
+	duration := time.Duration(exp) * time.Second
+	deadLine := time.Now().Add(duration).Unix()
+	return Entry{
+		Data:       val,
+		Expiration: exp,
+		ExpiredAT:  deadLine,
+	}
+}
+
+// NewRedisEntry prepares the entry for redis cache. This is required because redis accepts a byte array.
+func NewRedisEntry(entry Entry) string {
+	var data string
+	data, _ = sjson.Set(data, KEY_DATA, entry.Data.Value())
+	data, _ = sjson.Set(data, KEY_EXPIRATION, entry.Expiration)
+	data, _ = sjson.Set(data, KEY_EXPIREDAT, entry.ExpiredAT)
+
+	return data
+}
+
+// Store adds/ updates the entry against the provided key.
+func Store(key string, entry Entry) {
+	duration := time.Duration(entry.Expiration) * time.Second
+	// if otp manager uses redis cache, the data field (gjson.Result) is saved as is.
+	// This adds irrelevant fields in redis cache and we get them on retrieve operation.
+	// The following operation needs to be performed so that the data is marshaled correctly. Redis only accepts []byte{}.
+	if store.Type() == cachemdl.TypeRedisCache {
+		store.SetWithExpiration(key, NewRedisEntry(entry), duration)
+		return
+	}
+	store.SetWithExpiration(key, entry, duration)
+}
+
+// // Delete removes the otp entry. If the key is not present, error `ErrOtpNotFound` will be thrown. Caller can ignore error if this is acceptable.
+func DeleteOTP(key string) error {
+	_, ok := store.Get(key)
+	if !ok {
+		return ErrOtpNotFound
+	}
+
+	store.Delete(key)
+	return nil
+}
+
+func GetOTP(key string) (Entry, bool) {
+	data, ok := store.Get(key)
+	if !ok {
+		return Entry{}, false
+	}
+
+	switch v := data.(type) {
+	case string: // for result from redis cache
+		res := gjson.Parse(v)
+		return Entry{
+			Data:       res.Get(KEY_DATA),
+			Expiration: res.Get(KEY_EXPIRATION).Int(),
+			ExpiredAT:  res.Get(KEY_EXPIREDAT).Int(),
+		}, true
+
+	case Entry: // for result from fastcache
+		return v, true
+
+	default:
+		return Entry{}, false
+	}
+}