Skip to content
This repository has been archived by the owner on Jul 15, 2020. It is now read-only.

Sending custom authorizers to api gateway #76

Open
qmeteor opened this issue Mar 31, 2018 · 2 comments
Open

Sending custom authorizers to api gateway #76

qmeteor opened this issue Mar 31, 2018 · 2 comments
Labels

Comments

@qmeteor
Copy link

qmeteor commented Mar 31, 2018

Not sure if this is the place to ask but with this boilerplate how do you approach sending custom authorizers to aws api gateway?

@iaincollins
Copy link
Owner

iaincollins commented Apr 1, 2018

Ooh that's a great question.

So I have a setup that does this in another project, for Google and AWS APIs.

I've included a simple version of the example I use for Google below, as it's easier to follow.

// Uses express, express sessions and the Google oAuth library
expressApp.use(updateAccessTokens)

const updateAccessTokens = (req, res, next) => {
  // If no session, do nothing.
  if (!req.session || !req.user)
    return next()

  // If no Refresh Token stored for the user, then we can't continue
  if (!req.user.google || !req.user.google.refreshToken) {
    console.error('updateAccessTokens error: No refresh token found for user')
    next()
  }
  
  // Make sure we have a session object with the token details for the provider
  if (!req.session.google) req.session.google = {accessToken: null, accessTokenExpiry: null};

  // The refresh token is saved with the users account object.
  const refreshToken = req.user.google.refreshToken

  // The access token and access token expiry are stored in the session object.
  const accessToken = req.session.google.accessToken
  const accessTokenExpiry = req.session.google.accessTokenExpiry
  
  // If we don't have an accessTokenExpiry date for the token or if it expires soon then  
  // get a new token (5 minutes before actual accessTokenExpiry to allow for clock drift)
  if (!accessTokenExpiry || (accessTokenExpiry - 60000 * 5) < new Date().getTime()) {
    
    // Create oAuth2 client instance using our credentials and the users tokens
    const oauth2Client = new google.auth.OAuth2(
      process.env.GOOGLE_ID,
      process.env.GOOGLE_SECRET
    )

    oauth2Client.setCredentials({
      access_token: accessToken,
      refresh_token: accessTokenExpiry
    })

    oauth2Client.refreshAccessToken(function(err, tokens) {
      if (err) {
        console.error('refreshAccessToken error', err)
        return next()
      }

      // Update locally stored token values
      // Note: Refresh Token does not usually change, but it can with some
      // providers depending on how you have signed the user in to the service.
      // If it has changed, you should save it with the user object in your database.
      req.session.google.accessToken = tokens.access_token
      req.session.google.accessTokenExpiry = tokens.expiry_date
      next()
    })
  } else {
    // If token is valid and not about to expire soon then just return
    next()
  }
}
  • Basically I have a function called updateAccessTokens that I tell express to call every time.
  • It exits as soon as possible, it does nothing if the user is not logged in or if a session token exists and has not expired yet.
  • When checking if the session has expired yet, it allows for 5 minutes clock drift between the server running the code and the remote service as even with NTP clocks will drift. If your access tokens are valid for an hour or so this should work well in practice (i.e. it will treat access tokens as if valid for 55 minutes before it gets a new one). If you have very short tokens (i.e. only valid for 5 minutes) then you may not want to do this, but otherwise I strongly recommend it in practice.
  • On some services the refresh token itself rotates, and can change on each sign in, depending on how the user signs in. On others, it's issued once (and only once) on the users first sign in to the remote service and must be saved server side.
  • This example doesn't have proper error handling, it just logs to console.error(), but you can see where the failure cases are.

@qmeteor
Copy link
Author

qmeteor commented Apr 1, 2018

Thanks iaincollins I'll have to digest a bit what you mentioned here and play around with it. If I have more questions I'll direct them at you if I run into trouble. Still trying to understand the lambda authorizer function.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

2 participants