diff --git a/cmd/cache/main.go b/cmd/cache/main.go
index 2217d6fb077101a7922ab2d9db3d99fcc8606806..0db3723ab09cb4cf45928bcbffbdd264324875e6 100644
--- a/cmd/cache/main.go
+++ b/cmd/cache/main.go
@@ -14,12 +14,16 @@ import (
 	goa "goa.design/goa/v3/pkg"
 	"golang.org/x/sync/errgroup"
 
+	goacache "code.vereign.com/gaiax/tsa/cache/gen/cache"
 	goahealth "code.vereign.com/gaiax/tsa/cache/gen/health"
+	goacachesrv "code.vereign.com/gaiax/tsa/cache/gen/http/cache/server"
 	goahealthsrv "code.vereign.com/gaiax/tsa/cache/gen/http/health/server"
 	goaopenapisrv "code.vereign.com/gaiax/tsa/cache/gen/http/openapi/server"
 	"code.vereign.com/gaiax/tsa/cache/gen/openapi"
+	"code.vereign.com/gaiax/tsa/cache/internal/clients/redis"
 	"code.vereign.com/gaiax/tsa/cache/internal/config"
 	"code.vereign.com/gaiax/tsa/cache/internal/service"
+	"code.vereign.com/gaiax/tsa/cache/internal/service/cache"
 	"code.vereign.com/gaiax/tsa/cache/internal/service/health"
 	"code.vereign.com/gaiax/tsa/golib/graceful"
 )
@@ -40,20 +44,27 @@ func main() {
 
 	logger.Info("start cache service", zap.String("version", Version), zap.String("goa", goa.Version()))
 
+	// create redis client
+	redis := redis.New(cfg.Redis.Addr, cfg.Redis.User, cfg.Redis.Pass, cfg.Redis.DB, cfg.Redis.TTL)
+
 	// create services
 	var (
+		cacheSvc  goacache.Service
 		healthSvc goahealth.Service
 	)
 	{
+		cacheSvc = cache.New(redis, logger)
 		healthSvc = health.New()
 	}
 
 	// create endpoints
 	var (
+		cacheEndpoints   *goacache.Endpoints
 		healthEndpoints  *goahealth.Endpoints
 		openapiEndpoints *openapi.Endpoints
 	)
 	{
+		cacheEndpoints = goacache.NewEndpoints(cacheSvc)
 		healthEndpoints = goahealth.NewEndpoints(healthSvc)
 		openapiEndpoints = openapi.NewEndpoints(nil)
 	}
@@ -72,15 +83,18 @@ func main() {
 	mux := goahttp.NewMuxer()
 
 	var (
+		cacheServer   *goacachesrv.Server
 		healthServer  *goahealthsrv.Server
 		openapiServer *goaopenapisrv.Server
 	)
 	{
+		cacheServer = goacachesrv.New(cacheEndpoints, mux, dec, enc, nil, errFormatter)
 		healthServer = goahealthsrv.New(healthEndpoints, mux, dec, enc, nil, errFormatter)
 		openapiServer = goaopenapisrv.New(openapiEndpoints, mux, dec, enc, nil, errFormatter, nil, nil)
 	}
 
 	// Configure the mux.
+	goacachesrv.Mount(mux, cacheServer)
 	goahealthsrv.Mount(mux, healthServer)
 	goaopenapisrv.Mount(mux, openapiServer)
 
diff --git a/design/design.go b/design/design.go
index 24898ec3e833d5870f75fea6d0649d6a1d241401..0617832a38b93fa17411bdfbb53bd60df6dd43c0 100644
--- a/design/design.go
+++ b/design/design.go
@@ -10,7 +10,7 @@ var _ = API("cache", func() {
 		Description("Cache Server")
 		Host("development", func() {
 			Description("Local development server")
-			URI("http://localhost:8080")
+			URI("http://localhost:8083")
 		})
 	})
 })
@@ -37,6 +37,33 @@ var _ = Service("health", func() {
 	})
 })
 
+var _ = Service("cache", func() {
+	Description("Cache service allows storing and retrieving data from distributed cache.")
+
+	Method("Get", func() {
+		Description("Get value from the cache. The result is a sequence of bytes which the client must decode.")
+
+		Payload(CacheGetRequest)
+		Result(Bytes)
+
+		HTTP(func() {
+			GET("/v1/cache")
+
+			Header("key:x-cache-key", String, "Cache entry key", func() {
+				Example("did:web:example.com")
+			})
+			Header("namespace:x-cache-namespace", String, "Cache entry namespace", func() {
+				Example("Login")
+			})
+			Header("scope:x-cache-scope", String, "Cache entry scope", func() {
+				Example("administration")
+			})
+
+			Response(StatusOK)
+		})
+	})
+})
+
 var _ = Service("openapi", func() {
 	Description("The openapi service serves the OpenAPI(v3) definition.")
 	Meta("swagger:generate", "false")
diff --git a/design/types.go b/design/types.go
new file mode 100644
index 0000000000000000000000000000000000000000..a85991116ba7b668e76b6db6f504c53eb193ba41
--- /dev/null
+++ b/design/types.go
@@ -0,0 +1,10 @@
+package design
+
+import . "goa.design/goa/v3/dsl"
+
+var CacheGetRequest = Type("CacheGetRequest", func() {
+	Field(1, "key", String)
+	Field(2, "namespace", String)
+	Field(3, "scope", String) // Initial implementation with a single scope
+	Required("key", "namespace", "scope")
+})
diff --git a/internal/clients/redis/client.go b/internal/clients/redis/client.go
new file mode 100644
index 0000000000000000000000000000000000000000..73fe1086db9187c616f6bc57cfd6b4f138bf3ed4
--- /dev/null
+++ b/internal/clients/redis/client.go
@@ -0,0 +1,42 @@
+package redis
+
+import (
+	"context"
+	"time"
+
+	"github.com/go-redis/redis/v8"
+
+	"code.vereign.com/gaiax/tsa/golib/errors"
+)
+
+type Client struct {
+	rdb        *redis.Client
+	defaultTTL time.Duration
+}
+
+func New(addr, user, pass string, db int, defaultTTL time.Duration) *Client {
+	rdb := redis.NewClient(&redis.Options{
+		Addr:         addr,
+		Username:     user,
+		Password:     pass,
+		DB:           db,
+		DialTimeout:  10 * time.Second,
+		ReadTimeout:  5 * time.Second,
+		WriteTimeout: 5 * time.Second,
+	})
+
+	return &Client{
+		rdb: rdb,
+	}
+}
+
+func (c *Client) Get(ctx context.Context, key string) ([]byte, error) {
+	result := c.rdb.Get(ctx, key)
+	if result.Err() != nil {
+		if result.Err() == redis.Nil {
+			return nil, errors.New(errors.NotFound)
+		}
+		return nil, result.Err()
+	}
+	return []byte(result.Val()), nil
+}
diff --git a/internal/config/config.go b/internal/config/config.go
index bdb25c11fa2d8aa3c2ea8c19adb6d93c15d65799..38c84ee7304dcf412a17405e872be618118f79e2 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -3,15 +3,24 @@ package config
 import "time"
 
 type Config struct {
-	HTTP httpConfig
+	HTTP  httpConfig
+	Redis redisConfig
 
 	LogLevel string `envconfig:"LOG_LEVEL" default:"INFO"`
 }
 
 type httpConfig struct {
 	Host         string        `envconfig:"HTTP_HOST"`
-	Port         string        `envconfig:"HTTP_PORT" default:"8080"`
+	Port         string        `envconfig:"HTTP_PORT" default:"8083"`
 	IdleTimeout  time.Duration `envconfig:"HTTP_IDLE_TIMEOUT" default:"120s"`
 	ReadTimeout  time.Duration `envconfig:"HTTP_READ_TIMEOUT" default:"10s"`
 	WriteTimeout time.Duration `envconfig:"HTTP_WRITE_TIMEOUT" default:"10s"`
 }
+
+type redisConfig struct {
+	Addr string        `envconfig:"REDIS_ADDR" required:"true"`
+	User string        `envconfig:"REDIS_USER" required:"true"`
+	Pass string        `envconfig:"REDIS_PASS" required:"true"`
+	DB   int           `envconfig:"REDIS_DB" default:"0"`
+	TTL  time.Duration `envconfig:"REDIS_EXPIRATION"` //  no default expiration, keys are set to live forever
+}
diff --git a/internal/service/cache/service.go b/internal/service/cache/service.go
new file mode 100644
index 0000000000000000000000000000000000000000..28744bc09cc300d433ebbbcef861fcee7d6b16a4
--- /dev/null
+++ b/internal/service/cache/service.go
@@ -0,0 +1,52 @@
+package cache
+
+import (
+	"context"
+	"fmt"
+
+	"go.uber.org/zap"
+
+	"code.vereign.com/gaiax/tsa/cache/gen/cache"
+	"code.vereign.com/gaiax/tsa/golib/errors"
+)
+
+type Cache interface {
+	Get(ctx context.Context, key string) ([]byte, error)
+}
+
+type Service struct {
+	cache  Cache
+	logger *zap.Logger
+}
+
+func New(cache Cache, logger *zap.Logger) *Service {
+	return &Service{
+		cache:  cache,
+		logger: logger.With(zap.String("service", "cache")),
+	}
+}
+
+func (s *Service) Get(ctx context.Context, req *cache.CacheGetRequest) ([]byte, error) {
+	var operation = zap.String("operation", "get")
+	if req.Key == "" || req.Namespace == "" || req.Scope == "" {
+		s.logger.Error("bad request: missing key or namespace or scopes", operation)
+		return nil, errors.New(errors.BadRequest, "bad request")
+	}
+
+	// create key from the input fields
+	key := makeCacheKey(req.Key, req.Namespace, req.Scope)
+	data, err := s.cache.Get(ctx, key)
+	if err != nil {
+		s.logger.Error("error getting value from cache", zap.String("key", key), zap.Error(err))
+		if errors.Is(errors.NotFound, err) {
+			return nil, errors.New("key not found in cache", err)
+		}
+		return nil, errors.New("error getting value from cache", err)
+	}
+
+	return data, nil
+}
+
+func makeCacheKey(key, namespace, scope string) string {
+	return fmt.Sprintf("%s,%s,%s", namespace, scope, key)
+}