Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions auth/client/rs/src/api/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,58 @@ pub type ExchangeForJwtResponse = JwtResponse;

//

/// The OAuth 2.0 subject token type (RFC 8693).
/// Identifies the security token presented for exchange.
#[typeshare]
#[derive(
Debug, Clone, Serialize, Deserialize, Display, EnumString,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub enum SubjectTokenType {
/// OIDC ID Token (`urn:ietf:params:oauth:token-type:id_token`)
OidcIdToken,
/// Google ID Token (`urn:ietf:params:oauth:token-type:id_token`, Google issuer)
GoogleIdToken,
/// GitHub Access Token (`urn:ietf:params:oauth:token-type:access_token`)
GitHubAccessToken,
}

#[allow(unused)]
#[cfg(feature = "utoipa")]
#[utoipa::path(
post,
path = "/login/ExchangeProviderTokenForJwt",
description = "Exchange an OAuth provider token (OIDC ID Token, Google ID Token, or GitHub Access Token) for a Komodo JWT. Follows RFC 8693 token exchange semantics.",
request_body(content = ExchangeProviderTokenForJwt),
responses(
(status = 200, description = "Authentication JWT", body = ExchangeProviderTokenForJwtResponse),
(status = 401, description = "Unauthorized — token invalid or provider not configured", body = mogh_error::Serror),
(status = 500, description = "Request failed", body = mogh_error::Serror)
),
)]
fn exchange_provider_token_for_jwt() {}

/// Exchange an OAuth provider token for a JWT (RFC 8693 Token Exchange).
/// Response: [ExchangeProviderTokenForJwtResponse].
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Resolve)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[empty_traits(MoghAuthLoginRequest)]
#[response(ExchangeProviderTokenForJwtResponse)]
#[error(mogh_error::Error)]
pub struct ExchangeProviderTokenForJwt {
/// The type of the presented token (RFC 8693 `subject_token_type`).
pub subject_token_type: SubjectTokenType,
/// The token to exchange (RFC 8693 `subject_token`).
pub subject_token: String,
}

/// Response for [ExchangeProviderTokenForJwt].
#[typeshare]
pub type ExchangeProviderTokenForJwtResponse = JwtResponse;

//

#[allow(unused)]
#[cfg(feature = "utoipa")]
#[utoipa::path(
Expand Down
1 change: 1 addition & 0 deletions auth/client/rs/src/openapi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod auth {
// =========
auth::get_login_options,
auth::exchange_for_jwt,
auth::exchange_provider_token_for_jwt,
auth::complete_passkey_login,
auth::complete_totp_login,
// ==========
Expand Down
1 change: 1 addition & 0 deletions auth/client/ts/src/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type LoginResponses = {
SignUpLocalUser: Types.SignUpLocalUserResponse;
LoginLocalUser: Types.LoginLocalUserResponse;
ExchangeForJwt: Types.ExchangeForJwtResponse;
ExchangeProviderTokenForJwt: Types.ExchangeProviderTokenForJwtResponse;
CompleteTotpLogin: Types.CompleteTotpLoginResponse;
CompletePasskeyLogin: Types.CompletePasskeyLoginResponse;
};
Expand Down
25 changes: 25 additions & 0 deletions auth/client/ts/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ export type DeleteApiKeyV2Response = NoData;
/** Response for [ExchangeForJwt]. */
export type ExchangeForJwtResponse = JwtResponse;

/** Response for [ExchangeProviderTokenForJwt]. */
export type ExchangeProviderTokenForJwtResponse = JwtResponse;

export type JsonValue = any;

/** JSON containing either an authentication token or the required 2fa auth check. */
Expand Down Expand Up @@ -248,6 +251,27 @@ export interface DeleteApiKeyV2 {
export interface ExchangeForJwt {
}

/** The OAuth 2.0 subject token type (RFC 8693). */
export enum SubjectTokenType {
/** OIDC ID Token (`urn:ietf:params:oauth:token-type:id_token`) */
OidcIdToken = "OidcIdToken",
/** Google ID Token (`urn:ietf:params:oauth:token-type:id_token`, Google issuer) */
GoogleIdToken = "GoogleIdToken",
/** GitHub Access Token (`urn:ietf:params:oauth:token-type:access_token`) */
GitHubAccessToken = "GitHubAccessToken",
}

/**
* Exchange an OAuth provider token for a JWT (RFC 8693 Token Exchange).
* Response: [ExchangeProviderTokenForJwtResponse].
*/
export interface ExchangeProviderTokenForJwt {
/** The type of the presented token (RFC 8693 `subject_token_type`). */
subject_token_type: SubjectTokenType;
/** The token to exchange (RFC 8693 `subject_token`). */
subject_token: string;
}

/**
* Get the available options to login, eg. local and external providers.
* Response: [GetLoginOptionsResponse].
Expand Down Expand Up @@ -360,6 +384,7 @@ export enum ExternalLoginProvider {
export type LoginRequest =
| { type: "GetLoginOptions", params: GetLoginOptions }
| { type: "ExchangeForJwt", params: ExchangeForJwt }
| { type: "ExchangeProviderTokenForJwt", params: ExchangeProviderTokenForJwt }
| { type: "SignUpLocalUser", params: SignUpLocalUser }
| { type: "LoginLocalUser", params: LoginLocalUser }
| { type: "CompletePasskeyLogin", params: CompletePasskeyLogin }
Expand Down
5 changes: 4 additions & 1 deletion auth/server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ serde.workspace = true
strum.workspace = true
rand.workspace = true
axum.workspace = true
uuid.workspace = true
uuid.workspace = true

[dev-dependencies]
tokio.workspace = true
Loading