diff --git a/cmd/zitadel/authz.yaml b/cmd/zitadel/authz.yaml
index 49f9e6d095..3f69f637f7 100644
--- a/cmd/zitadel/authz.yaml
+++ b/cmd/zitadel/authz.yaml
@@ -45,6 +45,7 @@ InternalAuthZ:
- "user.grant.write"
- "user.grant.delete"
- "user.membership.read"
+ - "user.credential.write"
- "features.read"
- "policy.read"
- "policy.write"
@@ -120,6 +121,7 @@ InternalAuthZ:
- "user.grant.write"
- "user.grant.delete"
- "user.membership.read"
+ - "user.credential.write"
- "features.read"
- "policy.read"
- "policy.write"
@@ -192,6 +194,7 @@ InternalAuthZ:
- "user.grant.write"
- "user.grant.delete"
- "user.membership.read"
+ - "user.credential.write"
- "features.read"
- "policy.read"
- "policy.write"
diff --git a/docs/docs/apis/proto/management.md b/docs/docs/apis/proto/management.md
index 6ebc734fb8..780b38f1ed 100644
--- a/docs/docs/apis/proto/management.md
+++ b/docs/docs/apis/proto/management.md
@@ -529,6 +529,20 @@ Returns all configured passwordless authenticators
POST: /users/{user_id}/passwordless/_search
+### AddPasswordlessRegistration
+
+> **rpc** AddPasswordlessRegistration([AddPasswordlessRegistrationRequest](#addpasswordlessregistrationrequest))
+[AddPasswordlessRegistrationResponse](#addpasswordlessregistrationresponse)
+
+Adds a new passwordless authenticator link to the user and returns it directly
+This link enables the user to register a new device if current passwordless devices are all platform authenticators
+e.g. User has already registered Windows Hello and wants to register FaceID on the iPhone
+
+
+
+ POST: /users/{user_id}/passwordless/_link
+
+
### SendPasswordlessRegistration
> **rpc** SendPasswordlessRegistration([SendPasswordlessRegistrationRequest](#sendpasswordlessregistrationrequest))
@@ -3369,6 +3383,30 @@ This is an empty request
+### AddPasswordlessRegistrationRequest
+
+
+
+| Field | Type | Description | Validation |
+| ----- | ---- | ----------- | ----------- |
+| user_id | string | - | string.min_len: 1
string.max_len: 200
|
+
+
+
+
+### AddPasswordlessRegistrationResponse
+
+
+
+| Field | Type | Description | Validation |
+| ----- | ---- | ----------- | ----------- |
+| details | zitadel.v1.ObjectDetails | - | |
+| link | string | - | |
+| expiration | google.protobuf.Duration | - | |
+
+
+
+
### AddProjectGrantMemberRequest
diff --git a/internal/api/grpc/management/user.go b/internal/api/grpc/management/user.go
index 6d87747c54..6ac983c61f 100644
--- a/internal/api/grpc/management/user.go
+++ b/internal/api/grpc/management/user.go
@@ -493,6 +493,19 @@ func (s *Server) ListHumanPasswordless(ctx context.Context, req *mgmt_pb.ListHum
}, nil
}
+func (s *Server) AddPasswordlessRegistration(ctx context.Context, req *mgmt_pb.AddPasswordlessRegistrationRequest) (*mgmt_pb.AddPasswordlessRegistrationResponse, error) {
+ ctxData := authz.GetCtxData(ctx)
+ initCode, err := s.command.HumanAddPasswordlessInitCode(ctx, req.UserId, ctxData.OrgID)
+ if err != nil {
+ return nil, err
+ }
+ return &mgmt_pb.AddPasswordlessRegistrationResponse{
+ Details: object.AddToDetailsPb(initCode.Sequence, initCode.ChangeDate, initCode.ResourceOwner),
+ Link: initCode.Link(s.systemDefaults.Notifications.Endpoints.PasswordlessRegistration),
+ Expiration: durationpb.New(initCode.Expiration),
+ }, nil
+}
+
func (s *Server) SendPasswordlessRegistration(ctx context.Context, req *mgmt_pb.SendPasswordlessRegistrationRequest) (*mgmt_pb.SendPasswordlessRegistrationResponse, error) {
ctxData := authz.GetCtxData(ctx)
initCode, err := s.command.HumanSendPasswordlessInitCode(ctx, req.UserId, ctxData.OrgID)
diff --git a/proto/zitadel/management.proto b/proto/zitadel/management.proto
index a31d33a36e..10fad473fa 100644
--- a/proto/zitadel/management.proto
+++ b/proto/zitadel/management.proto
@@ -574,6 +574,19 @@ service ManagementService {
};
}
+ // Adds a new passwordless authenticator link to the user and returns it directly
+ // This link enables the user to register a new device if current passwordless devices are all platform authenticators
+ // e.g. User has already registered Windows Hello and wants to register FaceID on the iPhone
+ rpc AddPasswordlessRegistration(AddPasswordlessRegistrationRequest) returns (AddPasswordlessRegistrationResponse) {
+ option (google.api.http) = {
+ post: "/users/{user_id}/passwordless/_link"
+ body: "*"
+ };
+ option (zitadel.v1.auth_option) = {
+ permission: "user.credential.write"
+ };
+ }
+
// Adds a new passwordless authenticator link to the user and sends it to the registered email address
// This link enables the user to register a new device if current passwordless devices are all platform authenticators
// e.g. User has already registered Windows Hello and wants to register FaceID on the iPhone
@@ -583,7 +596,7 @@ service ManagementService {
body: "*"
};
option (zitadel.v1.auth_option) = {
- permission: "authenticated"
+ permission: "user.write"
};
}
@@ -3290,6 +3303,16 @@ message ListHumanPasswordlessResponse {
repeated zitadel.user.v1.WebAuthNToken result = 1;
}
+message AddPasswordlessRegistrationRequest {
+ string user_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
+}
+
+message AddPasswordlessRegistrationResponse {
+ zitadel.v1.ObjectDetails details = 1;
+ string link = 2;
+ google.protobuf.Duration expiration = 3;
+}
+
message SendPasswordlessRegistrationRequest {
string user_id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
}