React SDK Example Issue
-
I am testing out FusionAuth for using in React and trying to implement the FusionAuth example for React using the FusionAuth React SDK:
I have FusionAuth running on my dev machine and followed the instructions in the REAME. Everything seems to be setup as instructed and double checked but when attempting to login the app/callback route responds with service unavailable and the console message:
refresh token or access token is missing. {"error":"invalid_request","error_description":"Invalid Authorization Code","error_reason":"auth_code_not_found"}
Through various console.logs I have checked all the form field variables posted to the /oauth2/token route and they seem correct but the response body only has the error object, no tokens.
Searching around I have seen issue with the redirect_uri and the setup in the FusionAuth Application but again they seem properly setup and matching. I am assuming I am missing some key setting but have rechecked the README instructions and the Application setup multiple times without success so at this point any suggestions I should checkout would be much appreciated!
-
Hmmm. Are you still seeing this issue?
-
@dan Yes, it is still happening. I just went through it again and everything seems to check out with the setup. With console.log checks of the flow through app/callback I did find one potential issue that there is no codeVerifier in the req.cookies
router.get("/", (req, res) => { console.log("accepting request for token exchange") // added console.log checks console.log("Request Cookie: ", req.cookies) console.log("Code Verifier: ", req.cookies.codeVerifier) const code = req.query.code const codeVerifier = req.cookies.codeVerifier const redirect_uri = `${req.protocol}://${req.get("host")}/app/callback` ...
Console Output
accepting request for token exchange Request Cookie: { 'fusionauth.remember-device': 'QkJCAQFsTNi5MoJrFruNrayMfc8hu0-RyUsGyIShNODgcEAA', 'fusionauth.sso': 'AgIoJJexUbQDN2Bmp_KPxP1i9PkO0_ItLkg9PNIbkYol', 'fusionauth.locale': 'en', 'fusionauth.timezone': 'America/New_York', lastState: '94acf860312a9d798db4049f741e764cf90da8ce65e0338d7b6715d0:', 'fusionauth.at': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImd0eSI6WyJhdXRob3JpemF0aW9uX2NvZGUiXSwia2lkIjoiZmMyNGZlNTU3OCJ9.eyJhdWQiOiIzYzIxOWU1OC1lZDBlLTRiMTgtYWQ0OC1mNGY5Mjc5M2FlMzIiLCJleHAiOjE2ODMwNDE5OTcsImlhdCI6MTY4MzA0MTkzNywiaXNzIjoiZnVzaW9uYXV0aC5pbyIsInN1YiI6IjFhNTMyZWNmLWM2YzItNGMwOS04ZmY3LTBjMTEwZTg3ZTMyOSIsImp0aSI6IjliNzU1YTQ5LWFmNjEtNDI0NC1hNjk0LTQxMjNhMzI1NTM2MSIsImF1dGhlbnRpY2F0aW9uVHlwZSI6IlBBU1NXT1JEIiwiZW1haWwiOiJqcHJpY2VyQGxvbmdob3VzZXNvZnR3YXJlLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhcHBsaWNhdGlvbklkIjoiM2MyMTllNTgtZWQwZS00YjE4LWFkNDgtZjRmOTI3OTNhZTMyIiwic2NvcGUiOiJvZmZsaW5lX2FjY2VzcyIsInJvbGVzIjpbImFkbWluIl0sInNpZCI6IjEwMGM2MzkyLWEyYzctNDNiMy05ZTY0LTEzYmE5M2Y5OGQzZSIsImF1dGhfdGltZSI6MTY4MzA0MTkzNywidGlkIjoiMjE1YTgxYTgtZGYyMi0xMWVkLWFhYTQtOTY1OWZkZTY4OWZkIn0.qdeLWlVcKfXIfRQUjdmMDs2yCHD0hVq2WIYnIXatX-w', 'fusionauth.rt': 'CFoc15z-AiYcxcqw35cXjn7TY2wNhn43ouxy7t_qfto5dVY0wHt0fA', sAccessToken: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsInZlcnNpb24iOiIyIn0=.eyJzZXNzaW9uSGFuZGxlIjoiMWQ5YjNhYmEtMTNmMy00YzViLWE3MDYtZWZkZGRjMzgyM2UwIiwidXNlcklkIjoiMWUwNzY0MzMtMzc1NC00MWRiLThmZTgtOTg4Mzk3YWY4MmZkIiwicmVmcmVzaFRva2VuSGFzaDEiOiJkMjBlNTM3MDE3NTQ2YzY0MWE3NTVjMzk2N2NhYzcyY2RkYzRhZGFhZGQxNjc0ZGVlYWY3ZjQ3MDQ0MzRmN2ExIiwicGFyZW50UmVmcmVzaFRva2VuSGFzaDEiOm51bGwsInVzZXJEYXRhIjp7fSwiYW50aUNzcmZUb2tlbiI6bnVsbCwiZXhwaXJ5VGltZSI6MTY4MjgyMzc3MjAyMSwidGltZUNyZWF0ZWQiOjE2ODI4MjAxNzIwMjEsImxtcnQiOjE2ODI4MjAxNzIwMjF9.Kszhn1PT5bHnIcLsKwUQ3zyV25Xy24qLwVUUeS66NlTWH1spN/UoKgP6AhMKXunucYkvT2BGArYqdFnFM4fCxhytrboTKtYaVF6OeCdAxYhladYvgz59gALKYZ2Htiq8Pi3MMQQTum8J20Ae5nSmWUQfrQlzyN5Nc6v59ugSYlNXVvdaQDbJtjjf96yUHdOn3vpGHNjBplTR68mvOEXcavMICPfaCfqMwsaxmlQtHCE30keavinPgEDZ7LclWbJk+cKI6m28yWLGe77WW89oTGJ+mCauprZDwYyVWxIS7BXLYSTgiEWiIvgQtDYbGQlUVrwDGN4pn2VL3vhEbzHzHQ==', sFrontToken: 'eyJ1aWQiOiIxZTA3NjQzMy0zNzU0LTQxZGItOGZlOC05ODgzOTdhZjgyZmQiLCJhdGUiOjE2ODI4MjM3NzIwMjEsInVwIjp7fX0=', 'st-last-access-token-update': '1682820172039', 'fusionauth.known-device.B_L9M3zcnQB5ZmkY_vZSdxt4bj7DG02aF1ur2Gle5uI': 'k1-SYySzGI1JI93fnWd70TjMhRLwXl3H_v1LJLiK03lU9qrmvj7wpT5ktEnqyB8b', 'fusionauth.known-device.58nYCMmurFn0ZYtN8AHocKJJC4A74IkRq0McoRtcik8': 'rIk7kVrwANxWPOiUYtKIQtCWrD8FlLe0kr7MWJqEcQL3BbvVrlchLzlpEmQdLfty', 'fusionauth.known-device.171xuqNosEvqLcUHp26t_opk4L-p4qqp1nTXNAYsnT4': 'cT_K5TflTbG6kl4W-XVFuw5pfAGl5GPNoIAxkS-bMV_pRDND_wJiIYC36NU6M99z', 'fusionauth.known-device.HlilUTdHiTm-5g9-0E3SkStX_Vlx5HlqncVgeoz1PIE': '1qwS-PwMf-KW-puKlkbrIL9rMFkQYZwBV1KAKikbZ5MIYM5gT3UMp7C8LLNCCNqu' } Code Verifier: undefined
I tried changing the app OAuth setting for PKCE to required and still no codeVerifier was undefined nor any change in behavior. In the request it sent as undefined in the form.
request( // POST request to /oauth2/token endpoint { method: "POST", uri: `${config.fusionAuthBaseUrl}/oauth2/token`, form: { client_id: config.clientID, client_secret: config.clientSecret, code: code, code_verifier: codeVerifier, // undefined grant_type: "authorization_code", redirect_uri: redirect_uri, }, headers: { "Content-Type": "application/x-www-form-urlencoded", }, },
The docs seem to indicate that code_verifier is optional if a client secret is used and I have triple checked the id and secret are properly set and being sent from the config.js as well as matching the Application OAuth settings in the dashboard. The only other thing is the redirectURL which is sent as http://localhost:9000/app/callback.
Any ideas on what I may have missed or should check next? Thanks~
-
A few things that you can try:
- Make sure you are running our latest SDK version by running
npm list @fusionauth/react-sdk
(right now, it should be 0.25.0) - When being redirected back after logging in to your FusionAuth instance, take a look at the address as it may contain more info in the query string (e.g.
http://localhost:9000/app/callback?error=something+here&error_reason=something+here&error_description=something+here
) - Troubleshoot server/pkce.js to check if there's anything strange with the code generation
Please let me know if you managed to get it working and what was going on.
- Make sure you are running our latest SDK version by running
-
@vinicius-campitelli Thanks for the suggestions.
- It looks to be running v0.25.0.
npm list @fusionauth/react-sdk ../FusionAuth/fusionauth-react-sdk/client └── @fusionauth/react-sdk@0.25.0
- No error info in the callback url
http://localhost:9000/app/callback?code=8qyqXxsXBAYv1i3RAjD5ecjVi05jfPSawUwi_n1Qzmw&locale=en&state=aHR0cDovL2xvY2FsaG9zdDozMDAw%3Adb93b7b1df541be08ee5b2800735992945696efa66e73fa183f26307%3A&userState=Authenticated
- server/pkce.js is used in register.js and login.js. Following the flow with console logs of the code object being returned by pkce.js and starting from the Log In Button:
click Login and lands on fusionAuth service route /oauth2/authorize with the following in the url
http://localhost:9011/oauth2/authorize?client_id=21129524-908f-49e6-b6d7-435d7fe6119a&scope=openid+offline_access&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fapp%2Fcallback&code_challenge=z_XjnlmOGqunLdkSO5AT6lJYsrTPTarA9oMsRLKasw0&code_challenge_method=S256&state=aHR0cDovL2xvY2FsaG9zdDozMDAw%3A78a0ad25655561244958f39e4cdaeb0eb216029ab3cbbdc9687fc0d5%3A
From the login.js I had added the console.logs on the code returned from pkce.generatePKCE()
router.get("/", async (req, res) => { console.log("accepting request for login") console.log(`client_id is ${req.query.client_id}`) const newState = redirectState.pushRedirectUrlToState( req.query.redirect_uri, req.query.state ) console.log(`newState is ${newState}`) const code = await pkce.generatePKCE() // Added Console logs console.log(">> login.js code: ", code) console.log(">> login.js code.code_verifier: ", code.code_verifier) cookie.setSecure(res, "codeVerifier", code.code_verifier) const token_exchange_uri = `${req.protocol}://${req.get("host")}/app/callback` console.log("Login Redirect URI: ", token_exchange_uri) const queryParams = { client_id: req.query.client_id, scope: req.query.scope, response_type: "code", redirect_uri: token_exchange_uri, code_challenge: code.code_challenge, code_challenge_method: "S256", scope: "openid offline_access", state: newState, } const fullUrl = generateUrl(queryParams) res.redirect(fullUrl)
and get this in the console:
accepting request for login client_id is 21129524-908f-49e6-b6d7-435d7fe6119a newState is aHR0cDovL2xvY2FsaG9zdDozMDAw:e4f8adf6a76523e08258f2a550e6a13e2db5a853ecc54ba194cf872b: in generatePKCE >> login.js code: { code_verifier: '6429ae643852c4205933d692481ef296262b19535f618a53190a7d09', code_challenge: '6SUGydL3h7lcE9y54xKGrzJeHsyTnN0_J8GigrFTn7g' } >> login.js code.code_verifier: 6429ae643852c4205933d692481ef296262b19535f618a53190a7d09
So the code.code_verifier from pkce.js has a value which is then set in cookie.setSecure as a value to codeVerifier.
But as shown in the app/callback req.cookies.codeVerifier is undefined and is passed that way in the oauth2/token call.
Not sure if that qualifies as troubleshooting pkce.js but now looks to be more a cookie issue?
Looking at cookie.js both setSecure() and setReadable() use
secure: true
in the cookieProps and then doing a little google research on secure cookies read thatbrowsers which support the secure attribute will only send cookies with the secure attribute when the request is going to an HTTPS page
So since this is all running on http localhost the cookies probably are not sent. Changing the cookieProps to secure: false and no longer get the error!
So solved!? BUT now it throws me back to the localhost:3000/ root path with the login & register buttons after logging in instead of to the secure /account page. And when I manually navigate to /account the isAuthenticated check routes me back to the root path. Using a timeout function to hold the page in view a couple seconds show a blank page with just the logo and a simple console.log shows isAuthenticated from the SDK is false. So new issue.
I think I am a bit burned out on getting this to run locally, will probably eject the whole thing and retry with a clean start with only changes to the cookie security when I have the bandwidth. Thanks again for your suggestions.
-
@tiny-lamp6590
I had a slightly different issues, but I thought I would share regardless. My error wasEither refresh token or access token is missing. {"error":"invalid_request","error_description":"The request is missing a required parameter: code","error_reason":"missing_code"}
When being redirect, i did get a '/callback?error..' This was my error...
error: invalid_request error_reason: invalid_origin error_description: Invalid origin uri http://localhost:3000/ state: aHR0cDovL2xvY2FsaG9zdDozMDAw:2b689ffb2efd1f66c4a5170e162400d4902ef37ddee3b2adceef5463:
I ended up checking the kickstart.json file, and notice the authorizedOriginURL required both localhost:9000 and localhost:3000. The README only indicated localhost:9000
{ "method": "POST", "url": "/api/application/#{applicationId}", "tenantId": "#{defaultTenantId}", "body": { "application": { "name": "Example app", "oauthConfiguration" : { "authorizedRedirectURLs": ["http://localhost:3000","http://localhost:9000/app/callback"], "authorizedOriginURLs": ["http://localhost:9000","http://localhost:3000"], "clientSecret": "super-secret-secret-that-should-be-regenerated-for-production", "logoutURL": "http://localhost:3000", "enabledGrants": ["authorization_code","refresh_token"], "debug": true, "generateRefreshTokens": true }, "jwtConfiguration": { "enabled": true, "accessTokenKeyId": "#{asymmetricKeyId}", "idTokenKeyId": "#{asymmetricKeyId}" }, "registrationConfiguration": { "enabled": true } } } },
Once I added localhost:3000, my error went away. Anyway, double checking your setup against the kickstart.json file, might provide some additional information.
-
@tiny-lamp6590 said in React SDK Example Issue:
I think I am a bit burned out on getting this to run locally, will probably eject the whole thing and retry with a clean start with only changes to the cookie security when I have the bandwidth. Thanks again for your suggestions.
Maybe that would be the best approach to be honest... I just cloned the repository, started the FusionAuth instance with
docker compose up
in that folder, installed dependencies from client and server and everything works, even with thesecure: true
(which I think browsers just ignore when running locally).I tried both Firefox Developer Edition 114 and Chrome 113 and they run fine. Which browser are you running on? Have you tried disabling extensions or going incognito?