question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using Auth.currentCredentials() server side

See original GitHub issue

Which Category is your question related to?

Using Auth.currentCredentials() server side.

What AWS Services are you utilising?

aws-amplify, aws-appsync

Provide additional details e.g. code snippets

Hi!

I’m using AWSAppSyncClient with my nuxt.js project and I stumbled into an issue. I’m running nuxt app in the AWS Lambda behind API Gateway.

When I’m using the AWSAppSyncClient on the client side (in the browser) everything works as expected. However using it on the server side, the credentials returned by the Auth.currentCredentials() are totally different than on the client side. This results in a 401 http error when querying the AppSync.

I’m storing user credentials in the cookies and I’m passing them via request headers to the server side. I’ve also written the custom CredentialsStorage class, so it can be used server and client side.

Code samples

CredentialsStorage

Used for storing credentials in the cookies. I’ve verified the getItem returns the same result server and client side.

import * as Cookies from 'js-cookie'

// This implementation is based on the amazon-cognito-auth-js/es/CookieStorage.js
class CredentialsStorage {
  constructor(req, params) {
    this.logger = new Logger('CredentialsStorageLogger', 'DEBUG')

    this.logger.debug('params: %j', params)
    this.req = req
    this.path = params.path
    this.expires = params.expires
    this.domain = params.domain
    this.secure = params.secure
    this.isClient = params.isClient
  }

  setItem(key, value) {
    Cookies.set(key, value, {
      path: this.path,
      expires: this.expires,
      domain: this.domain,
      secure: this.secure,
    })

    return Cookies.get(key)
  }

  getItemClient(key) {
    return Cookies.get(key)
  }

  getItemServer(passedKey) {
    const req = this.req
    const key = encodeURIComponent(passedKey) // there are @ symbols in the passedKey sometimes
    const cookieItem = req.cookies && req.cookies[key]

    this.logger.debug('key', key)
    this.logger.debug('cookieItem', cookieItem)
    return cookieItem
  }

  getItem(key) {
    return this.isClient ? this.getItemClient(key) : this.getItemServer(key)
  }

  removeItem(key) {
    return Cookies.remove(key, {
      path: this.path,
      domain: this.domain,
      secure: this.secure,
    })
  }

  clear() {
    const cookies = Cookies.get()
    for (let index = 0; index < cookies.length; ++index) {
      Cookies.remove(cookies[index])
    }
    return {}
  }
}

Auth configuration

This is how I configured the Auth:

req - is coming from nuxtjs and is a usual nodejs request.

const credentialsStorage = new CredentialsStorage(req, {
  domain: process.env.hostname,     // example.com
  path: '/',
  expires: 365,
  secure: process.env.isProduction, // true or false
  isClient: process.client,         // true or false
})

Auth.configure({
  identityPoolId: process.env.awsCognitoIdentityPoolId, // eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
  region: process.env.awsCognitoRegion,                 // eu-central-1
  userPoolId: process.env.awsCognitoUserPoolId,         // eu-central-1_XXXXXXXX
  userPoolWebClientId: process.env.awsCognitoClientId,  // cognito client id
  authenticationFlowType: 'USER_PASSWORD_AUTH',
  storage: credentialsStorage,
})

import { Auth } from 'aws-amplify'

const apolloDefaultClient = new AWSAppSyncClient(
  {
    url: process.env.awsAppsyncGraphqlEndpoint,       // App sync url
    region: process.env.awsAppsyncRegion,             // eu-central-1
    auth: {
      type: 'AWS_IAM',
      credentials: () => Auth.currentCredentials(),
    },
    disableOffline: true,
  },
  {
    ssrMode: true,
  },
)

Credentials received from Auth.currentCredentials() the client side

{                                                                                                                    
  expired: false,
  expireTime: 2019-03-01T13:21:51.000Z,
  accessKeyId: 'XXXXXXXXXXXXXXXXXXXX',
  sessionToken: 'some-session-token',
  params: 
   { IdentityPoolId: 'eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
     Logins: 
      { 'cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXXXXXXX': 'some-id-token' },
     RoleSessionName: 'web-identity',
     IdentityId: 'eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' },
  data: 
   { IdentityId: 'eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
     Credentials: 
      { AccessKeyId: 'XXXXXXXXXXXXXXXXXXXX',
        SecretKey: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
        SessionToken: 'some-session-token',
        Expiration: 2019-03-01T13:21:51.000Z } },
  _identityId: 'eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
  _clientConfig: { region: 'eu-central-1' },
  webIdentityCredentials: 
   WebIdentityCredentials {
     expired: true,
     expireTime: null,
     accessKeyId: undefined,
     sessionToken: undefined,
     params: 
      { IdentityPoolId: 'eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
        Logins: [Object],
        RoleSessionName: 'web-identity',
        IdentityId: 'eu-central-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' },
     data: null,
     _clientConfig: { region: 'eu-central-1' } },
  cognito: 
   Service {
     config: 
      Config {
        credentials: null,
        credentialProvider: [Object],
        region: 'eu-central-1',
        logger: null,
        apiVersions: {},
        apiVersion: null,
        endpoint: 'cognito-identity.eu-central-1.amazonaws.com',
        httpOptions: [Object],
        maxRetries: undefined,
        maxRedirects: 10,
        paramValidation: true,
        sslEnabled: true,
        s3ForcePathStyle: false,
        s3BucketEndpoint: false,
        s3DisableBodySigning: true,
        computeChecksums: true,
        convertResponseTypes: true,
        correctClockSkew: false,
        customUserAgent: 'aws-amplify/1.0.22 js',
        dynamoDbCrc32: true,
        systemClockOffset: 0,
        signatureVersion: 'v4',
        signatureCache: true,
        retryDelayOptions: {},
        useAccelerateEndpoint: false,
        clientSideMonitoring: false,
        params: [Object] },
     isGlobalEndpoint: false,
     endpoint: 
      Endpoint {
        protocol: 'https:',
        host: 'cognito-identity.eu-central-1.amazonaws.com',
        port: 443,
        hostname: 'cognito-identity.eu-central-1.amazonaws.com',
        pathname: '/',
        path: '/',
        href: 'https://cognito-identity.eu-central-1.amazonaws.com/' },
     _events: { apiCallAttempt: [Array], apiCall: [Array] },
     MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
     CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
     _clientId: 1 },
  sts: 
   Service {
     config: 
      Config {
        credentials: null,
        credentialProvider: [Object],
        region: 'eu-central-1',
        logger: null,
        apiVersions: {},
        apiVersion: null,
        endpoint: 'https://sts.amazonaws.com',
        httpOptions: [Object],
        maxRetries: undefined,
        maxRedirects: 10,
        paramValidation: true,
        sslEnabled: true,
        s3ForcePathStyle: false,
        s3BucketEndpoint: false,
        s3DisableBodySigning: true,
        computeChecksums: true,
        convertResponseTypes: true,
        correctClockSkew: false,
        customUserAgent: 'aws-amplify/1.0.22 js',
        dynamoDbCrc32: true,
        systemClockOffset: 0,
        signatureVersion: 'v4',
        signatureCache: true,
        retryDelayOptions: {},
        useAccelerateEndpoint: false,
        clientSideMonitoring: false },
     isGlobalEndpoint: true,
     endpoint: 
      Endpoint {
        protocol: 'https:',
        host: 'sts.amazonaws.com',
        port: 443,
        hostname: 'sts.amazonaws.com',
        pathname: '/',
        path: '/',
        href: 'https://sts.amazonaws.com/' },
     _events: { apiCallAttempt: [Array], apiCall: [Array] },
     MONITOR_EVENTS_BUBBLE: [Function: EVENTS_BUBBLE],
     CALL_EVENTS_BUBBLE: [Function: CALL_EVENTS_BUBBLE],
     _clientId: 2 },
  authenticated: true }

Credentials received from Auth.currentCredentials() the server side

{
expired: false,
expireTime: null,
accessKeyId: 'XXXXXXXXXXXXXXXX',
sessionToken: 'some-session-token',
envPrefix: 'AWS' }

As you can see credentials on the server side are missing these params:

  • data
  • webIdentityCredentials
  • cognito

I am however unable to reproduce this issue locally. It only happens in the lambda. Thank you for any idea / hint you might have.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:1
  • Comments:12

github_iconTop GitHub Comments

3reactions
JuHwoncommented, Aug 19, 2019

actually calling Auth.currentUserCredentials() instead of Auth.currentCredentials() did the trick for me.

1reaction
JuHwoncommented, Aug 21, 2019

@mihaerzen imo you do get different credentials on the server, because your lambda environment has credentials from the current lambda role. and the same should be the case for a fargate container.

Also if you look into the sourcecode of the amplify Auth.ts (thats how i found the solution) you can see that just using currentCredentials() does not set the credentials according to the amplify auth configuration, while the method currentUserCredentials() does.

So if you configure the auth store properly on the server, so the server side can read it, there should be no issues with using the Auth.currentUserCredentials() method i guess.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using OAuth 2.0 for Web Server Applications | YouTube Data ...
The code snippet below creates a Google\Client() object, which defines the parameters in the authorization request. That object uses information ...
Read more >
Authentication - Advanced workflows - JavaScript - Amplify Docs
federatedSignIn() to get AWS credentials directly from Cognito Federated Identities and not use User Pool federation. If you have logged in with Auth.signIn()...
Read more >
Handling authentication for Power Query connectors
The authentication UI displayed to end users in Power Query is driven by the type ... CurrentCredential() function returns a record object.
Read more >
Sending data from Client to Server - help - Meteor forums
I have this data from Auth.currentCredentials() from the client side, I need to share this data with the server. How can I do...
Read more >
SSR Support for AWS Amplify JavaScript Libraries
Enabling Server-Side Rendering (SSR) support in an Amplify app ... Using the Auth class to check and determine user authentication status in ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found