As far as I understand it, the OAuth2 flows in a security definition map to the "official OAuth2 flows" (taken from http://tools.ietf.org/html/rfc6749) as follows:
+1
After munging the OAuth2 RFC for weeks and working on a server implementation I can confirm that @olensmar's understanding is the only reasonable one. It's a pity that Swagger's keywords don't follow the OAuth2 spec naming scheme. Adding the info to the documentation would help.
+1
+1!
We should also consider the common scenario of supporting multiple grant types. With the current structure, flow can only reference a single type:
This is from the current spec:
"petstore_auth": {
"type": "oauth2",
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
"flow": "implicit",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
It should look more like this:
"petstore_auth": {
"type": "oauth2",
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
"grantType": [ # rename flow, as the OAuth2 spec calls it "grant type"
"authorization_code", # naming convention is snake_case in OAuth2 spec
"client_credentials"
"implicit",
"password",
"refresh_token" (this addresses #272)
],
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
Refresh token wasn't mentioned in this issue, but has been previously addressed in #272, so it seemed appropriate to add here.
One current tooling issue is validating the URLs required vs grant_type. It would be an easier tooling approach with a more hierarchical structure (although not as DRY). It seems like an anti-pattern to use different URLs for each grant type in practice, but it might be good to measure the interest level in having this potential flexibility (and trading DRYness).
"petstore_auth": {
"type": "oauth2",
"grantType": {
"authorization_code": {
"tokenUrl": "http://api.swagger.io/api/oauth/token",
"authorizationUrl": "http://swagger.io/api/oauth/dialog"
},
"client_credentials": {
"tokenUrl": "http://api.swagger.io/api/oauth/token"
},
"implicit": {
"tokenUrl": "http://api.swagger.io/api/oauth/token",
"authorizationUrl": "http://swagger.io/api/oauth/dialog"
},
"password": {
"tokenUrl": "http://api.swagger.io/api/oauth/token"
},
"refresh_token": {
"tokenUrl": "http://api.swagger.io/api/oauth/token"
}
}
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
}
@jasonh-n-austin - you can already define multiple oauth2 schemes, is that not enough?
So the only way I'm aware of defining multiple schemes, in the current structure:
"petstore_auth_implicit": {
"type": "oauth2",
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
"flow": "implicit",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
},
"petstore_auth_code": {
"type": "oauth2",
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
"tokenUrl": "http://swagger.io/api/oauth/token",
"flow": "accessCode",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
Sorry if I went a little beyond the issue scope, I guess I'm really proposing the question: does the current structure make sense? If that's not a big issue, then perhaps some of the key/value changes are really the value here, to maintain consistency with the OAuth2 spec.
The issue is more about the naming convention we chose for the flows which do not correspond directly to the OAuth2 spec, and we should probably change that in the next version.
As for the definition, yes, you'd define those as you did above, but you can still have an AND/OR relation between those definitions which I believe cover the requirements you raised earlier. It's true that it requires duplicating the URLs (and possibly scopes if they're the same), but this is done once in the definition there and referenced from the rest of the spec, so I don't know if the DRY principal here is worth it compared to the added complexity of the definition. That said, I don't feel strongly towards either approach (for now :wink:).
OK so to exemplify the original proposal:
"petstore_auth_implicit": {
"type": "oauth2",
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
"refreshUrl": "http://swagger.io/api/oauth/token",
"grantType": "implicit",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
},
"petstore_auth_code": {
"type": "oauth2",
"authorizationUrl": "http://swagger.io/api/oauth/dialog",
"tokenUrl": "http://swagger.io/api/oauth/token",
"refreshUrl": "http://swagger.io/api/oauth/token",
"grantType": "authorization_code",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
},
"petstore_auth_password": {
"type": "oauth2",
"tokenUrl": "http://swagger.io/api/oauth/token",
"grantType": "password",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
},
"petstore_auth_client": {
"type": "oauth2",
"tokenUrl": "http://swagger.io/api/oauth/token",
"refreshUrl": "http://swagger.io/api/oauth/token",
"grantType": "client_credentials",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
},
Summary:
flow to grantTypeflow/grantType values to match OAuth2 spec (snake_case)refreshUrl fieldHere's my issue: scopes could be a long list for some APIs, and is now copy-pasted across numerous definitions, which seems to be asking for trouble. I'm not convinced that it's a common use case to have specific scopes available for each grant_type.
One other thing to consider is custom grant_types. As OAuth2 is a framework, not a standard, custom grant_type is not uncommon...we could leave some of the validation open to new values for grantType.
In the meantime I've completed my standard-compliant OAuth2 authorization server that covers all flows with an extendible software architecture and I am confident I worked through the RFC thoroughly. My two cents:
Change
flowtograntType
There are two different processes when the browser interacts with the authorization server's webpage (HTML) and when the client (3rd party web service or JavaScript application running in the resource owner's browser) interacts with the authorization's token endpoint (JSON). OAuth2 predefines a handful _flows_ and only the _authorization code flow_ covers both an _authorization request_ sent to the webpage and an _access token request_ sent to the token endpoint. The type of authorization requests is specified by response_type--the type of access token requests is defined by grant_type. flow is the right keyword to specify the complete process.
Change naming convention of flow/grantType values to match OAuth2 spec (snake_case)
I support this one.
Add
refreshUrlfield
I am not sure about this one. In the RFC the refresh process is not in the section about the flows but a separate section. More technically it is definitely a flow that includes only a single _access token request_ of grant_type refresh_token. That's the way it's naturally implemented.
As this flow is pointless on its own but implicitly part of other flows because access tokens expire I tend not to list it as one of the advertised flows.
But if every flow gets its own URL one might want to explicitly define the URL for refresh_token requests. I think the RFC doesn't prohibit different URLs for multiple token endpoints--either as aliases or with different supported flows. But it is also not explicitly permitted and I'd strongly discourage doing so. I'd prefer having one URL and a list of supported flows. In every case custom flows should be allowed as they're explicitly permitted and probably quite common.
scopescould be a long list for some APIs, and is now copy-pasted across numerous definitions, which seems to be asking for trouble. I'm not convinced that it's a common use case to have specific scopes available for eachgrant_type.
The list of scopes doesn't need to be flow-specific as it's only a list of valid tokens that may be defined as required for certain operations under /paths. Different flows may result in different tokens granted but the user might [de]select certain scope tokens, too, and the original reasoning for a certain scope is irrelevant when supplying (client) or verifying (resource owner) the access token.
On flow->grantType: well said, I think you're right. We should leave flow as-is.
The list of scopes doesn't need to be flow-specific as it's only a list of valid tokens that may be defined as required for certain operations under /paths. Different flows may result in different tokens granted but the user might [de]select certain scope tokens, too, and the original reasoning for a certain scope is irrelevant when supplying (client) or verifying (resource owner) the access token.
Yep great point about a consolidated list of scopes. Part of my reasoning in suggesting a different structure: https://github.com/OAI/OpenAPI-Specification/issues/400#issuecomment-181998910
But if every flow gets its own URL one might want to explicitly define the URL for refresh_token requests. I think the RFC doesn't prohibit different URLs for multiple token endpoints--either as aliases or with different supported flows. But it is also not explicitly permitted and I'd strongly discourage doing so.
+1 on this. I really threw the refreshUrl in there to see if that was requisite flexibility for anyone, but I doubt there's much reality to separate token/refresh URLs.
Regarding the refresh token, we should take #272 into account (it's come up in other places too, iirc). We may choose to not support it, however, if it doesn't introduce complexity, perhaps we should (as something optional).
Regarding naming the different flows. The spec allows to implement custom flows. When you use your own naming schemes for the default Oauth2 flows it makes it hard to document custom Oauth2 flows.
This has changed in 3.0.
Most helpful comment
We should also consider the common scenario of supporting multiple grant types. With the current structure,
flowcan only reference a single type:This is from the current spec:
It should look more like this:
Refresh token wasn't mentioned in this issue, but has been previously addressed in #272, so it seemed appropriate to add here.
One current tooling issue is validating the URLs required vs
grant_type. It would be an easier tooling approach with a more hierarchical structure (although not as DRY). It seems like an anti-pattern to use different URLs for each grant type in practice, but it might be good to measure the interest level in having this potential flexibility (and trading DRYness).