diff --git a/cmd/flux/create_secret_helm_test.go b/cmd/flux/create_secret_helm_test.go
index fe0bc0c941789cc3524fb780103190ca7ded0b88..821f8311be4e82712e81bc1a29b7514843f36aa4 100644
--- a/cmd/flux/create_secret_helm_test.go
+++ b/cmd/flux/create_secret_helm_test.go
@@ -1,3 +1,19 @@
+/*
+Copyright 2022 The Flux authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
 package main
 
 import (
diff --git a/cmd/flux/create_secret_oci.go b/cmd/flux/create_secret_oci.go
new file mode 100644
index 0000000000000000000000000000000000000000..decd680c3afce3bbb7b68f72f830933753886c46
--- /dev/null
+++ b/cmd/flux/create_secret_oci.go
@@ -0,0 +1,117 @@
+/*
+Copyright 2022 The Flux authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/fluxcd/flux2/internal/utils"
+	"github.com/fluxcd/flux2/pkg/manifestgen/sourcesecret"
+	"github.com/google/go-containerregistry/pkg/name"
+	"github.com/spf13/cobra"
+	corev1 "k8s.io/api/core/v1"
+	"sigs.k8s.io/yaml"
+)
+
+var createSecretOCICmd = &cobra.Command{
+	Use:   "oci [name]",
+	Short: "Create or update a Kubernetes secret for docker authentication",
+	Long:  `The create secret oci command generates a Kubernetes secret with `,
+	Example: `  # Create a secret for a OCI repository using basic authentication
+  flux create secret oci podinfo-auth \
+    --url=ghcr.io/stefanprodan/charts \
+    --username=username \
+    --password=password
+	`,
+	RunE: createSecretOCICmdRun,
+}
+
+type secretOCIFlags struct {
+	url      string
+	password string
+	username string
+}
+
+var secretOCIArgs = secretOCIFlags{}
+
+func init() {
+	createSecretOCICmd.Flags().StringVar(&secretOCIArgs.url, "url", "", "oci repository address e.g ghcr.io/stefanprodan/charts")
+	createSecretOCICmd.Flags().StringVarP(&secretOCIArgs.username, "username", "u", "", "basic authentication username")
+	createSecretOCICmd.Flags().StringVarP(&secretOCIArgs.password, "password", "p", "", "basic authentication")
+
+	createSecretCmd.AddCommand(createSecretOCICmd)
+}
+
+func createSecretOCICmdRun(cmd *cobra.Command, args []string) error {
+	if len(args) < 1 {
+		return fmt.Errorf("name is required")
+	}
+
+	secretName := args[0]
+
+	if secretOCIArgs.url == "" {
+		return fmt.Errorf("--url is required")
+	}
+
+	if secretOCIArgs.username == "" {
+		return fmt.Errorf("--username is required")
+	}
+
+	if secretOCIArgs.password == "" {
+		return fmt.Errorf("--password is required")
+	}
+
+	if _, err := name.ParseReference(secretOCIArgs.url); err != nil {
+		return fmt.Errorf("error parsing url: '%s'", err)
+	}
+
+	opts := sourcesecret.Options{
+		Name:      secretName,
+		Namespace: *kubeconfigArgs.Namespace,
+		Registry:  secretOCIArgs.url,
+		Password:  secretOCIArgs.password,
+		Username:  secretOCIArgs.username,
+	}
+
+	secret, err := sourcesecret.Generate(opts)
+	if err != nil {
+		return err
+	}
+
+	if createArgs.export {
+		rootCmd.Println(secret.Content)
+		return nil
+	}
+
+	ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
+	defer cancel()
+	kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
+	if err != nil {
+		return err
+	}
+	var s corev1.Secret
+	if err := yaml.Unmarshal([]byte(secret.Content), &s); err != nil {
+		return err
+	}
+	if err := upsertSecret(ctx, kubeClient, s); err != nil {
+		return err
+	}
+
+	logger.Actionf("oci secret '%s' created in '%s' namespace", secretName, *kubeconfigArgs.Namespace)
+	return nil
+}
diff --git a/cmd/flux/create_secret_oci_test.go b/cmd/flux/create_secret_oci_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a78977961e8c4a9841a330ae8f94817465fa8fea
--- /dev/null
+++ b/cmd/flux/create_secret_oci_test.go
@@ -0,0 +1,51 @@
+/*
+Copyright 2022 The Flux authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package main
+
+import (
+	"testing"
+)
+
+func TestCreateSecretOCI(t *testing.T) {
+	tests := []struct {
+		name   string
+		args   string
+		assert assertFunc
+	}{
+		{
+			args:   "create secret oci",
+			assert: assertError("name is required"),
+		},
+		{
+			args:   "create secret oci ghcr",
+			assert: assertError("--url is required"),
+		},
+		{
+			args:   "create secret oci ghcr --namespace=my-namespace --url ghcr.io --username stefanprodan --password=password --export",
+			assert: assertGoldenFile("testdata/create_secret/oci/create-secret.yaml"),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			cmd := cmdTestCase{
+				args:   tt.args,
+				assert: tt.assert,
+			}
+			cmd.runTestCmd(t)
+		})
+	}
+}
diff --git a/cmd/flux/testdata/create_secret/oci/create-secret.yaml b/cmd/flux/testdata/create_secret/oci/create-secret.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b023bbe28758fd272a63ed32b65d7ac0c669a4a1
--- /dev/null
+++ b/cmd/flux/testdata/create_secret/oci/create-secret.yaml
@@ -0,0 +1,10 @@
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: ghcr
+  namespace: my-namespace
+stringData:
+  .dockerconfigjson: '{"auths":{"ghcr.io":{"username":"stefanprodan","password":"password","auth":"c3RlZmFucHJvZGFuOnBhc3N3b3Jk"}}}'
+type: kubernetes.io/dockerconfigjson
+
diff --git a/pkg/manifestgen/sourcesecret/options.go b/pkg/manifestgen/sourcesecret/options.go
index c5239bfbd82755697bdf8b98c68ede2ad3f3387e..371e6f9b15f203a4406a0334a04c89ef4c339796 100644
--- a/pkg/manifestgen/sourcesecret/options.go
+++ b/pkg/manifestgen/sourcesecret/options.go
@@ -43,6 +43,7 @@ type Options struct {
 	Name                string
 	Namespace           string
 	Labels              map[string]string
+	Registry            string
 	SSHHostname         string
 	PrivateKeyAlgorithm PrivateKeyAlgorithm
 	RSAKeyBits          int
diff --git a/pkg/manifestgen/sourcesecret/sourcesecret.go b/pkg/manifestgen/sourcesecret/sourcesecret.go
index 53806328be4f6bf34ab36314c2ca28532a2cffa6..2ea33227bac8af2fe4867afc8c17af145ddf827b 100644
--- a/pkg/manifestgen/sourcesecret/sourcesecret.go
+++ b/pkg/manifestgen/sourcesecret/sourcesecret.go
@@ -18,6 +18,8 @@ package sourcesecret
 
 import (
 	"bytes"
+	"encoding/base64"
+	"encoding/json"
 	"fmt"
 	"net"
 	"os"
@@ -36,6 +38,18 @@ import (
 
 const defaultSSHPort = 22
 
+type DockerConfigJson struct {
+	Auths DockerConfig `json:"auths"`
+}
+
+type DockerConfig map[string]DockerConfigEntry
+
+type DockerConfigEntry struct {
+	Username string `json:"username,omitempty"`
+	Password string `json:"password,omitempty"`
+	Auth     string `json:"auth,omitempty"`
+}
+
 func Generate(options Options) (*manifestgen.Manifest, error) {
 	var err error
 
@@ -77,7 +91,15 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
 		}
 	}
 
-	secret := buildSecret(keypair, hostKey, caFile, certFile, keyFile, options)
+	var dockerCfgJson []byte
+	if options.Registry != "" {
+		dockerCfgJson, err = generateDockerConfigJson(options.Registry, options.Username, options.Password)
+		if err != nil {
+			return nil, fmt.Errorf("failed to generate json for docker config: %w", err)
+		}
+	}
+
+	secret := buildSecret(keypair, hostKey, caFile, certFile, keyFile, dockerCfgJson, options)
 	b, err := yaml.Marshal(secret)
 	if err != nil {
 		return nil, err
@@ -89,7 +111,7 @@ func Generate(options Options) (*manifestgen.Manifest, error) {
 	}, nil
 }
 
-func buildSecret(keypair *ssh.KeyPair, hostKey, caFile, certFile, keyFile []byte, options Options) (secret corev1.Secret) {
+func buildSecret(keypair *ssh.KeyPair, hostKey, caFile, certFile, keyFile, dockerCfg []byte, options Options) (secret corev1.Secret) {
 	secret.TypeMeta = metav1.TypeMeta{
 		APIVersion: "v1",
 		Kind:       "Secret",
@@ -101,6 +123,12 @@ func buildSecret(keypair *ssh.KeyPair, hostKey, caFile, certFile, keyFile []byte
 	secret.Labels = options.Labels
 	secret.StringData = map[string]string{}
 
+	if dockerCfg != nil {
+		secret.Type = corev1.SecretTypeDockerConfigJson
+		secret.StringData[corev1.DockerConfigJsonKey] = string(dockerCfg)
+		return
+	}
+
 	if options.Username != "" && options.Password != "" {
 		secret.StringData[UsernameSecretKey] = options.Username
 		secret.StringData[PasswordSecretKey] = options.Password
@@ -189,3 +217,19 @@ func resourceToString(data []byte) string {
 	data = bytes.Replace(data, []byte("status: {}\n"), []byte(""), 1)
 	return string(data)
 }
+
+func generateDockerConfigJson(url, username, password string) ([]byte, error) {
+	cred := fmt.Sprintf("%s:%s", username, password)
+	auth := base64.StdEncoding.EncodeToString([]byte(cred))
+	cfg := DockerConfigJson{
+		Auths: map[string]DockerConfigEntry{
+			url: {
+				Username: username,
+				Password: password,
+				Auth:     auth,
+			},
+		},
+	}
+
+	return json.Marshal(cfg)
+}