Skip to content
Draft
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
15 changes: 15 additions & 0 deletions idp/initial_schema.dbdiagram
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"version": "3.0.0",
"darkMode": false,
"gridEnabling": false,
"currentViewName": null,
"defaultView": {
"detailLevel": "All",
"relationshipMode": "All",
"tablePositions": [],
"tableGroupCollapseStates": [],
"stickyNoteLayouts": [],
"referencePaths": []
},
"views": {}
}
3 changes: 0 additions & 3 deletions idp/initial_schema.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -1021,9 +1021,6 @@ Table account_dynamic_registration_configs as ADRC {
software_statement_verification_methods "software_statement_verification_method[]" [not null]
require_verified_domains_credentials_type "account_credentials_type[]" [not null]

require_initial_access_token_credential_types "account_credentials_type[]" [not null]
initial_access_token_generation_methods "initial_access_token_generation_method[]" [not null]

created_at timestamptz [not null, default: `now()`]
updated_at timestamptz [not null, default: `now()`]

Expand Down
8 changes: 4 additions & 4 deletions idp/internal/controllers/account_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ func (c *Controllers) ListAccountCredentials(ctx fiber.Ctx) error {
}

queryParams := params.PaginationQueryParams{
Offset: fiber.Query[int](ctx, "offset", 0),
Limit: fiber.Query[int](ctx, "limit", 20),
Offset: fiber.Query(ctx, "offset", 0),
Limit: fiber.Query(ctx, "limit", 20),
}
if err := c.validate.StructCtx(ctx.Context(), &queryParams); err != nil {
return validateQueryParamsErrorResponse(logger, ctx, err)
Expand Down Expand Up @@ -243,8 +243,8 @@ func (c *Controllers) ListAccountCredentialsSecrets(ctx fiber.Ctx) error {
}

queryParams := params.PaginationQueryParams{
Offset: fiber.Query[int](ctx, "offset", 0),
Limit: fiber.Query[int](ctx, "limit", 20),
Offset: fiber.Query(ctx, "offset", 0),
Limit: fiber.Query(ctx, "limit", 20),
}
if err := c.validate.StructCtx(ctx.Context(), queryParams); err != nil {
return validateQueryParamsErrorResponse(logger, ctx, err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@ func (c *Controllers) UpsertAccountDynamicRegistrationConfig(ctx fiber.Ctx) erro
dto, created, serviceErr := c.services.SaveAccountDynamicRegistrationConfig(
ctx.Context(),
services.SaveAccountDynamicRegistrationConfigOptions{
RequestID: requestID,
AccountPublicID: accountClaims.AccountID,
AccountVersion: accountClaims.AccountVersion,
AccountCredentialsTypes: body.AccountCredentialsTypes,
RequireSoftwareStatementCredentialTypes: body.RequireSoftwareStatementCredentialTypes,
SoftwareStatementVerificationMethods: body.SoftwareStatementVerificationMethods,
RequireInitialAccessTokenCredentialTypes: body.RequireInitialAccessTokenCredentialTypes,
InitialAccessTokenGenerationMethods: body.InitialAccessTokenGenerationMethods,
RequestID: requestID,
AccountPublicID: accountClaims.AccountID,
AccountVersion: accountClaims.AccountVersion,
AccountCredentialsTypes: body.AccountCredentialsTypes,
RequireSoftwareStatementCredentialTypes: body.RequireSoftwareStatementCredentialTypes,
SoftwareStatementVerificationMethods: body.SoftwareStatementVerificationMethods,
},
)
if serviceErr != nil {
Expand Down
55 changes: 55 additions & 0 deletions idp/internal/controllers/app_dynamic_registration_iat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright (c) 2026 Afonso Barracha
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

package controllers

import (
"github.com/gofiber/fiber/v3"

"github.com/tugascript/devlogs/idp/internal/controllers/bodies"
"github.com/tugascript/devlogs/idp/internal/services"
)

const (
appDynamicRegistrationIATLocation string = "app_dynamic_registration_iat"
)

func (c *Controllers) AppDynamicRegistrationIATSign(ctx fiber.Ctx) error {
requestID := getRequestID(ctx)
logger := c.buildLogger(requestID, appDynamicRegistrationIATLocation, "AppDynamicRegistrationIATSign")
logRequest(logger, ctx)

accountClaims, serviceErr := getAccountClaims(ctx)
if serviceErr != nil {
return serviceErrorResponse(logger, ctx, serviceErr)
}

body := new(bodies.CreateDynamicRegistrationDomainBody)
if err := ctx.Bind().Body(body); err != nil {
return parseRequestErrorResponse(logger, ctx, err)
}
if err := c.validate.StructCtx(ctx.Context(), body); err != nil {
return validateBodyErrorResponse(logger, ctx, err)
}

authDTO, serviceErr := c.services.CreateAppCredentialsRegistrationIAT(
ctx.Context(),
services.CreateAppCredentialsRegistrationIATOptions{
RequestID: requestID,
AccountPublicID: accountClaims.AccountID,
AccountVersion: accountClaims.AccountVersion,
Domain: body.Domain,
BackendDomain: c.backendDomain,
},
)
if serviceErr != nil {
return serviceErrorResponse(logger, ctx, serviceErr)
}

ctx.Set(fiber.HeaderCacheControl, cacheControlNoStore)
logResponse(logger, ctx, fiber.StatusCreated)
return ctx.Status(fiber.StatusCreated).JSON(&authDTO)
}
8 changes: 4 additions & 4 deletions idp/internal/controllers/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,8 +456,8 @@ func (c *Controllers) ListApps(ctx fiber.Ctx) error {
}

queryParams := params.GetAppsQueryParams{
Limit: fiber.Query[int](ctx, "limit", 10),
Offset: fiber.Query[int](ctx, "offset", 0),
Limit: fiber.Query(ctx, "limit", 10),
Offset: fiber.Query(ctx, "offset", 0),
Name: ctx.Query("name"),
Order: ctx.Query("order", "date"),
Type: ctx.Query("type"),
Expand Down Expand Up @@ -1035,8 +1035,8 @@ func (c *Controllers) ListAppSecrets(ctx fiber.Ctx) error {
}

queryParams := params.PaginationQueryParams{
Offset: fiber.Query[int](ctx, "offset", 0),
Limit: fiber.Query[int](ctx, "limit", 20),
Offset: fiber.Query(ctx, "offset", 0),
Limit: fiber.Query(ctx, "limit", 20),
}
if err := c.validate.StructCtx(ctx.Context(), queryParams); err != nil {
return validateQueryParamsErrorResponse(logger, ctx, err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
package bodies

type AccountDynamicRegistrationConfigBody struct {
AccountCredentialsTypes []string `json:"account_credentials_types" validate:"required,unique,min=1,max=3,oneof=native service mcp"`
WhitelistedDomains []string `json:"whitelisted_domains" validate:"omitempty,unique,min=1,max=250,dive,fqdn"`
RequireSoftwareStatementCredentialTypes []string `json:"require_software_statement_credential_types" validate:"omitempty,unique,min=1,max=3,oneof=native service mcp"`
SoftwareStatementVerificationMethods []string `json:"software_statement_verification_methods" validate:"omitempty,unique,min=1,max=2,oneof=manual jwks_uri"`
RequireInitialAccessTokenCredentialTypes []string `json:"require_initial_access_token_credential_types" validate:"omitempty,unique,min=1,max=3,oneof=native service mcp"`
InitialAccessTokenGenerationMethods []string `json:"initial_access_token_generation_methods" validate:"omitempty,unique,min=1,max=2,oneof=manual authorization_code"`
AccountCredentialsTypes []string `json:"account_credentials_types" validate:"required,unique,min=1,max=3,oneof=native service mcp"`
WhitelistedDomains []string `json:"whitelisted_domains" validate:"omitempty,unique,min=1,max=250,dive,fqdn"`
RequireSoftwareStatementCredentialTypes []string `json:"require_software_statement_credential_types" validate:"omitempty,unique,min=1,max=3,oneof=native service mcp"`
SoftwareStatementVerificationMethods []string `json:"software_statement_verification_methods" validate:"omitempty,unique,min=1,max=2,oneof=manual jwks_uri"`
}
72 changes: 37 additions & 35 deletions idp/internal/controllers/bodies/oauth_dynamic_registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,44 @@

package bodies

import "github.com/tugascript/devlogs/idp/internal/utils"

type OAuthDynamicClientRegistrationBody struct {
RedirectURIs []string `json:"redirect_uris,omitempty" validate:"omitempty,min=1,dive,uri"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty" validate:"omitempty,oneof=none client_secret_basic client_secret_post client_secret_jwt private_key_jwt"`
ResponseTypes []string `json:"response_types,omitempty" validate:"omitempty,dive,oneof=code 'code id_token'"`
GrantTypes []string `json:"grant_types,omitempty" validate:"omitempty,min=1,dive,oneof=authorization_code refresh_token client_credentials urn:ietf:params:oauth:grant-type:jwt-bearer"`
ApplicationType string `json:"application_type" validate:"required,oneof=native service mcp web spa backend device"`
ClientName string `json:"client_name" validate:"required,min=1,max=255"`
ClientURI string `json:"client_uri" validate:"required,url"`
LogoURI string `json:"logo_uri,omitempty" validate:"omitempty,url"`
Scope string `json:"scope" validate:"required,multiple_scope"`
Contacts []string `json:"contacts,omitempty" validate:"omitempty,unique,dive,email"`
TOSURI string `json:"tos_uri,omitempty" validate:"omitempty,url"`
PolicyURI string `json:"policy_uri,omitempty" validate:"omitempty,url"`
JWKsURI string `json:"jwks_uri,omitempty" validate:"omitempty,url"`
JWKs []string `json:"jwks,omitempty" validate:"omitempty,json"`
SoftwareID string `json:"software_id,omitempty" validate:"omitempty,max=512"`
SoftwareVersion string `json:"software_version,omitempty" validate:"omitempty,max=512"`
SubjectType string `json:"subject_type,omitempty" validate:"omitempty,oneof=public pairwise"`
SectorIdentifierURI string `json:"sector_identifier_uri,omitempty" validate:"omitempty,url"`
DefaultMaxAge int64 `json:"default_max_age,omitempty" validate:"omitempty,min=0"`
RequireAuthTime bool `json:"require_auth_time,omitempty" validate:"omitempty,bool"`
DefaultACRValues []string `json:"default_acr_values,omitempty" validate:"omitempty,unique,dive,max=100"`
InitiateLoginURI string `json:"initiate_login_uri,omitempty" validate:"omitempty,url"`
RequestURIs []string `json:"request_uris,omitempty" validate:"omitempty,unique,dive,url"`
IDTokenSignedResponseAlg string `json:"id_token_signed_response_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
IDTokenEncryptedResponseAlg string `json:"id_token_encrypted_response_alg,omitempty" validate:"omitempty,oneof=RSA-OAEP-256 ECDH-ES ECDH-ES+A256KW"`
IDTokenEncryptedResponseEnc string `json:"id_token_encrypted_response_enc,omitempty" validate:"omitempty,oneof=A128CBC-HS256 A192CBC-HS384 A256CBC-HS512 A128GCM A192GCM A256GCM"`
UserInfoSignedResponseAlg string `json:"userinfo_signed_response_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
UserInfoEncryptedResponseAlg string `json:"userinfo_encrypted_response_alg,omitempty" validate:"omitempty,oneof=RSA-OAEP-256 ECDH-ES ECDH-ES+A256KW"`
UserInfoEncryptedResponseEnc string `json:"userinfo_encrypted_response_enc,omitempty" validate:"omitempty,oneof=A128CBC-HS256 A192CBC-HS384 A256CBC-HS512 A128GCM A192GCM A256GCM"`
RequestObjectSigningAlg string `json:"request_object_signing_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
RequestObjectEncryptionAlg string `json:"request_object_encryption_alg,omitempty" validate:"omitempty,oneof=RSA-OAEP-256 ECDH-ES ECDH-ES+A256KW"`
RequestObjectEncryptionEnc string `json:"request_object_encryption_enc,omitempty" validate:"omitempty,oneof=A128CBC-HS256 A192CBC-HS384 A256CBC-HS512 A128GCM A192GCM A256GCM"`
TokenEndpointAuthSigningAlg string `json:"token_endpoint_auth_signing_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
AccessTokenSigningAlg string `json:"access_token_signing_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
SoftwareStatement string `json:"software_statement,omitempty" validate:"omitempty,jwt"`
RedirectURIs []string `json:"redirect_uris,omitempty" validate:"omitempty,min=1,dive,uri"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty" validate:"omitempty,oneof=none client_secret_basic client_secret_post client_secret_jwt private_key_jwt"`
ResponseTypes []string `json:"response_types,omitempty" validate:"omitempty,dive,oneof=code 'code id_token'"`
GrantTypes []string `json:"grant_types,omitempty" validate:"omitempty,min=1,dive,oneof=authorization_code refresh_token client_credentials urn:ietf:params:oauth:grant-type:jwt-bearer"`
ApplicationType string `json:"application_type,omitempty" validate:"omitempty,oneof=native service mcp web spa backend device"`
ClientName string `json:"client_name,omitempty" validate:"omitempty,min=1,max=255"`
ClientURI string `json:"client_uri,omitempty" validate:"omitempty,url"`
LogoURI string `json:"logo_uri,omitempty" validate:"omitempty,url"`
Scope string `json:"scope,omitempty" validate:"omitempty,multiple_scope"`
Contacts []string `json:"contacts,omitempty" validate:"omitempty,unique,dive,email"`
TOSURI string `json:"tos_uri,omitempty" validate:"omitempty,url"`
PolicyURI string `json:"policy_uri,omitempty" validate:"omitempty,url"`
JWKsURI string `json:"jwks_uri,omitempty" validate:"omitempty,url"`
JWKs *utils.JWKSet `json:"jwks,omitempty" validate:"omitempty"`
SoftwareID string `json:"software_id,omitempty" validate:"omitempty,max=512"`
SoftwareVersion string `json:"software_version,omitempty" validate:"omitempty,max=512"`
SubjectType string `json:"subject_type,omitempty" validate:"omitempty,oneof=public pairwise"`
SectorIdentifierURI string `json:"sector_identifier_uri,omitempty" validate:"omitempty,url"`
DefaultMaxAge int64 `json:"default_max_age,omitempty" validate:"omitempty,min=0"`
RequireAuthTime bool `json:"require_auth_time,omitempty"`
DefaultACRValues []string `json:"default_acr_values,omitempty" validate:"omitempty,unique,dive,max=100"`
InitiateLoginURI string `json:"initiate_login_uri,omitempty" validate:"omitempty,url"`
RequestURIs []string `json:"request_uris,omitempty" validate:"omitempty,unique,dive,url"`
IDTokenSignedResponseAlg string `json:"id_token_signed_response_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
IDTokenEncryptedResponseAlg string `json:"id_token_encrypted_response_alg,omitempty" validate:"omitempty,oneof=RSA-OAEP-256 ECDH-ES ECDH-ES+A256KW"`
IDTokenEncryptedResponseEnc string `json:"id_token_encrypted_response_enc,omitempty" validate:"omitempty,oneof=A128CBC-HS256 A192CBC-HS384 A256CBC-HS512 A128GCM A192GCM A256GCM"`
UserInfoSignedResponseAlg string `json:"userinfo_signed_response_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
UserInfoEncryptedResponseAlg string `json:"userinfo_encrypted_response_alg,omitempty" validate:"omitempty,oneof=RSA-OAEP-256 ECDH-ES ECDH-ES+A256KW"`
UserInfoEncryptedResponseEnc string `json:"userinfo_encrypted_response_enc,omitempty" validate:"omitempty,oneof=A128CBC-HS256 A192CBC-HS384 A256CBC-HS512 A128GCM A192GCM A256GCM"`
RequestObjectSigningAlg string `json:"request_object_signing_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
RequestObjectEncryptionAlg string `json:"request_object_encryption_alg,omitempty" validate:"omitempty,oneof=RSA-OAEP-256 ECDH-ES ECDH-ES+A256KW"`
RequestObjectEncryptionEnc string `json:"request_object_encryption_enc,omitempty" validate:"omitempty,oneof=A128CBC-HS256 A192CBC-HS384 A256CBC-HS512 A128GCM A192GCM A256GCM"`
TokenEndpointAuthSigningAlg string `json:"token_endpoint_auth_signing_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
AccessTokenSigningAlg string `json:"access_token_signing_alg,omitempty" validate:"omitempty,oneof=RS256 ES256 EdDSA"`
SoftwareStatement string `json:"software_statement,omitempty" validate:"omitempty,jwt"`
}

type OAuthDynamicRegistrationIATAuthHiddenFieldsBody struct {
Expand Down
4 changes: 2 additions & 2 deletions idp/internal/controllers/dynamic_registration_domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ func (c *Controllers) ListAccountCredentialsRegistrationDomains(ctx fiber.Ctx) e
}

queryParams := params.DynamicRegistrationDomainQueryParams{
Limit: fiber.Query[int](ctx, "limit", 10),
Offset: fiber.Query[int](ctx, "offset", 0),
Limit: fiber.Query(ctx, "limit", 10),
Offset: fiber.Query(ctx, "offset", 0),
Order: ctx.Query("order", "date"),
Search: ctx.Query("search"),
}
Expand Down
2 changes: 2 additions & 0 deletions idp/internal/controllers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ func dynamicRegistrationServiceError(
serviceErr *exceptions.ServiceError,
) error {
switch serviceErr.Code {
case exceptions.OAuthErrorInvalidRedirectURI:
return oauthErrorResponse(logger, ctx, exceptions.OAuthErrorInvalidRedirectURI)
case exceptions.CodeUnauthorized, exceptions.CodeForbidden:
return oauthErrorResponse(logger, ctx, exceptions.OAuthErrorUnauthorizedClient)
case exceptions.CodeNotFound, exceptions.CodeValidation:
Expand Down
Loading