Do we need client_secret when using PKCE in OpenID connect authorization code flow? - oauth-2.0

As per PKCE spec, OAuth provider uses code_verifier to avoid the man in the middle attack. My understanding that, it is the best alternative for JavaScript based single page application (SPA) to exchange OAuth code for token.
When I experiment this with Google API, it says "client_secret is missing".
Here is the HTTP Request and Response.
ID: 1
Address: https://oauth2.googleapis.com/token
Http-Method: POST
Content-Type: application/x-www-form-urlencoded
Headers: {Content-Type=[application/x-www-form-urlencoded], Accept=[/]}
Payload: grant_type=authorization_code&code=4%2F1AH3Ubnm550IoT8AZ_e_eqLYDn3-JyXVo22LOcAlsWPnxTV_o0tV2N1YMNFtqhvFm65n4tuZmHfK5tkKLOsbnRw&scope=openid+profile+email&redirect_uri=https%3A%2F%2Flocalhost%3A8443%2Fdemo&client_id=myclientid.apps.googleusercontent.com&code_verifier=iv8n89-Dh3QD1uroYm6e6jcpZwxff60m-RYYlmLYArun6KF8o0z%7Ee3EjyVyYUp.4XxSbyI47QQSCMrY542sLWSUnxAG8e0a%7ETjmF_UFioJMA_ctB2jz6qbcYtu9uUOKp
ID: 1
Response-Code: 400
Encoding: UTF-8
Content-Type: application/json; charset=utf-8
Headers: {Accept-Ranges=[none], Alt-Svc=[h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"], Cache-Control=[private], content-type=[application/json; charset=utf-8], Date=[Mon, 22 Jun 2020 04:41:53 GMT], Server=[scaffolding on HTTPServer2], transfer-encoding=[chunked], Vary=[Origin,Accept-Encoding, Referer, X-Origin], X-Content-Type-Options=[nosniff], X-Frame-Options=[SAMEORIGIN], X-XSS-Protection=[0]}
Payload: {
"error": "invalid_request",
"error_description": "client_secret is missing."
}
Is my understanding that "we don't need client_secret when passing code_verifier" wrong or Google is not supporting PKCE or Do I miss some other parameter in the request? Please help.

I took a look and experienced the same problem when trying to use the latest Single Page App Standards. Looking at Google docs their implementation seems to still be based on the implicit flow.
I verified that you can send response_type='token id_token' and successfully get tokens, though I'd also prefer to use Authorization Code Flow (PKCE).

I tried without client_secret using keycloak on flutter app but it failed. code_verifier did not work; Hence I moved to use client_secret in my payload.

Related

Decode Access Token getting from frontend IOS application to fetch user information using Okta and Node JS

I am trying to decode the access token at the backend which i receive from frontend using okta jwt verifier. I am not sure about which type of token i am getting as it does not seems to be JWT token.Login module has developed by some other company and client is not aware about the Encoded mechanism.So the access token we are getting is of the form:
The entire response that i am receiving at login -
success({
"scope": "userinfo offline_access",
"token_type": "Bearer",
"expires_in": 3600,
"access_token": "CfDJ8G7oFS712aJJkUnWhDsiXlVRL4XtxRzsNbl6up_LvGbZlZtW1RwE9pRxsVC73MT6I-r7Wvj7rVsb-jp6hghJYrHLrk9KqEmUDOtHDhE63edAGnPm3WntjEL_dQyanOXHb7aiSWFeLDVak_tV0lH6DSMCbpvy-6Cr5TPmCBHRUZybOQWYl36aidrskEvZACuPy3AvfkSCnIcFIjDuh7JSk7IU_LPZzI42Pa-O2-6V4LGf6pqtdLmO1KZIPD6gtOJn7Fidk_SDOxW74OuPakBLCf_7kQAwV1qB8lyG_Dcz_fL5qK45T9iqtyf_nB6rtwvdj07rzqgGGQ6T_JAUOAo745xoF7gnl-hIZ8pxu9OPgGdC8ymFqSneFuOhv2QZty6OMVc_ORlqoW3XTtntmBuEBSYUKnYmb4n-JAkg_cAvj-lvugxBrlHJqFKUabPbZC6_MWsMabonq0IAI_-CP7OcFcjRXGgyqgTtyYYU8UfbsYhJtp7eYyQSd_WNebiEuYOQoqrCigY7XzHoCV97YQ1TuotpuLFtHDzXc1gi_1DAozrira2LCh2DOrbAsmucKwun-G5pi2VbjFwTLknbz9vcfgrfxhq6AD9P1SALG2UtPgBMoMJ0ZW4VyEJ83NCAqaOrhHMuNrPEwdB3vrEqydJerH0xbL3Z8NtE54qu_vN6IGt8yO1SkQFNibui3FBG8Aq26zsjMusC9AlXX1EMqyLK5w9VzdbzEbeY7T5od9gYqMUR_5N1Xpr8vNKuMAanqNBHqkHBsOTgumSluSoa4BKHPS4eSvImo8ip2siKRkk3c348XqR_kIGToyuElROpVZuZ1PfTTp0tYpneCfKIHwtymt11gq-vZ-3dPjOSGQU-W5zemFAyhrEv-6NSQfGI-vi4rsWPr6fpeGgiEA3CkBUanbrXbsM3-48cHFkj0NkG3z1bTGqoAHmwP9Fub8-EhQDpNd74znYyi75Un_OjbLb2pvZ8Vp6ewRClaCEjXL44_7SOWyQ-uNnjIS_wlJ01WzRj6Nj9VNTlhYktBhi0LbUIYiaRrazCF671pc3KxYmLQzh8tLw-x-pG5UHLQNnId6YgbNL9vXi8B7NaKOMMI7ip46mO32rSxS4TE2cWjxUFeDMoRxN3XaZ9TLANvrvDpdZVSRyTpqHVmjk5Lfnj8GAUG4FY9NWYHsGLwXnT3Nn2GAgKjjVRTpUoSuXrqDCzM0fXDRAFPZ8SLe5YviG6_O4AtqGGzqj7wUUcotkwrH4WU7xVcDBip4L8yEudNCPpQkLOs0tdU5qysO8pAyVgJ89taBWeCB3VkKTdi9VXgOpUjg_wJU2eAez_xVkf3qgovk80vivhIrjRVAh0vyPVmYWwF1uwsjzx_w3_3HYspbPIC7KSpmxaMdiTg6a2wJtimdo_wmhNIJhe-EY60VG0Hlnmv6kuiakXqhyuFLl-XC97TrZL",
"refresh_token": "CfDJ8G7oFS712aJJkUnWhDsiXlUEOo0WAwIjVHVFeMiNBX4jl9mIJhwKW2uzS4OaiwhddF9LBbKOWkGaKw8vNynImRV0wJmHpp8U6iWP3UIY29s6rD65_iwrsPYfiBnrGUfusTCPRLG43Px1VQIgsBGhSGkys8t89IlKFLn7ec48Hkj8SKE0gAU6MhncTCZcyuuPzy-ip_u7OSwfxVd495qcpsnTbcxU2kfITyoVOl25NBXKYdaemMoqznEN4DMgfXNStNNTXgl0P6W6ag7frCVaiQSd9vHS9wohmLVmGH6-jyZ7Fad7LRIKMZgtMCONssGE2b8Bi0FhCJsKwYelFRcfR2Ox4IRBz0yTe8bQ3qfgYxcO4DzP9IT6kg0gZODNIi-CfhtOufMGUS5ZW6jTKXz5JFjF7JpwlY3vZokIWtu-HWrLsrFYUBGvBFxE6vWMuJ9GKv1B8Av85BKilWe3t8ND24-zDj0LIl7eZGmVa596VhoB7uepL4rQQb22f4Qagcw3NwUUfwl9Y4F-nguYZZxFNeESJItJ5Zlk6QUMaOQytMqCbxIB1ZuO_9-1qpo4EFv5rvFUPyMsU6o0Z78jytUVipgWu91Uzy0EDa6Qq9HgmYKykocxpMgerfKWo4W1z1qiCdjQ5g5n-Vzv50ZfD18HiCk1F3viiUEvMFUE3JmXVJ_YVoO0170LFryhSpTCsgx-UxiePKRXmhTheeOGxMNbhYCI6TXhgknesYFibdbds-3oLe135B0RJ3wG3_-NuEVLARWsPabYwF8puHIpHMH6io0oC4TcerOL-HfyI0CfvxNMRHydGQhVwSk72ja7yi0I_1BnnKop2UMtt_xGfkUkUlNXfJkvXAigUC77IphlfnMoQ5WZMWj-sPyHR-180z4OkeS8vXAwGxDFYI2Cl0Dc1XQXsbxQq98zxFWh7oni4EUxeb5eLoiK_zTcmQsq-4uq_W-PRGRS-QlkiHWKMvNykMWhYBSxpzHORfG4RRE4fVbdWbHMU0gh2d74mbXCJanw-ViYXdO2u3zh-k8oMbmHp2nNw3SBsMcCZPE2pOkdNlxGJTF1B9pS9BfTlxc60uF7JC9u57UqjGa-bA_xVOnvdB72JtVjtpV4eU9OWczfkCNlnWt7q4QBskVpI7zMuQfFhWaa4lbilrKuUwl1O057qvcP2cm800qeT3FGgebIXnfFmUEXCA4K28nvPa50yHXxK8nS6iKsPZSKSXaDenyCLjejxd4IyrYj0B02GXJLq7SmpZVYaQRoUq8AAawI0OUxoD31jj_bR_IdComt1Fljiz0y8BZxH74_sYl0gNTV1o6tDOEbE_2BeX7fiTJtMOk33W5kqeqsHA9stPUk8rZyOLSoK3u1tLAr0wZfnWSMw6GXu1gtG8UKuYD5SkqtnjPSOKZkvgS2D_aLKaBdNPqwoWSlqsLETiu2XbnDrunaSpRyIddYnHG9_r9zfSzXHYVEIjkJc9ix_V3tFjDOHkhi6Jg1qtYyG3l-BWGODo0uyduYKDoVJ9hjHdAlFy7gp87iE_LW-LN56IcziAFfPyV5cqYyQ571UFFET4kVTK3ypRrkEgPwwaGvj8Mm0IptJDpXOD6_wJm92YGgwlkGFsly1girz9YcOZpXfzo7KU1-s_zxSPLSx15eRvKU8FRblcSZZI1oGR8x3h1Cw-3dS3PkPkeidTVwN9In_VDWx4RgR6uwt6yxQJ49ZMKufvnv2DaZVr2pzSuj9a4BtNw7c_sIohE-Or8GbaksncXfD_JGMXR28NsDGLaH-uLJGPdGDK0YzO3bdkqAg4RQo1QHDCLY6X11pY3jIVhsvtLZzwrR3K81-Ff_QwDPBV0D8RrMVnAKYvb4AOdBDXWrrO2BckrvAFqfA1R-BFTJUAOJC9KH18qN"
},
Optional([
AnyHashable("Pragma"): no-cache,
AnyHashable("x-amzn-remapped-connection"): keep-alive,
AnyHashable("x-cache"): Missfromcloudfront,
AnyHashable("x-amzn-remapped-content-length"): 3516,
AnyHashable("Content-Type"): application/json;charset=UTF-8,
AnyHashable("Date"): Mon,
AnyHashable("x-amz-cf-id"): o2aYOoNsMY
3jqyQfcvtCsj8qitdXuHP63Jm8A1Hg1Edo-bvJxIxq9w==,
AnyHashable("x-flg-call-id"): 88aa3619167546ca8ed0304402502fq2,
AnyHashable("x-amz-cf-pop"): BOM51-C1,
AnyHashable("x-amzn-remapped-date"): Mon, 03Feb202008: 03: 44GMT,
AnyHashable("Content-Length"): 3516,
AnyHashable("Expires"): Thu,01Jan197000: 00: 00GMT,
AnyHashable("Set-Cookie"): .AspNetCore.Identity.Application=;expires=Thu,
01Jan197000: 00: 00GMT;
path=/;samesite=lax,Identity.External=;expires=Thu,
01Jan197000: 00: 00GMT;path=/;samesite=lax,
Identity.TwoFactorUserId=;expires=Thu,
01Jan197000: 00: 00GMT;path=/;samesite=lax,
AnyHashable("x-amzn-remapped-server"): Kestrel,
AnyHashable("x-amz-apigw-id"): ,
AnyHashable("Via"): ,
AnyHashable("x-amzn-requestid"): 5c6e9360-7245-42d3-aa0c-56a6a73d286f,
AnyHashable("Cache-Control"): no-cache
]))
I am unable to find out what type of access token is it. Client has only told us that they have used Okta to encrypt the login credentials and we are unable to find out from frontend ios that what kind of mechanism have they used to encrypt the user credentials.
It does not have separated period(".") just like JWT token has.So it is something linked to open id connect and oauth using Okta. I tried searching but unable to find out such token in the URL:
https://openid.net/specs/openid-connect-core-1_0.html#RFC6750
https://developer.okta.com/blog/2018/11/13/create-and-verify-jwts-with-node
https://github.com/okta/okta-oidc-js/tree/master/packages/oidc-middleware
https://developer.okta.com/blog/2019/10/03/painless-node-authentication
Everywhere i can see JWT access token and not the above type of token. Could any one please help as i am using Okta for the first time using Node and Express.
Thank you for your concern in advance :)

Implicit grant type: Invalid grant_type parameter value WSO2

I try generate a access token in my application on WSO2 using implicit grant type, following the request:
POST /token HTTP/1.1
Host: localhost:8243
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: d6ef6038-9860-bdc6-3867-70af98b37cc6
grant_type=code&response_type=implicit&client_id=CLIENT_ID&redirect_uri=http%3A%2F%2Flocalhost%3A8888%2Fplayground%2Foauth2client&scope=default
And the request return this error:
{
"error_description": "Invalid grant_type parameter value",
"error": "invalid_request"
}
This is my grant types settings:
Grant Types
Why this error happen, although the settings include the implicit grant type?
I think you are mixing up few things. If you want to use the Implicit grant, you don't use the /token endpoint - you get everything from the authorization endpoint. The request could look like this:
/auth?response_type=token&client_id=...&redirect_uri=...
and after a successful authentication, the client gets an access token right away as part of the redirect URL.
If you have a code and you want to exchange it for an access token and a refresh token, you are using the Authorization code grant. Then the correct grant_type value is authorization_code and you must specify the code in the code URL parameter. So the error message you are getting is correct.
Finally, the token endpoint has no response_type parameter. It's a parameter of the authrization endpoint and the correct value for the implicit flow is token, because you want an access token to be returned.

Reddit API returns HTTP 403

Following the OAuth2 login flow described at https://github.com/reddit/reddit/wiki/OAuth2 I got to the point where POST-ing to https://www.reddit.com/api/v1/access_token returns something like this:
{'token_type': 'bearer', 'expires_in': 3600, 'scope': 'identity', 'access_token': '*****'}
Then I do
GET https://oauth.reddit.com/api/v1/me
With this header:
Authorization: bearer *****
The response is HTTP 403 Unauthorized. But why? It is clear that the access token has 'identity' scope. It is also documented that the /api/v1/me call requires this scope only. (See https://www.reddit.com/dev/api/oauth#GET_api_v1_me )
So why am I getting http 403?
I was experiencing the exact same issue as you described. In my case, I resolved the 403 by adding a faux user agent string in the request headers.
In my case, using HttpClient of C#, this proceeds like so:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", "MockClient/0.1 by Me");
...
}
In my case this was because of a redirect.
Calling a non-oauth endpoint in my application (like https://www.reddit.com/r/learnpython/about.json) with the Authorization header would fail with code 403. But calling https://reddit.com/r/learnpython/about.json (without www) with the Authorization header succeeded. However both endpoints worked when I tried via Postman.
The reason for this is that reddit.com would redirect to www.reddit.com, which results in the Authorization header being dropped by Postman for the second request. In my application code, I was including the header with both requests, which explains the different behavior.
Solution: don't include the Authorization header when calling non-oauth endpoints.

How to obtain access-token for a RAML API using OAuth 2.0

I was working around with Mule project using RAML and API Manager.
by following procedure given here
AM using API Manager to handle the service tied with characteristics like
Simple Security Manager,
OAuth 2.0 Provider and
OAuth 2.0 Access Token Enforcement.
I have a separate flow for redirection which does following
set 'status' to 302
set 'Location' to URL below
http://localhost:8081/org/oauth/token?grant_type=authorization_code&&client_id=53a406c3e4b0624da8246eed&client_secret=myclientsecret&code=#[message.inboundProperties.code]&redirect_uri=http://localhost:8081/raml-api-with-oauth/redirect
All goes well till here.
But when I try to hit the url for access token I see a message
{"error":"unauthorized_client","error_description":""}
to sumup my question:
please help me with 'OAuth dance' procedure
How do i set a valid contract with the API to facilitate the communication of the clientId and clientSecret necessary for the OAuth dance.
Please help me where am going wrong.
RAML code:
#%RAML 0.8
title: raml-api-with-oauth
version: v1
baseUri: http://localhost:8081/raml-api-with-oauth
securedBy: [oauth_2_0]
securitySchemes:
- oauth_2_0:
description: |
This supports OAuth 2.0 for authenticating all API requests.
type: OAuth 2.0
describedBy:
headers:
Authorization:
description: |
Used to send a valid OAuth 2 access token. Do not use
with the "access_token" query string parameter.
type: string
queryParameters:
access_token:
description: |
Used to send a valid OAuth 2 access token. Do not use together with
the "Authorization" header
type: string
responses:
401:
description: |
Bad or expired token. This can happen if the user or Dropbox
revoked or expired an access token. To fix, you should re-
authenticate the user.
403:
description: |
Bad OAuth request (wrong consumer key, bad nonce, expired
timestamp...). Unfortunately, re-authenticating the user won't help here.
404:
description: Unauthorized
settings:
authorizationUri: org/oauth/authorize
accessTokenUri: org/oauth/token
authorizationGrants: [code,token]
scopes:
- "READ_RESOURCE"
- "POST_RESOURCE"
- basic
- comments
- relationships
- likes
mediaType: application/json
/employee:
get:
description:
This is a Get Call which throws some response in json.
responses:
200:
body:
application/json:
example: |
{
"empcode" : 1,
"ename": "Rafiq",
"company" : "org"
}
Oauth policy is based on Mule Enterprise security, in order to understand the dances for the different types of grants, please see this documentation page:
http://www.mulesoft.org/documentation/display/current/Creating+an+OAuth+2.0a+Web+Service+Provider
The below code represents oauth 2.0 (raml 1.0)
securitySchemes:
oauth_2_0:
description: |
This API supports OAuth 2.0 for authenticating all API requests.
type: OAuth 2.0
describedBy:
headers:
Authorization:
description: |
Used to send a valid OAuth 2 access token. Do not use with the "access_token" query
string parameter.
type: string
queryParameters:
access_token:
description: |
Used to send a valid OAuth 2 access token. Do not use together with the "Authorization"
header
type: string
responses:
401:
description: |
Bad or expired token. This can happen if the user or the API revoked or expired an
access token. To fix, you should re-authenticate the user.
403:
description: |
Bad OAuth request (wrong consumer key, bad nonce, expired timestamp...). Unfortunately,
re-authenticating the user won't help here.
settings:
authorizationUri: INSERT_OAUTH2_AUTHORIZATION_URI
accessTokenUri: INSERT_OAUTH2_ACCESS_TOKEN_URI
authorizationGrants: INSERT_OAUTH2_AUTHORIZATION_GRANTS
scope: [READ,WRITE]
once you include this code in your raml, we need to provide validate
url in oauth policy. https://application-name/validate(external oauth
provider)
or oauth provider should give the url which is required in
raml(authorization and access_token and validation url)
The resources can be enforced with oauth so that it will be more
secured to share the resources.
after generating the flow from raml, we need to deploy the
application to cloudhub.
we need to provide organization client_id and client_secret, so that
it will provide the access_token otherwise it throws wrong client.

Asana server returning error code 500 on OAuth 2 request with GTMOAuth 2

I'm using the GTMOAuth-2 library to implement an OAuth 2 Authorization Code Grant flow to the Asana API, but consistently getting back a server error 500. The GTMHTTPFetcher log is as follows (selectively redacted):
fetch tokens for app.asana.com
2013-05-08 16:46:58 +0000
Request: POST https://app.asana.com/-/oauth_authorize
Request headers:
Content-Type: application/x-www-form-urlencoded
User-Agent: gtm-oauth2 <user-agent>
Request body: (199 bytes)
client_id=<client-id>&client_secret=_snip_&code=<client-secret>&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fwww.google.com%2FOAuthCallback
Response: status 500
Response headers:
Cache-Control: no-store
Content-Length: 303
Content-Type: text/html; charset=UTF-8
Date: Wed, 08 May 2013 16:46:56 GMT
Pragma: no-cache
Server: nginx
Set-Cookie: <cookie>
X-Asana-Content-String-Length: 303
X-Asana-Preferred-Release-Revision: 20130508_073846_310cafc985fd5fb43121784b58d5dcd2503ffffe
Response body: (303 bytes)
<html>
<head>
<title>Error</title><script>__FILE__="(none)";var config = {
"CLUSTER": "prod",
"PRETTY_JS_CODEGEN": false,
"ENABLED_FEATURES": ""
};</script><link rel="shortcut icon" href="/-/static/luna/browser/images/favicon.ico" />
</head>
<body>
<h3>Error</h3><pre>Server Error</pre>
</body>
</html>
I've double-checked the auth and token URLs, client ID and secret, made sure the redirect URIs match on Asana and in-app. Interestingly, the authorization flow seems to get as far as authorizing the app (and the Asana site records the app as authorized), but it then never seems to return the authorization token. Is there anywhere I might be going wrong, or is this truly an internal server error?
(I work at Asana). I'm unsure where in the flow this request is being made, but it doesn't look correct. Once you've obtained the authorization code (by having the user interact with the Asana form), the library should then make a request to our /-/oauth_token endpoint, and pass us the code. So it's possible that you just need to be using the /-/oauth_token endpoint instead of the /-/oauth_authorize endpoint as you're doing.
If you look at our OAuth examples you'll note that there are two different URLs, one for authorization and one for token exchange.
Asana is probably returning a 500 because it's not expecting this and we're not doing a good enough job catching the problem.

Resources