mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 18:07:31 +00:00
feat: invite user link (#8578)
# Which Problems Are Solved As an administrator I want to be able to invite users to my application with the API V2, some user data I will already prefil, the user should add the authentication method themself (password, passkey, sso). # How the Problems Are Solved - A user can now be created with a email explicitly set to false. - If a user has no verified email and no authentication method, an `InviteCode` can be created through the User V2 API. - the code can be returned or sent through email - additionally `URLTemplate` and an `ApplicatioName` can provided for the email - The code can be resent and verified through the User V2 API - The V1 login allows users to verify and resend the code and set a password (analog user initialization) - The message text for the user invitation can be customized # Additional Changes - `verifyUserPasskeyCode` directly uses `crypto.VerifyCode` (instead of `verifyEncryptedCode`) - `verifyEncryptedCode` is removed (unnecessarily queried for the code generator) # Additional Context - closes #8310 - TODO: login V2 will have to implement invite flow: https://github.com/zitadel/typescript/issues/166
This commit is contained in:
@@ -137,4 +137,8 @@ func init() {
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, MachineSecretCheckSucceededType, MachineSecretCheckSucceededEventMapper)
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, MachineSecretCheckFailedType, MachineSecretCheckFailedEventMapper)
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, MachineSecretHashUpdatedType, eventstore.GenericEventMapper[MachineSecretHashUpdatedEvent])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCodeAddedType, eventstore.GenericEventMapper[HumanInviteCodeAddedEvent])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCodeSentType, eventstore.GenericEventMapper[HumanInviteCodeSentEvent])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCheckSucceededType, eventstore.GenericEventMapper[HumanInviteCheckSucceededEvent])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCheckFailedType, eventstore.GenericEventMapper[HumanInviteCheckFailedEvent])
|
||||
}
|
||||
|
@@ -21,6 +21,10 @@ const (
|
||||
HumanInitialCodeSentType = humanEventPrefix + "initialization.code.sent"
|
||||
HumanInitializedCheckSucceededType = humanEventPrefix + "initialization.check.succeeded"
|
||||
HumanInitializedCheckFailedType = humanEventPrefix + "initialization.check.failed"
|
||||
HumanInviteCodeAddedType = humanEventPrefix + "invite.code.added"
|
||||
HumanInviteCodeSentType = humanEventPrefix + "invite.code.sent"
|
||||
HumanInviteCheckSucceededType = humanEventPrefix + "invite.check.succeeded"
|
||||
HumanInviteCheckFailedType = humanEventPrefix + "invite.check.failed"
|
||||
HumanSignedOutType = humanEventPrefix + "signed.out"
|
||||
)
|
||||
|
||||
@@ -379,6 +383,137 @@ func HumanInitializedCheckFailedEventMapper(event eventstore.Event) (eventstore.
|
||||
}, nil
|
||||
}
|
||||
|
||||
type HumanInviteCodeAddedEvent struct {
|
||||
*eventstore.BaseEvent `json:"-"`
|
||||
Code *crypto.CryptoValue `json:"code,omitempty"`
|
||||
Expiry time.Duration `json:"expiry,omitempty"`
|
||||
TriggeredAtOrigin string `json:"triggerOrigin,omitempty"`
|
||||
URLTemplate string `json:"urlTemplate,omitempty"`
|
||||
CodeReturned bool `json:"codeReturned,omitempty"`
|
||||
ApplicationName string `json:"applicationName,omitempty"`
|
||||
AuthRequestID string `json:"authRequestID,omitempty"`
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeAddedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||
e.BaseEvent = b
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeAddedEvent) Payload() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeAddedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeAddedEvent) TriggerOrigin() string {
|
||||
return e.TriggeredAtOrigin
|
||||
}
|
||||
|
||||
func NewHumanInviteCodeAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
code *crypto.CryptoValue,
|
||||
expiry time.Duration,
|
||||
urlTemplate string,
|
||||
codeReturned bool,
|
||||
applicationName string,
|
||||
authRequestID string,
|
||||
) *HumanInviteCodeAddedEvent {
|
||||
return &HumanInviteCodeAddedEvent{
|
||||
BaseEvent: eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanInviteCodeAddedType,
|
||||
),
|
||||
Code: code,
|
||||
Expiry: expiry,
|
||||
TriggeredAtOrigin: http.DomainContext(ctx).Origin(),
|
||||
URLTemplate: urlTemplate,
|
||||
CodeReturned: codeReturned,
|
||||
ApplicationName: applicationName,
|
||||
AuthRequestID: authRequestID,
|
||||
}
|
||||
}
|
||||
|
||||
type HumanInviteCodeSentEvent struct {
|
||||
*eventstore.BaseEvent `json:"-"`
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeSentEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||
e.BaseEvent = b
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeSentEvent) Payload() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *HumanInviteCodeSentEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanInviteCodeSentEvent(ctx context.Context, aggregate *eventstore.Aggregate) *HumanInviteCodeSentEvent {
|
||||
return &HumanInviteCodeSentEvent{
|
||||
BaseEvent: eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanInviteCodeSentType,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type HumanInviteCheckSucceededEvent struct {
|
||||
*eventstore.BaseEvent `json:"-"`
|
||||
}
|
||||
|
||||
func (e *HumanInviteCheckSucceededEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||
e.BaseEvent = b
|
||||
}
|
||||
|
||||
func (e *HumanInviteCheckSucceededEvent) Payload() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *HumanInviteCheckSucceededEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanInviteCheckSucceededEvent(ctx context.Context, aggregate *eventstore.Aggregate) *HumanInviteCheckSucceededEvent {
|
||||
return &HumanInviteCheckSucceededEvent{
|
||||
BaseEvent: eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanInviteCheckSucceededType,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type HumanInviteCheckFailedEvent struct {
|
||||
*eventstore.BaseEvent `json:"-"`
|
||||
}
|
||||
|
||||
func (e *HumanInviteCheckFailedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||
e.BaseEvent = b
|
||||
}
|
||||
|
||||
func (e *HumanInviteCheckFailedEvent) Payload() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *HumanInviteCheckFailedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanInviteCheckFailedEvent(ctx context.Context, aggregate *eventstore.Aggregate) *HumanInviteCheckFailedEvent {
|
||||
return &HumanInviteCheckFailedEvent{
|
||||
BaseEvent: eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanInviteCheckFailedType,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type HumanSignedOutEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
|
Reference in New Issue
Block a user