feat: allow setting op.Crypto during provider setup (#778)

Add a `op.WithCrypto` `op.Option` that allows developers to specify
their custom `op.Crypto` implementations during setup. If the
`op.Option` is used, it will override `op.Config.CryptoKey`.

Closes https://github.com/zitadel/oidc/issues/736.

### Definition of Ready

- [x] I am happy with the code
- [x] Short description of the feature/issue is added in the pr
description
- [x] PR is linked to the corresponding user story
- [ ] Acceptance criteria are met
- [ ] All open todos and follow ups are defined in a new ticket and
justified
- [ ] Deviations from the acceptance criteria and design are agreed with
the PO and documented.
- [x] No debug or dead code
- [ ] My code has no repetitions
- [ ] Critical parts are tested automatically
- [ ] Where possible E2E tests are implemented
- [x] Documentation/examples are up-to-date
- [ ] All non-functional requirements are met
- [ ] Functionality of the acceptance criteria is checked manually on
the dev system.

---------

Signed-off-by: mqf20 <mingqingfoo@gmail.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
mqf20
2025-08-05 20:00:11 +08:00
committed by GitHub
parent 1fb34f3d41
commit 3edc81ed9a
4 changed files with 68 additions and 7 deletions
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"github.com/zitadel/oidc/v3/pkg/crypto"
"github.com/zitadel/oidc/v3/pkg/op"
"log/slog"
)
var _ op.Crypto = &myCrypto{}
// myCrypto demonstrates how to provide your custom implementation of op.Crypto.
type myCrypto struct {
key string
logger *slog.Logger
}
func newMyCrypto(key [32]byte, l *slog.Logger) *myCrypto {
return &myCrypto{
key: string(key[:32]),
logger: l,
}
}
func (m *myCrypto) Decrypt(s string) (string, error) {
m.logger.Info("decrypting")
return crypto.DecryptAES(s, m.key)
}
func (m *myCrypto) Encrypt(s string) (string, error) {
m.logger.Info("encrypting")
return crypto.EncryptAES(s, m.key)
}
+15 -3
View File
@@ -51,7 +51,13 @@ func SetupServer(issuer string, storage Storage, logger *slog.Logger, wrapServer
})
// creation of the OpenIDProvider with the just created in-memory Storage
provider, err := newOP(storage, issuer, key, logger, extraOptions...)
provider, err := newOP(
storage,
issuer,
key,
logger,
extraOptions...,
)
if err != nil {
log.Fatal(err)
}
@@ -84,10 +90,16 @@ func SetupServer(issuer string, storage Storage, logger *slog.Logger, wrapServer
return router
}
// newOP will create an OpenID Provider for localhost on a specified port with a given encryption key
// newOP will create an OpenID Provider for localhost on a specified port
// and a predefined default logout uri
// it will enable all options (see descriptions)
func newOP(storage op.Storage, issuer string, key [32]byte, logger *slog.Logger, extraOptions ...op.Option) (op.OpenIDProvider, error) {
func newOP(
storage op.Storage,
issuer string,
key [32]byte, // encryption key
logger *slog.Logger,
extraOptions ...op.Option,
) (op.OpenIDProvider, error) {
config := &op.Config{
CryptoKey: key,
+9 -2
View File
@@ -44,8 +44,15 @@ func main() {
logger.Error("cannot create UserStore", "error", err)
os.Exit(1)
}
storage := storage.NewStorage(store)
router := exampleop.SetupServer(issuer, storage, logger, false)
stor := storage.NewStorage(store)
router := exampleop.SetupServer(
issuer,
stor,
logger,
false,
//op.WithCrypto(newMyCrypto(sha256.Sum256([]byte("test")), logger)),
)
server := &http.Server{
Addr: ":" + cfg.Port,