Skip to content

Commit b416973

Browse files
committed
normalize the scopes so that if the user selects both read/write in the swagger ui it still works
1 parent 38d6cb9 commit b416973

1 file changed

Lines changed: 29 additions & 3 deletions

File tree

api/v1_oauth.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ type oauthRevokeBody struct {
5858
ClientID string `json:"client_id" form:"client_id"`
5959
}
6060

61+
// normalizeOAuthScope collapses space-separated OAuth scopes (e.g. "read write") to the
62+
// highest-privilege single scope. This tolerates Swagger UI sending compound scope strings.
63+
func normalizeOAuthScope(raw string) string {
64+
for _, part := range strings.Fields(raw) {
65+
if part == "write" {
66+
return "write"
67+
}
68+
}
69+
return strings.TrimSpace(raw)
70+
}
71+
6172
// normalizeClientID lowercases and ensures the 0x prefix on a client_id (developer app address).
6273
func normalizeClientID(raw string) string {
6374
id := strings.ToLower(strings.TrimSpace(raw))
@@ -77,6 +88,20 @@ type oauthTokenCacheEntry struct {
7788

7889
// --- Handlers ---
7990

91+
// v1OAuthAuthorizeRedirect handles GET /v1/oauth/authorize
92+
// Redirects the browser to the Audius app consent page, forwarding all query parameters.
93+
func (app *ApiServer) v1OAuthAuthorizeRedirect(c *fiber.Ctx) error {
94+
base := app.config.AudiusAppUrl
95+
if base == "" {
96+
base = "https://audius.co"
97+
}
98+
target := base + "/oauth/auth"
99+
if qs := string(c.Request().URI().QueryString()); qs != "" {
100+
target += "?" + qs
101+
}
102+
return c.Redirect(target, fiber.StatusFound)
103+
}
104+
80105
// v1OAuthAuthorize handles POST /v1/oauth/authorize
81106
// Called by the audius.co consent screen after the user authenticates.
82107
func (app *ApiServer) v1OAuthAuthorize(c *fiber.Ctx) error {
@@ -99,7 +124,8 @@ func (app *ApiServer) v1OAuthAuthorize(c *fiber.Ctx) error {
99124
return oauthError(c, fiber.StatusBadRequest, "invalid_request", "code_challenge_method must be S256")
100125
}
101126

102-
if body.Scope != "read" && body.Scope != "write" {
127+
scope := normalizeOAuthScope(body.Scope)
128+
if scope != "read" && scope != "write" {
103129
return oauthError(c, fiber.StatusBadRequest, "invalid_request", "scope must be 'read' or 'write'")
104130
}
105131

@@ -165,7 +191,7 @@ func (app *ApiServer) v1OAuthAuthorize(c *fiber.Ctx) error {
165191
}
166192

167193
// 4. If scope is write, check for existing approved grant
168-
if body.Scope == "write" {
194+
if scope == "write" {
169195
var grantExists bool
170196
err = app.pool.QueryRow(c.Context(), `
171197
SELECT EXISTS (
@@ -193,7 +219,7 @@ func (app *ApiServer) v1OAuthAuthorize(c *fiber.Ctx) error {
193219
_, err = app.writePool.Exec(c.Context(), `
194220
INSERT INTO oauth_authorization_codes (code, client_id, user_id, redirect_uri, code_challenge, code_challenge_method, scope)
195221
VALUES ($1, $2, $3, $4, $5, $6, $7)
196-
`, code, clientID, int32(userId), body.RedirectURI, body.CodeChallenge, body.CodeChallengeMethod, body.Scope)
222+
`, code, clientID, int32(userId), body.RedirectURI, body.CodeChallenge, body.CodeChallengeMethod, scope)
197223
if err != nil {
198224
app.logger.Error("Failed to insert auth code", zap.Error(err))
199225
return oauthError(c, fiber.StatusInternalServerError, "server_error", "Failed to create authorization code")

0 commit comments

Comments
 (0)