mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 17:27:31 +00:00
feat(api): add OIDC session service (#6157)
This PR starts the OIDC implementation for the API V2 including the Implicit and Code Flow. Co-authored-by: Livio Spring <livio.a@gmail.com> Co-authored-by: Tim Möhlmann <tim+github@zitadel.com> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
This commit is contained in:
117
proto/zitadel/oidc/v2alpha/authorization.proto
Normal file
117
proto/zitadel/oidc/v2alpha/authorization.proto
Normal file
@@ -0,0 +1,117 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package zitadel.oidc.v2alpha;
|
||||
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha;oidc";
|
||||
|
||||
message AuthRequest{
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
|
||||
external_docs: {
|
||||
url: "https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest";
|
||||
description: "Find out more about OIDC Auth Request parameters";
|
||||
}
|
||||
};
|
||||
|
||||
string id = 1 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "ID of the authorization request";
|
||||
}
|
||||
];
|
||||
|
||||
google.protobuf.Timestamp creation_date = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Time when the auth request was created";
|
||||
}
|
||||
];
|
||||
|
||||
string client_id = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "OIDC client ID of the application that created the auth request";
|
||||
}
|
||||
];
|
||||
|
||||
repeated string scope = 4 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Requested scopes by the application, which the user must consent to.";
|
||||
}
|
||||
];
|
||||
|
||||
string redirect_uri = 5 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Base URI that points back to the application";
|
||||
}
|
||||
];
|
||||
|
||||
repeated Prompt prompt = 6 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Prompts that must be displayed to the user";
|
||||
}
|
||||
];
|
||||
|
||||
repeated string ui_locales = 7 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "End-User's preferred languages and scripts for the user interface, represented as a list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value [fr-CA, fr, en] represents a preference for French as spoken in Canada, then French (without a region designation), followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested locales are not supported.";
|
||||
}
|
||||
];
|
||||
|
||||
optional string login_hint = 8 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Login hint can be set by the application with a user identifier such as an email or phone number.";
|
||||
}
|
||||
];
|
||||
|
||||
optional google.protobuf.Duration max_age = 9 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Specifies the allowable elapsed time in seconds since the last time the End-User was actively authenticated. If the elapsed time is greater than this value, or the field is present with 0 duration, the user must be re-authenticated.";
|
||||
}
|
||||
];
|
||||
|
||||
optional string hint_user_id = 10 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "User ID taken from a ID Token Hint if it was present and valid.";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
enum Prompt {
|
||||
PROMPT_UNSPECIFIED = 0;
|
||||
PROMPT_NONE = 1;
|
||||
PROMPT_LOGIN = 2;
|
||||
PROMPT_CONSENT = 3;
|
||||
PROMPT_SELECT_ACCOUNT = 4;
|
||||
PROMPT_CREATE = 5;
|
||||
}
|
||||
|
||||
message AuthorizationError {
|
||||
ErrorReason error = 1;
|
||||
optional string error_description = 2;
|
||||
optional string error_uri = 3;
|
||||
}
|
||||
|
||||
enum ErrorReason {
|
||||
ERROR_REASON_UNSPECIFIED = 0;
|
||||
|
||||
// Error states from https://datatracker.ietf.org/doc/html/rfc6749#section-4.2.2.1
|
||||
ERROR_REASON_INVALID_REQUEST = 1;
|
||||
ERROR_REASON_UNAUTHORIZED_CLIENT = 2;
|
||||
ERROR_REASON_ACCESS_DENIED = 3;
|
||||
ERROR_REASON_UNSUPPORTED_RESPONSE_TYPE = 4;
|
||||
ERROR_REASON_INVALID_SCOPE = 5;
|
||||
ERROR_REASON_SERVER_ERROR = 6;
|
||||
ERROR_REASON_TEMPORARY_UNAVAILABLE = 7;
|
||||
|
||||
// Error states from https://openid.net/specs/openid-connect-core-1_0.html#AuthError
|
||||
ERROR_REASON_INTERACTION_REQUIRED = 8;
|
||||
ERROR_REASON_LOGIN_REQUIRED = 9;
|
||||
ERROR_REASON_ACCOUNT_SELECTION_REQUIRED = 10;
|
||||
ERROR_REASON_CONSENT_REQUIRED = 11;
|
||||
ERROR_REASON_INVALID_REQUEST_URI = 12;
|
||||
ERROR_REASON_INVALID_REQUEST_OBJECT = 13;
|
||||
ERROR_REASON_REQUEST_NOT_SUPPORTED = 14;
|
||||
ERROR_REASON_REQUEST_URI_NOT_SUPPORTED = 15;
|
||||
ERROR_REASON_REGISTRATION_NOT_SUPPORTED = 16;
|
||||
}
|
190
proto/zitadel/oidc/v2alpha/oidc_service.proto
Normal file
190
proto/zitadel/oidc/v2alpha/oidc_service.proto
Normal file
@@ -0,0 +1,190 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package zitadel.oidc.v2alpha;
|
||||
|
||||
import "zitadel/object/v2alpha/object.proto";
|
||||
import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
||||
import "zitadel/oidc/v2alpha/authorization.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "google/api/field_behavior.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "validate/validate.proto";
|
||||
|
||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/oidc/v2alpha;oidc";
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
|
||||
info: {
|
||||
title: "OIDC Service";
|
||||
version: "2.0-alpha";
|
||||
description: "Get OIDC Auth Request details and create callback URLs. This project is in alpha state. It can AND will continue breaking until the services provide the same functionality as the current login.";
|
||||
contact:{
|
||||
name: "ZITADEL"
|
||||
url: "https://zitadel.com"
|
||||
email: "hi@zitadel.com"
|
||||
}
|
||||
license: {
|
||||
name: "Apache 2.0",
|
||||
url: "https://github.com/zitadel/zitadel/blob/main/LICENSE";
|
||||
};
|
||||
};
|
||||
schemes: HTTPS;
|
||||
schemes: HTTP;
|
||||
|
||||
consumes: "application/json";
|
||||
consumes: "application/grpc";
|
||||
|
||||
produces: "application/json";
|
||||
produces: "application/grpc";
|
||||
|
||||
consumes: "application/grpc-web+proto";
|
||||
produces: "application/grpc-web+proto";
|
||||
|
||||
host: "$ZITADEL_DOMAIN";
|
||||
base_path: "/";
|
||||
|
||||
external_docs: {
|
||||
description: "Detailed information about ZITADEL",
|
||||
url: "https://zitadel.com/docs"
|
||||
}
|
||||
|
||||
responses: {
|
||||
key: "403";
|
||||
value: {
|
||||
description: "Returned when the user does not have permission to access the resource.";
|
||||
schema: {
|
||||
json_schema: {
|
||||
ref: "#/definitions/rpcStatus";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
responses: {
|
||||
key: "404";
|
||||
value: {
|
||||
description: "Returned when the resource does not exist.";
|
||||
schema: {
|
||||
json_schema: {
|
||||
ref: "#/definitions/rpcStatus";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
service OIDCService {
|
||||
rpc GetAuthRequest (GetAuthRequestRequest) returns (GetAuthRequestResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v2alpha/oidc/auth_requests/{auth_request_id}"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "Get OIDC Auth Request details";
|
||||
description: "Get OIDC Auth Request details by ID, obtained from the redirect URL. Returns details that are parsed from the application's Auth Request."
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
rpc CreateCallback (CreateCallbackRequest) returns (CreateCallbackResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v2alpha/oidc/auth_requests/{auth_request_id}"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||
auth_option: {
|
||||
permission: "authenticated"
|
||||
}
|
||||
};
|
||||
|
||||
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||
summary: "Finalize an Auth Request and get the callback URL.";
|
||||
description: "Finalize an Auth Request and get the callback URL for success or failure. The user must be redirected to the URL in order to inform the application about the success or failure. On success, the URL contains details for the application to obtain the tokens. This method can only be called once for an Auth request."
|
||||
responses: {
|
||||
key: "200"
|
||||
value: {
|
||||
description: "OK";
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
message GetAuthRequestRequest {
|
||||
string auth_request_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;
|
||||
description: "ID of the Auth Request, as obtained from the redirect URL.";
|
||||
example: "\"163840776835432705\"";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message GetAuthRequestResponse {
|
||||
AuthRequest auth_request = 1;
|
||||
}
|
||||
|
||||
message CreateCallbackRequest {
|
||||
string auth_request_id = 1 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Set this field when the authorization flow failed. It creates a callback URL to the application, with the error details set.";
|
||||
ref: "https://openid.net/specs/openid-connect-core-1_0.html#AuthError";
|
||||
}
|
||||
];
|
||||
|
||||
oneof callback_kind {
|
||||
option (validate.required) = true;
|
||||
Session session = 2;
|
||||
AuthorizationError error = 3 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Set this field when the authorization flow failed. It creates a callback URL to the application, with the error details set.";
|
||||
ref: "https://openid.net/specs/openid-connect-core-1_0.html#AuthError";
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
message Session {
|
||||
string session_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;
|
||||
description: "ID of the session, used to login the user. Connects the session to the Auth Request.";
|
||||
example: "\"163840776835432705\"";
|
||||
}
|
||||
];
|
||||
|
||||
string session_token = 2 [
|
||||
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
min_length: 1;
|
||||
max_length: 200;
|
||||
description: "Token to verify the session is valid";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
message CreateCallbackResponse {
|
||||
zitadel.object.v2alpha.Details details = 1;
|
||||
string callback_url = 2 [
|
||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||
description: "Callback URL where the user should be redirected, using a \"302 FOUND\" status. Contains details for the application to obtain the tokens on success, or error details on failure. Note that this field must be treated as credentials, as the contained code can be used to obtain tokens on behalve of the user.";
|
||||
example: "\"https://client.example.org/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj\""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
Reference in New Issue
Block a user