Registering an application with any scope other than read fails, and read write follow takes only read and discards the rest, when showing the user what permissions the app requests. So an app can request to read write follow and the instance will only show that the app wants to read your data.
All you need to reproduce is to call this curl request, and then fill in the client_id parameter in the second url and open it in the browser.
curl --form client_name=scopeissue --form redirect_uris=urn:ietf:wg:oauth:2.0:oob --form scopes=follow https://mastodon.social/api/v1/apps
open "https://mastodon.social/oauth/authorize?client_id=CLIENT_ID&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code"
master (If you're a user, don't worry about this).I'm pretty sure this doesn't happen in every release since I have apps that show other permissions?

which version are you testing this on?
@wxcafe On the "Authorised Apps" screen it shows the correct data. However you can't currently sign up an app that doesn't read, and when you're on the Authorise or Deny screen for the app it will only say that it will "read your account's data".
Which version is 'currently'? Thanks for the clarification
@wxcafe The version currently running on https://mastodon.social
I think this is due to curl submitting the request parameters as multipart/form-data when --form is used, whereas OAuth 2.0 asks for application/x-www-form-urlencoded. You can append -v to your curl call to see the content type. This syntax works for me:
curl -X POST -d "client_name=scopeissue&redirect_uris=urn:ietf:wg:oauth:2.0:oob&scopes=read write" http://localhost:3000/api/v1/apps
@patf I think you misread. As I mentioned previously having read as the first value will work(But will cause the authorise page to say you're only requesting to read), when you remove read or switch order to scopes=write read it won't work.
The following curl call:
curl -X POST -d "client_name=foobar&redirect_uris=urn:ietf:wg:oauth:2.0:oob&scopes=follow write" http://localhost:3000/api/v1/apps
Generated this application in the database:
[1] pry(main)> Doorkeeper::Application.last
Doorkeeper::Application Load (0.5ms) SELECT "oauth_applications".* FROM "oauth_applications" ORDER BY "oauth_applications"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<Doorkeeper::Application:0x007f7fa4b597f0
id: 7,
name: "foobar",
uid: "397583a17dc71d3b7db0ff5da8867eac359c3c8ee16a42f342f363065f9644fb",
secret: "1e5a4cbd2ba2ec0fe0924c7086894952520aa92ace21e7fda1c2b70612734e34",
redirect_uri: "urn:ietf:wg:oauth:2.0:oob",
scopes: "follow write",
created_at: Sat, 22 Apr 2017 16:22:45 UTC +00:00,
updated_at: Sat, 22 Apr 2017 16:22:45 UTC +00:00,
superapp: false,
website: nil>
Following that up with this:
open "http://localhost:3000/oauth/authorize?client_id=397583a17dc71d3b7db0ff5da8867eac359c3c8ee16a42f342f363065f9644fb&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=follow write"
I get the following prompt:

Note that I added the scope parameter for the authorize endpoint as well. This is mentioned in the documentation:
Multiple scopes can be requested during the authorization phase with the scope query param (space-separate the scopes). If you do not specify a scope in your authorization request, the resulting access token will default to read access.

Trying any write or follow action after that still gives me "This action is outside the authorized scopes".
Are you using the code returned by the authorize endpoint as your OAuth bearer token by any chance?
The returned code is not a bearer token, but rather an authorization code which has to be exchanged for a token by hitting the /oauth/token endpoint. The full flow is decribed in Section 4.1 of RFC 6749. I can recommend Google's OAuth playground for testing purposes. I was able to obtain a token using "scope=follow write" for the app/authorize call and then submit a new status using that token. The UI correctly shows the app scope as "follow, block, unblock and unfollow accounts, post on your behalf".
change scopes to the oauth standard compliant scope (singular) instead.
URL param:
&scope=write+read+follow
I have noticed that authorized apps show all scopes in the UI even when not all scopes have been properly associated with the token.
I also have an issue when requesting write authorizations for an app on my instance (V1.3.3). Here are the requests:
POST https://url.com/api/v1/apps?redirect_uris=urn:ietf:wg:oauth:2.0:oob&client_name=CLIENT_NAME&scope=read+write
POST https://url.com/oauth token?client_id=CLIENT_ID&client_secret=CLIENT_SECRET&grant_type=password&username=USERNAME&password=PASSWORD
Answer :
'{"access_token":"TOKEN","token_type":"bearer","scope":"read","created_at":1494874942}'
Note that the 'scope' in the answer is only 'read' while I request read+write.
In the webUI, the authorizations description is correct : read your account's data,
post on your behalf
But... I cannot post a toot:
POST 聽https://url.com/api/v1/statuses?status=@user+TEXT&visibility=direct',聽headers={'Authorization':聽'Bearer聽TOKEN'})
returns
{"error":"This聽action聽is聽outside聽the聽authorized聽scopes"}'
@JF002: You're missing the scope param in the /oauth/token request. They're separate from the app you created and default to read if no parameter is supplied.
@patf Oh? Ok, I'll have a look and give an update as soon as possible! Thanks for the information!
Can this be closed?
for the record, as mentioned by @patf,
@Aaronepower and @JF002 request failed for 2 reasons:
scope is supplied during authorization (oauth/authorize endpoint) the server assumes readscope used during authorization, explicit or implicit, does not match, it must fail.reference: Oauth Standard (RFC6749)
If the client omits the scope parameter when requesting
authorization, the authorization server MUST either process the
request using a pre-defined default value or fail the request
indicating an invalid scope. The authorization server SHOULD
document its scope requirements and default value (if defined).
Most helpful comment
Trying any write or follow action after that still gives me "This action is outside the authorized scopes".