GetClientConfiguration returns an http.HandlerFunc that handles GET /oauth2/clients/{client_id}
(db database.Store)
| 170 | |
| 171 | // GetClientConfiguration returns an http.HandlerFunc that handles GET /oauth2/clients/{client_id} |
| 172 | func GetClientConfiguration(db database.Store) http.HandlerFunc { |
| 173 | return func(rw http.ResponseWriter, r *http.Request) { |
| 174 | ctx := r.Context() |
| 175 | |
| 176 | // Extract client ID from URL path |
| 177 | clientIDStr := chi.URLParam(r, "client_id") |
| 178 | clientID, err := uuid.Parse(clientIDStr) |
| 179 | if err != nil { |
| 180 | writeOAuth2RegistrationError(ctx, rw, http.StatusBadRequest, |
| 181 | "invalid_client_metadata", "Invalid client ID format") |
| 182 | return |
| 183 | } |
| 184 | |
| 185 | // Get app by client ID |
| 186 | //nolint:gocritic // OAuth2 system context — RFC 7592 client configuration endpoint |
| 187 | app, err := db.GetOAuth2ProviderAppByClientID(dbauthz.AsSystemOAuth2(ctx), clientID) |
| 188 | if err != nil { |
| 189 | if xerrors.Is(err, sql.ErrNoRows) { |
| 190 | writeOAuth2RegistrationError(ctx, rw, http.StatusUnauthorized, |
| 191 | "invalid_token", "Client not found") |
| 192 | } else { |
| 193 | writeOAuth2RegistrationError(ctx, rw, http.StatusInternalServerError, |
| 194 | "server_error", "Failed to retrieve client") |
| 195 | } |
| 196 | return |
| 197 | } |
| 198 | |
| 199 | // Check if client was dynamically registered |
| 200 | if !app.DynamicallyRegistered.Bool { |
| 201 | writeOAuth2RegistrationError(ctx, rw, http.StatusUnauthorized, |
| 202 | "invalid_token", "Client was not dynamically registered") |
| 203 | return |
| 204 | } |
| 205 | |
| 206 | // Return client configuration (without client_secret for security) |
| 207 | response := codersdk.OAuth2ClientConfiguration{ |
| 208 | ClientID: app.ID.String(), |
| 209 | ClientIDIssuedAt: app.ClientIDIssuedAt.Time.Unix(), |
| 210 | ClientSecretExpiresAt: 0, // No expiration for now |
| 211 | RedirectURIs: app.RedirectUris, |
| 212 | ClientName: app.Name, |
| 213 | ClientURI: app.ClientUri.String, |
| 214 | LogoURI: app.LogoUri.String, |
| 215 | TOSURI: app.TosUri.String, |
| 216 | PolicyURI: app.PolicyUri.String, |
| 217 | JWKSURI: app.JwksUri.String, |
| 218 | JWKS: app.Jwks.RawMessage, |
| 219 | SoftwareID: app.SoftwareID.String, |
| 220 | SoftwareVersion: app.SoftwareVersion.String, |
| 221 | GrantTypes: slice.StringEnums[codersdk.OAuth2ProviderGrantType](app.GrantTypes), |
| 222 | ResponseTypes: slice.StringEnums[codersdk.OAuth2ProviderResponseType](app.ResponseTypes), |
| 223 | TokenEndpointAuthMethod: codersdk.OAuth2TokenEndpointAuthMethod(app.TokenEndpointAuthMethod.String), |
| 224 | Scope: app.Scope.String, |
| 225 | Contacts: app.Contacts, |
| 226 | RegistrationAccessToken: "", // RFC 7592: Not returned in GET responses for security |
| 227 | RegistrationClientURI: app.RegistrationClientUri.String, |
| 228 | } |
| 229 |
no test coverage detected