mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 14:47:33 +00:00
feat(api): allow Device Authorization Grant using custom login UI (#9387)
# Which Problems Are Solved The OAuth2 Device Authorization Grant could not yet been handled through the new login UI, resp. using the session API. This PR adds the ability for the login UI to get the required information to display the user and handle their decision (approve with authorization or deny) using the OIDC Service API. # How the Problems Are Solved - Added a `GetDeviceAuthorizationRequest` endpoint, which allows getting the `id`, `client_id`, `scope`, `app_name` and `project_name` of the device authorization request - Added a `AuthorizeOrDenyDeviceAuthorization` endpoint, which allows to approve/authorize with the session information or deny the request. The identification of the request is done by the `device_authorization_id` / `id` returned in the previous request. - To prevent leaking the `device_code` to the UI, but still having an easy reference, it's encrypted and returned as `id`, resp. decrypted when used. - Fixed returned error types for device token responses on token endpoint: - Explicitly return `access_denied` (without internal error) when user denied the request - Default to `invalid_grant` instead of `access_denied` - Explicitly check on initial state when approving the reqeust - Properly handle done case (also relates to initial check) - Documented the flow and handling in custom UIs (according to OIDC / SAML) # Additional Changes - fixed some typos and punctuation in the corresponding OIDC / SAML guides. - added some missing translations for auth and saml request # Additional Context - closes #6239 --------- Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
This commit is contained in:
@@ -114,4 +114,17 @@ enum ErrorReason {
|
||||
ERROR_REASON_REQUEST_NOT_SUPPORTED = 14;
|
||||
ERROR_REASON_REQUEST_URI_NOT_SUPPORTED = 15;
|
||||
ERROR_REASON_REGISTRATION_NOT_SUPPORTED = 16;
|
||||
}
|
||||
|
||||
message DeviceAuthorizationRequest {
|
||||
// The unique identifier of the device authorization request to be used for authorizing or denying the request.
|
||||
string id = 1;
|
||||
// The client_id of the application that initiated the device authorization request.
|
||||
string client_id = 2;
|
||||
// The scopes requested by the application.
|
||||
repeated string scope = 3;
|
||||
// Name of the client application.
|
||||
string app_name = 4;
|
||||
// Name of the project the client application is part of.
|
||||
string project_name = 5;
|
||||
}
|
@@ -147,6 +147,58 @@ service OIDCService {
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Get device authorization request
|
||||
//
|
||||
// Get the device authorization based on the provided "user code".
|
||||
// This will return the device authorization request, which contains the device authorization id
|
||||
// that is required to authorize the request once the user signed in or to deny it.
|
||||
rpc GetDeviceAuthorizationRequest(GetDeviceAuthorizationRequestRequest) returns (GetDeviceAuthorizationRequestResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v2/oidc/device_authorization/{user_code}"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// Authorize or deny device authorization
|
||||
//
|
||||
// Authorize or deny the device authorization request based on the provided device authorization id.
|
||||
rpc AuthorizeOrDenyDeviceAuthorization(AuthorizeOrDenyDeviceAuthorizationRequest) returns (AuthorizeOrDenyDeviceAuthorizationResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v2/oidc/device_authorization/{device_authorization_id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
message GetAuthRequestRequest {
|
||||
@@ -217,3 +269,42 @@ message CreateCallbackResponse {
|
||||
];
|
||||
}
|
||||
|
||||
message GetDeviceAuthorizationRequestRequest {
|
||||
// The user_code returned by the device authorization request and provided to the user by the device.
|
||||
string user_code = 1 [
|
||||
(validate.rules).string = {len: 9},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
min_length: 9;
|
||||
max_length: 9;
|
||||
example: "\"K9LV-3DMQ\"";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GetDeviceAuthorizationRequestResponse {
|
||||
DeviceAuthorizationRequest device_authorization_request = 1;
|
||||
}
|
||||
|
||||
message AuthorizeOrDenyDeviceAuthorizationRequest {
|
||||
// The device authorization id returned when submitting the user code.
|
||||
string device_authorization_id = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
min_length: 1;
|
||||
max_length: 200;
|
||||
}
|
||||
];
|
||||
|
||||
// The decision of the user to authorize or deny the device authorization request.
|
||||
oneof decision {
|
||||
option (validate.required) = true;
|
||||
// To authorize the device authorization request, the user's session must be provided.
|
||||
Session session = 2;
|
||||
// Deny the device authorization request.
|
||||
Deny deny = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Deny{}
|
||||
|
||||
message AuthorizeOrDenyDeviceAuthorizationResponse {}
|
Reference in New Issue
Block a user