Skip to content

feat: add edit functionality for OAuth metadata fields#1336

Draft
simplesagar wants to merge 3 commits intomainfrom
oauth_metadata_update-
Draft

feat: add edit functionality for OAuth metadata fields#1336
simplesagar wants to merge 3 commits intomainfrom
oauth_metadata_update-

Conversation

@simplesagar
Copy link
Member

@simplesagar simplesagar commented Jan 22, 2026

Summary

  • Add edit functionality for OAuth metadata fields so users don't have to delete and re-add configuration
  • Add updateExternalOAuthServer API endpoint to update external OAuth server metadata
  • Add updateOAuthProxyServer API endpoint to update OAuth proxy configuration
  • Add edit button and inline editing in the OAuth Details modal
  • Add server-side validation to reject empty authorization_endpoint and token_endpoint for custom OAuth proxy providers

Test plan

  • Test editing External OAuth Server metadata JSON
  • Test editing OAuth Proxy Server fields (authorization endpoint, token endpoint, scopes, auth method, environment)
  • Verify Gram OAuth type cannot be edited (intentional restriction)
  • Verify validation for required endpoints in external OAuth metadata
  • Verify server rejects empty authorization_endpoint or token_endpoint for custom providers

Closes AGE-1215

🤖 Generated with Claude Code

Add ability to update OAuth configuration without deleting and re-adding:
- Add updateExternalOAuthServer and updateOAuthProxyServer API endpoints
- Add edit button and inline editing UI in OAuthDetailsModal
- Support editing authorization endpoint, token endpoint, scopes, auth method, and environment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@simplesagar simplesagar added enhancement New feature or request go Pull requests that update go code labels Jan 22, 2026
@linear
Copy link

linear bot commented Jan 22, 2026

@changeset-bot
Copy link

changeset-bot bot commented Jan 22, 2026

🦋 Changeset detected

Latest commit: 31b8a18

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
dashboard Patch
@gram/client Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Jan 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
gram Ready Ready Preview, Comment Jan 23, 2026 0:47am
gram-docs-redirect Ready Ready Preview, Comment Jan 23, 2026 0:47am

Request Review

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Open in Devin Review

Comment on lines +8 to +27
export type UpdateExternalOAuthServerRequestBody = {
/**
* The updated metadata for the external OAuth server
*/
metadata?: any | undefined;
};

/** @internal */
export type UpdateExternalOAuthServerRequestBody$Outbound = {
metadata?: any | undefined;
};

/** @internal */
export const UpdateExternalOAuthServerRequestBody$outboundSchema: z.ZodType<
UpdateExternalOAuthServerRequestBody$Outbound,
z.ZodTypeDef,
UpdateExternalOAuthServerRequestBody
> = z.object({
metadata: z.any().optional(),
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 UpdateExternalOAuthServerRequestBody marks metadata optional despite API requiring it

The OpenAPI schema for UpdateExternalOAuthServerRequestBody marks metadata as required, but the generated TypeScript model makes it optional:

export type UpdateExternalOAuthServerRequestBody = {
  metadata?: any | undefined;
};

client/sdk/src/models/components/updateexternaloauthserverrequestbody.ts:8-13

This violates the API contract: SDK consumers can construct requests without metadata, which will then fail server-side validation at runtime.

Actual: SDK allows omitting metadata.
Expected: metadata should be required in the SDK type and validation schema.

Recommendation: Regenerate/fix the OpenAPI->SDK generation so metadata is required (remove .optional() and make the TS field non-optional).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@simplesagar simplesagar requested a review from qstearns January 23, 2026 00:32
…m providers

Addresses Devin review feedback: OAuth proxy update could persist empty
endpoints because the server didn't validate that authorization_endpoint
and token_endpoint are non-empty strings for custom provider types.

This adds validation that matches the AddOAuthProxyServer behavior,
rejecting requests that provide empty strings for these required fields.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@simplesagar
Copy link
Member Author

Addressed Devin Review Feedback

Issue 1 (🔴 Empty endpoints): Fixed in commit 31b8a18. Added server-side validation in UpdateOAuthProxyServer that rejects empty strings for authorization_endpoint and token_endpoint when the provider type is "custom". This matches the validation behavior in AddOAuthProxyServer.

Issue 2 (🟡 SDK metadata optional): The Goa design correctly marks metadata as required, and the server-generated validation code properly rejects requests without metadata (see ValidateUpdateExternalOAuthServerRequestBody in the generated code). The SDK showing it as optional is a Speakeasy SDK generation quirk when dealing with Any types - runtime behavior is correct since the server validates the field.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

View issues and 6 additional flags in Devin Review.

Open in Devin Review

Comment on lines +883 to +889
setJsonError(null);
updateExternalOAuthMutation.mutate({
request: {
slug: toolset.slug,
metadata: parsedMetadata,
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Dashboard calls updateExternalOAuthServer with wrong request shape (missing updateExternalOAuthServerRequestBody wrapper)

The generated SDK operation updateExternalOAuthServer expects the JSON body under updateExternalOAuthServerRequestBody (see generated operation docs/types), but the dashboard mutation sends metadata at the top-level of request.

Code:

updateExternalOAuthMutation.mutate({
  request: {
    slug: toolset.slug,
    metadata: parsedMetadata,
  },
});

client/dashboard/src/pages/mcp/MCPDetails.tsx:883-889

Actual behavior: the SDK will serialize a request body where UpdateExternalOAuthServerRequestBody is undefined (or omit it), causing client-side validation failures or a server 400/422 because the required metadata body field is missing.

Expected behavior: pass updateExternalOAuthServerRequestBody: { metadata: parsedMetadata } (and keep slug in the query).

Recommendation: Change the mutate call to:

updateExternalOAuthMutation.mutate({
  request: {
    slug: toolset.slug,
    updateExternalOAuthServerRequestBody: { metadata: parsedMetadata },
  },
});
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +897 to +906

updateOAuthProxyMutation.mutate({
request: {
slug: toolset.slug,
authorizationEndpoint: proxyAuthorizationEndpoint,
tokenEndpoint: proxyTokenEndpoint,
scopesSupported: scopesArray,
tokenEndpointAuthMethodsSupported: [proxyTokenAuthMethod],
environmentSlug: proxyEnvironmentSlug,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Dashboard calls updateOAuthProxyServer with wrong request shape (missing updateOAuthProxyServerRequestBody wrapper)

The generated SDK operation updateOAuthProxyServer expects the JSON body under updateOAuthProxyServerRequestBody, but the dashboard mutation sends OAuth proxy fields at the top-level of request.

Code:

updateOAuthProxyMutation.mutate({
  request: {
    slug: toolset.slug,
    authorizationEndpoint: proxyAuthorizationEndpoint,
    tokenEndpoint: proxyTokenEndpoint,
    scopesSupported: scopesArray,
    tokenEndpointAuthMethodsSupported: [proxyTokenAuthMethod],
    environmentSlug: proxyEnvironmentSlug,
  },
});

client/dashboard/src/pages/mcp/MCPDetails.tsx:897-906

Actual behavior: the SDK will serialize an empty/incorrect request body because UpdateOAuthProxyServerRequestBody is not provided, leading to client-side validation errors or server rejecting the request / not applying updates.

Expected behavior: wrap those fields in updateOAuthProxyServerRequestBody: { ... }.

Recommendation: Change the mutate call to:

updateOAuthProxyMutation.mutate({
  request: {
    slug: toolset.slug,
    updateOAuthProxyServerRequestBody: {
      authorizationEndpoint: proxyAuthorizationEndpoint,
      tokenEndpoint: proxyTokenEndpoint,
      scopesSupported: scopesArray,
      tokenEndpointAuthMethodsSupported: [proxyTokenAuthMethod],
      environmentSlug: proxyEnvironmentSlug,
    },
  },
});
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@simplesagar simplesagar marked this pull request as draft February 6, 2026 15:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant