chore(api): proto definition of passkeys endpoints (user service) (#5864)

* feat: first proto definition of passkeys endpoints

* improve passkeys requests

* fix: some renaming of passkey endpoint attributes

* change to post methods

* improve passkeys requests

* add code id and make codes optional

* fix: some documentation for passkeys endpoints

* drop code from VerifyPasskeyRegistrationRequest

not needed, as disccussed

* put code_id and code in a nested object

* add passkey_id to RegisterPasskeyResponse

* improve description

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
Stefan Benz 2023-05-17 09:06:11 +02:00 committed by GitHub
parent 116d11dcf7
commit 80815e89cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 226 additions and 1 deletions

View File

@ -0,0 +1,50 @@
syntax = "proto3";
package zitadel.user.v2alpha;
option go_package = "github.com/zitadel/zitadel/pkg/grpc/user/v2alpha;user";
import "google/api/field_behavior.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
enum PasskeyAuthenticator {
PASSKEY_AUTHENTICATOR_UNSPECIFIED = 0;
PASSKEY_AUTHENTICATOR_PLATFORM = 1;
PASSKEY_AUTHENTICATOR_CROSS_PLATFORM = 2;
}
message SendPasskeyRegistrationLink {
optional string url_template = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"https://example.com/passkey/register?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}\"";
description: "\"Optionally set a url_template, which will be used in the mail sent by ZITADEL to guide the user to your passkey registration page. If no template is set, the default ZITADEL url will be used.\""
}
];
}
message ReturnPasskeyRegistrationCode {}
message PasskeyRegistrationCode {
string id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"id to the one time code generated by ZITADEL\"";
example: "\"e2a48d6a-362b-4db6-a1fb-34feab84dc62\"";
max_length: 200;
}
];
string code = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"one time code generated by ZITADEL\"";
example: "\"SomeSpecialCode\"";
max_length: 200;
}
];
}

View File

@ -30,7 +30,6 @@ message SetHumanEmail {
message SendEmailVerificationCode {
optional string url_template = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;

View File

@ -4,11 +4,13 @@ package zitadel.user.v2alpha;
import "zitadel/object/v2alpha/object.proto";
import "zitadel/protoc_gen_zitadel/v2/options.proto";
import "zitadel/user/v2alpha/auth.proto";
import "zitadel/user/v2alpha/email.proto";
import "zitadel/user/v2alpha/password.proto";
import "zitadel/user/v2alpha/user.proto";
import "google/api/annotations.proto";
import "google/api/field_behavior.proto";
import "google/protobuf/duration.proto";
import "protoc-gen-openapiv2/options/annotations.proto";
import "validate/validate.proto";
@ -153,6 +155,73 @@ service UserService {
};
};
}
rpc RegisterPasskey (RegisterPasskeyRequest) returns (RegisterPasskeyResponse) {
option (google.api.http) = {
post: "/users/{user_id}/passkeys"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Start the registration of passkey for a user";
description: "Start the registration of a passkey for a user, as a response the public key credential creation options are returned, which are used to verify the passkey."
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
rpc VerifyPasskeyRegistration (VerifyPasskeyRegistrationRequest) returns (VerifyPasskeyRegistrationResponse) {
option (google.api.http) = {
post: "/users/{user_id}/passkeys/{passkey_id}"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "authenticated"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Verify a passkey for a user";
description: "Verify the passkey registration with the public key credential."
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
rpc CreatePasskeyRegistrationLink (CreatePasskeyRegistrationLinkRequest) returns (CreatePasskeyRegistrationLinkResponse) {
option (google.api.http) = {
post: "/users/{user_id}/passkeys/registration_link"
body: "*"
};
option (zitadel.protoc_gen_zitadel.v2.options) = {
auth_option: {
permission: "user.passkey.write"
}
};
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
summary: "Create a passkey registration link for a user";
description: "Create a passkey registration link which includes a code and either return it or send it to the user."
responses: {
key: "200"
value: {
description: "OK";
}
};
};
}
}
message AddHumanUserRequest{
@ -254,3 +323,110 @@ message VerifyEmailRequest{
message VerifyEmailResponse{
zitadel.object.v2alpha.Details details = 1;
}
message RegisterPasskeyRequest{
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
optional PasskeyRegistrationCode code = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"one time code generated by ZITADEL; required to start the passkey registration without user authentication\"";
}
];
PasskeyAuthenticator authenticator = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"Optionally specify the authenticator type of the passkey device (platform or cross-platform). If none is provided, both values are allowed.\"";
}
];
}
message RegisterPasskeyResponse{
zitadel.object.v2alpha.Details details = 1;
string passkey_id = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\""
}
];
bytes public_key_credential_creation_options = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "json representation of public key credential creation options used by the passkey client"
example: "\"eyJwdWJsaWNLZXkiOnsiY2hhbGxlbmdlIoplfZm4vM21qSzBPdjltN2x6VWhnclYyejFJSlVzZnpLd0Z1TytWTWtzRW1Icz0iLCJycCI6eyJuYW1lIjoiWklUQURFTCIsImlkIjoiYWNtZS1nem9lNHgueml0YWRlbC5jbG91ZCJ9LCJ1c2VyIjp7Im5hbWUiOiJ0ZXN0dXNlcjU1QGFjbWUueml0YWRlbC5jbG91ZCIsImRpc3BsYXlOYW1lIjoiVGVzdCBUZXN0IiwiaWQiOiJNVGd5TVRVMk1qWTBNakk1TXpBMk5qSTEifSwicHViS2V5Q3JlZFBhcmFtcyI6W3sidHlwZSI6InB1YmxpYy1rZXkiLCJhbGciOi03fSx7InR5cGUiOiJwdWJsaWMta2V5IiwiYWxnIjotMzV9LHsidHlwZSI6InB1YmxpYy1rZXkiLCJhbGciOi0zNn0seyJ0eXBlIjoicHVibGljLWtleSIsImFsZyI6LTI1N30seyJ0eXBlIjoicHVibGljLWtleSIsImFsZyI6LTI1OH0seyJ0eXBlIjoicHVibGljLWtleSIsImFsZyI6LTI1OX0seyJ0eXBlIjoicHVibGljLWtleSIsImFsZyI6LTM3fSx7InR5cGUiOiJwdWJsaWMta2V5IiwiYWxnIjotMzh9LHsidHlwZSI6InB1YmxpYy1rZXkiLCJhbGciOi0zOX0seyJ0eXBlIjoicHVibGljLWtleSIsImFsZyI6LTh9XSwiYXV0aGVudGljYXRvclNlbGVjdGlvbiI6eyJ1c2VyVmVyaWZpY2F0aW9uIjoiZGlzY291cmFnZWQifn2ilGltZW91dCI6NjAwMDAsImF0dGVzdGF0aW9uIjoibm9uZSJ9fQ==\""
}
];
}
message VerifyPasskeyRegistrationRequest{
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
string passkey_id = 2 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"fabde5c8-c13f-481d-a90b-5e59a001a076\"";
}
];
bytes public_key_credential = 3 [
(validate.rules).bytes = {min_len: 55, max_len: 1048576},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "JSON representation of public key credential issued by the passkey client";
min_length: 55;
max_length: 1048576; //1 MB
}
];
string passkey_name = 4 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"fido key\""
}
];
}
message VerifyPasskeyRegistrationResponse{
zitadel.object.v2alpha.Details details = 1;
}
message CreatePasskeyRegistrationLinkRequest{
string user_id = 1 [
(validate.rules).string = {min_len: 1, max_len: 200},
(google.api.field_behavior) = REQUIRED,
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
min_length: 1;
max_length: 200;
example: "\"d654e6ba-70a3-48ef-a95d-37c8d8a7901a\"";
}
];
// if no medium is specified, an email is sent with the default url
oneof medium {
SendPasskeyRegistrationLink send_link = 2;
ReturnPasskeyRegistrationCode return_code = 3;
}
}
message CreatePasskeyRegistrationLinkResponse{
zitadel.object.v2alpha.Details details = 1;
// in case the medium was set to return_code, the code will be returned
optional PasskeyRegistrationCode code = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "\"one time code generated by ZITADEL; required to start the passkey registration without user authentication\"";
}
];
}