Title: Token endpoint scope parameter (avoiding ADSTS28003) · Issue #130 · SecureAuthCorp/oauth2c · GitHub
Open Graph Title: Token endpoint scope parameter (avoiding ADSTS28003) · Issue #130 · SecureAuthCorp/oauth2c
X Title: Token endpoint scope parameter (avoiding ADSTS28003) · Issue #130 · SecureAuthCorp/oauth2c
Description: In a relatively obscure passage in RFC6749 it seems that token endpoint may also accept scope parameter: [3.3](https://www.rfc-editor.org/rfc/rfc6749#section-3.3). Access Token Scope The authorization and token endpoints allow the client...
Open Graph Description: In a relatively obscure passage in RFC6749 it seems that token endpoint may also accept scope parameter: [3.3](https://www.rfc-editor.org/rfc/rfc6749#section-3.3). Access Token Scope The authorizat...
X Description: In a relatively obscure passage in RFC6749 it seems that token endpoint may also accept scope parameter: [3.3](https://www.rfc-editor.org/rfc/rfc6749#section-3.3). Access Token Scope The authorizat...
Opengraph URL: https://github.com/SecureAuthCorp/oauth2c/issues/130
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Token endpoint scope parameter (avoiding ADSTS28003)","articleBody":"In a relatively obscure passage in RFC6749 it seems that token endpoint may also accept `scope` parameter:\n\n [3.3](https://www.rfc-editor.org/rfc/rfc6749#section-3.3). Access Token Scope\n\n The authorization and token endpoints allow the client to specify the\n scope of the access request using the \"scope\" request parameter. In\n turn, the authorization server uses the \"scope\" response parameter to\n inform the client of the scope of the access token issued.\n\nWhen requesting multiple scopes for multiple audiences, Microsoft Entra refuses the authorization code to access token exchange with the message \n\n ADSTS28003: Provided value for the input parameter scope cannot be empty\n when requesting an access token using the provided authorization code\n\nThe application is supposed to re-use the authorization code (or use the refresh token if issued) and call the token endpoint multiple times to obtain multiple access tokens, one per requested scope. \n\nI wonder what should be the usable user interface for this in a tool like oauth2c. MSAL does it in a pretty ugly way (using an extra[extra_scopes_to_consent](https://msal-python.readthedocs.io/en/latest/#msal.PublicClientApplication.acquire_token_interactive.params.extra_scopes_to_consent) parameter). \n\nLooks like I can't call the token endpoint two times with the same authorization code:\n\n AADSTS54005: OAuth2 Authorization code was already redeemed,\n please retry with a new valid code or use an existing refresh token. \n\nThe following sequence of curl requests seems to work:\n\n# Obtain the authorization code (token endpoint call will fail, but we use the authorization code)\n\n```sh\noauth2c \"$URL\" \\\n --no-browser \\\n --client-id \"$CLIENT_ID\" \\\n --response-types code \\\n --response-mode query \\\n --grant-type authorization_code \\\n --auth-method none \\\n --scopes scope1,scope2 \\\n --authorization-endpoint \"${AUTHORIZATION_ENDPOINT}\" \\\n --token-endpoint \"${TOKEN_ENDPOINT}\" \\\n --pkce\n```\n\n# Exchange authorization code for scope1 only\n\n```sh\ncurl \"${TOKEN_ENDPOINT}\" \\\n -H \"Origin: http://localhost:9876\" \\\n -d redirect_uri=http://localhost:9876/callback \\\n -d code=\"$code\" \\\n -d code_verifier=\"$v\" \\\n -d grant_type=authorization_code \\\n -d client_id=$CLIENT_ID \\\n -d scope=scope1 \u003e token1\nREFRESH_TOKEN=\"$(jq -r .refresh_token \u003c token1)\"\n```\n\n# Exchange the refresh token for scope2 only\n\n```sh\ncurl \"${TOKEN_ENDPOINT}\" \\\n -H \"Origin: http://localhost:9876\" \\\n -d refresh_token=\"$REFRESH_TOKEN\" \\\n -d grant_type=refresh_token \\\n -d client_id=$CLIENT_ID \\\n -d scope=scope2 \u003e token2\n```\n\n# Refresh token for scope1\n\n```sh\nR1=$(jq -r .refresh_token token1)\noauth2c \"$URL\" \\\n --no-browser \\\n --client-id \"$CLIENT_ID\" \\\n --grant-type refresh_token \\\n --token-endpoint \"${TOKEN_ENDPOINT}\" \\\n --auth-method none \\\n --refresh-token \"$R1\"\n```\n\n# Refresh token for scope2\n\n```sh\nR2=$(jq -r .refresh_token token2)\noauth2c \"$URL\" \\\n --no-browser \\\n --client-id \"$CLIENT_ID\" \\\n --grant-type refresh_token \\\n --token-endpoint \"${TOKEN_ENDPOINT}\" \\\n --auth-method none \\\n --refresh-token \"$R2\"\n```\n\nIt looks like the refresh token \"knows\" which scope it should generate the updated access token for, but it is possible to specify the `scope` parameter anyway:\n\n```sh\nR2=$(jq -r .refresh_token token2)\noauth2c \"$URL\" \\\n --no-browser \\\n --client-id \"$CLIENT_ID\" \\\n --grant-type refresh_token \\\n --token-endpoint \"${TOKEN_ENDPOINT}\" \\\n --auth-method none \\\n --scope scope1 \\\n --refresh-token \"$R2\"\n```\n\nThis also works and generates a new access token for `scope1` and so on...\n\nOne implementation idea would be:\n\n1. We could add `--token-scopes` parameter (the actual name of the parameter would be `scope`) which could be added automatically for any calls to the token endpoint. \n\n1. The `--grant_type authorization_code` could send `--scopes` to the authorization endpoint and `--token-scopes` to the token endpoint (both as the `scope` parameter).\n\n2. The `--grant_type refresh_token` could send `--token-scopes` to the token endpoint.\n\n3. Implicit grant never calls the token endpoint, so the `--token-scopes` could be ignored (or not accepted)\n\n4. Client credentials - I don't know - in that case `--scopes` and `--token-scopes` mean the same.\n\n5. Other flows - no idea yet.","author":{"url":"https://github.com/saper","@type":"Person","name":"saper"},"datePublished":"2025-04-17T19:20:02.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":2},"url":"https://github.com/130/oauth2c/issues/130"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:9bf8da71-514d-fb83-b7b2-85006ee207ae |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | B700:11BE9D:1DB99F1:2B31E73:6A4BCE54 |
| html-safe-nonce | 07c0ff0fa2873672d52e158156c13224e3d6f5b64b9720bc0618c858a636406a |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJCNzAwOjExQkU5RDoxREI5OUYxOjJCMzFFNzM6NkE0QkNFNTQiLCJ2aXNpdG9yX2lkIjoiNjEwOTI0MjQxNzk3NzQ3ODc0MSIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | c97fe98bc4520c5a9c0c1c370f62f4dd8e93d81890b32a776d5e62fa6889f67c |
| hovercard-subject-tag | issue:3003268431 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/SecureAuthCorp/oauth2c/130/issue_layout |
| twitter:image | https://opengraph.githubassets.com/77d78a688ec6a88b4ddcd8a3441346beb763995d5cd587dd5fa2f214a3c2d277/SecureAuthCorp/oauth2c/issues/130 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/77d78a688ec6a88b4ddcd8a3441346beb763995d5cd587dd5fa2f214a3c2d277/SecureAuthCorp/oauth2c/issues/130 |
| og:image:alt | In a relatively obscure passage in RFC6749 it seems that token endpoint may also accept scope parameter: [3.3](https://www.rfc-editor.org/rfc/rfc6749#section-3.3). Access Token Scope The authorizat... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | saper |
| hostname | github.com |
| expected-hostname | github.com |
| None | 9df996be9551ac02247d09a2f7f64ece66c35ca28885d346e98fdfda9cdaa37b |
| turbo-cache-control | no-preview |
| go-import | github.com/SecureAuthCorp/oauth2c git https://github.com/SecureAuthCorp/oauth2c.git |
| octolytics-dimension-user_id | 9470173 |
| octolytics-dimension-user_login | SecureAuthCorp |
| octolytics-dimension-repository_id | 507841912 |
| octolytics-dimension-repository_nwo | SecureAuthCorp/oauth2c |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 507841912 |
| octolytics-dimension-repository_network_root_nwo | SecureAuthCorp/oauth2c |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | b71208a1c9ec7ccf364087569d0551f665dda674 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width