Search code examples
amazon-web-servicesexpressaws-lambdaaxioscors

Cors error persists no matter what I try with server


I have done everything possible to make this cors error go away but still no help.

I have uploaded my controller, app.js file for express and the request.

controller:

const login = async(req, res)=>{
    const {username, password} = req.body

    if(!username || !password){
       return res.status(200).json({message:'inavlid credentials'})
    }
    const user = await User.findOne({username:username})

    if(!user){
       return res.status(200).json({success:false, message:`user with username:${username} not found`})
    }

    const passwordCorrect = await user.comparePasswords(password)
    if(!passwordCorrect){
      return res.status(200).json({success:false, message:`no user with provided credentials`})
   }
   
    const token = await user.createToken()
    let respy = {user:user.username, token:token}
    const task = await Task.findOne({createdBy:user.username}).select("boards.name boards._id")

    if(task){
      respy.data = task
    }

    return res.status(200).json(respy)

Route:

router.route('/register').post(register)
router.route('/login').post(login)

module.exports = router;

server index file:

app.set('trust proxy', 1)
app.use(rateLimit({
    windowMs: 15 * 60 * 1000,
    limit: 1000
}))
app.use(helmet())
app.use(xss())
app.options('*', (req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', ["https://ifastaskmanager.netlify.app"]);
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, content-type, Origin, X-Requested-With, Authorization, Accept');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE');
    res.setHeader('Access-Control-Allow-Credentials', true)
    next();
} )
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', ["https://ifastaskmanager.netlify.app"]);
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type, content-type, Origin, X-Requested-With, Authorization, Accept');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE');
    res.setHeader('Access-Control-Allow-Credentials', true)
    next();
});
//my routes codes below the above

request:

    const postLogin = async () => {
        try {
            let { data} = await axios.post(`${process.env.REACT_APP_API}/api/login`, userPass, {withCredentials:true)
            settings(data.data)
            localStorage.setItem('taskId', data.data._id)
            localStorage.setItem('token', data.token)
            goto()
        }
        catch (err) {
            setLoading(false)
            setErrMsg(err.message)
        }
    }

I have used fetch API instead of axios and no change. Sometimes it works good and many times it throws cors Access-Control-Allow-Origin missing even though it's not. I've used the npm cors package and played with all its options still no change. I'm using aws lambda to host the server and my other server on aws works well. Thanks for you assistance!

this is the error I get:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://***********.amazonaws.com/latest/api/login. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 502.
access-control-allow-credentials
    true
access-control-allow-headers
    Content-Type, content-type, Origin, X-Requested-With, Authorization, Accept
access-control-allow-methods
    GET, POST, PATCH, PUT, DELETE
access-control-allow-origin
    https://ifastaskmanager.netlify.app/
allow
    POST
content-length
    4
content-security-policy
    default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests
content-type
    text/html; charset=utf-8
cross-origin-opener-policy
    same-origin
cross-origin-resource-policy
    same-origin
date
    Wed, 14 Aug 2024 15:25:22 GMT
etag
    W/"4-Yf+Bwwqjx254r+pisuO9HfpJ6FQ"
origin-agent-cluster
    ?1
referrer-policy
    no-referrer
strict-transport-security
    max-age=15552000; includeSubDomains
via
    1.1 d1770bd6cae759a3354f4f22aec533c2.cloudfront.net (CloudFront)
x-amz-apigw-id
    cgTe9FRbDoEErdA=
x-amz-cf-id
    DFdo6zwXM7xJboMGM4lACNSNJPEvZAnsm1PJx3XHI_f-ufnCMKvroQ==
x-amz-cf-pop
    MAN51-P2
x-amzn-remapped-connection
    keep-alive
x-amzn-remapped-content-length
    4
x-amzn-remapped-date
    Wed, 14 Aug 2024 15:25:21 GMT
x-amzn-requestid
    2e20c793-5397-4cd4-9c19-e22869549c45
x-amzn-trace-id
    Root=1-66bccc5f-4df753ff130075aa6354fe4f;Parent=1c993f9add57a541;Sampled=0;lineage=4c7e705a:0
x-cache
    Miss from cloudfront
x-content-type-options
    nosniff
x-dns-prefetch-control
    off
x-download-options
    noopen
X-Firefox-Spdy
    h2
x-frame-options
    SAMEORIGIN
x-permitted-cross-domain-policies
    none
x-ratelimit-limit
    1000
x-ratelimit-remaining
    999
x-ratelimit-reset
    1723650022
x-xss-protection
    0

I checked everything in my code base, I ran it locally and every works fine. so I can't trace where the 502 error code's cause is. Again, it works sometimes but most times it doesn't. Should I use EC2 instead? I have almost zero knowledge of EC2.


Solution

  • So far, this is what I did that works.

    I had this in my model file:

     userSchema.methods.createToken = function(){
       return JWT.sign({userId:this._id, username:this.username}, process.env.JWT_SECRET, {expiresIn:"20d"})
     }
    
     userSchema.methods.comparePasswords = async function(candidatePassword){
        let matches = await bcrypt.compare(candidatePassword, this.password)
         return matches
    }

    I commented it out in my model file and moved it directly to my login controller in my question above.

    then in my login controller, I put all my login in a try and catch block instead of depending on the async error package.

    then I moved my app.use(express.json()) above all other configurations basically where I was still requiring packages.

    Then I removed my cors config, used cors package with following settings:

    app.use(cors({
          allowedHeaders: ["authorization", "Content-Type", "Access-Control-Allow-Origin"],
          exposedHeaders: ["authorization", "Access-Control-Allow-Origin"],
          origin: "https://ifastaskmanager.netlify.app",
          methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
          preflightContinue: true,
          credentials:true,
          maxAge:600
    }))

    Knowing that this error comes and goes sometimes(Though hasn't been consistent for this long(10hrs now no error)), I'll give this 1 day or 2 to verify the error is officially gone for good, try to recreate and find the source before marking this as an answer

    Aug 25th 2024 test result:

    Today, I may have found the issue but I'm also going to let this run for two days before I mark as answer: I found typo in my mongoose schema; the required attribute was spelt reuqire so I had: password:{ type:String, reuqired:[true, 'User password must be entered'] }.

    But this doesn't explain why it works on local server and crashes when deployed. Before correcting the typo, bcrypt.compare() was marking await keyword as unecessary even though bcrypt.compare() returns a promise but after correcting the typo, bcrypt.compare accepts the await keyword without marking it as unecessary.

    sep 7 20204 after weeks of test:

    The Problem seem to be the typo in the authentication schema. Because I've not had that cors issue since I corrected the typo. I wasn't able to figure out why it worked locally and crashes when deployed but I can say the cors issue is solved so I'm marking this as answer.