aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.41k stars 2.11k forks source link

Authenticate user with jwt created in API #2864

Closed satch69rm closed 5 years ago

satch69rm commented 5 years ago

Auth with Amplify

Cognito and Appsync

Hi, I have seen similar posts everywhere online without an answer. I am validating a user by verifying a signature though a 3rd party utility once the user joins my site. This is not an Auth service and I will never know the password used by the 3rd party. At this point I am calling my API, which creates the user inside of Cognito. This is done with an API server side and the user will never know the Cognito password.

Everything is fine there and I can return jwt tokens back to the site. My issue is that I cannot find a way to authenticate the user with the token that is being returned by my API. I have tried many different ways with no luck. My API can authenticate with Auth.signIn(username, password); Since the site will never store the password, I cannot authenticate this way. I'm looking for a way to do Auth like Auth.signIn(idToken, accessToken); or similar.

Any help would be greatly appreciated! Thanks!!!

jordanranz commented 5 years ago

Hi @satch69rm,

Are you looking for this: https://aws-amplify.github.io/docs/js/authentication#federated-sign-in

If not, could you elaborate on your use case a bit more with a step by step workflow.

satch69rm commented 5 years ago

Thank you for your feedback. I am able to call Auth.federatedSignIn with the token; however, using that method does not work with the features I am trying to use. Running the below code gives me the error: "No current user". If I login with a user name and password instead of federatedSignIn, the code below will function. Than you in advanced, I'm sure I'm just missing a step and thank you for taking the time to answer my question.

import * as AWS from 'aws-sdk';
import awsAmplify, { Auth, API, graphqlOperation } from 'aws-amplify';
import awsExports from './aws-exports';
awsAmplify.configure(awsExports);
import * as queries from './graphql/queries';

export default async function test() : Promise<any> {

  try {

    await awsAmplify.configure({
      Auth: {
        region: 'us-east-1',
        userPoolId: 'us-east-1_XXXXXXXXX',
        userPoolWebClientId: 'XXXXXXXXXXXX9999999ZZZ999Z',
        mandatorySignIn: false,
        authenticationFlowType: 'CUSTOM_AUTH',
      },
    });

    // tslint:disable-next-line: max-line-length
    const token = 'big long jwt here';
    const domainOrProviderName = 'cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXXX';
    const expiresIn = 2700;

    // tslint:disable-next-line: max-line-length
    const fedSignin = await Auth.federatedSignIn(domainOrProviderName, { token, expires_at: expiresIn }, { name: 'PASSEDINUSER' });
    console.log(fedSignin);
    const currentUser = await Auth.currentAuthenticatedUser();
    console.log(currentUser);

    // Note if you uncomment below, it gets the same "No current user" error
    // const currentSession = await Auth.currentSession();

    const listQueryxxxx = await API.graphql(graphqlOperation(queries.listQueryxxxx));
    console.log(listQueryxxxx);
  } catch (err) {
    console.log(err);
  }

  return;
}

test();
satch69rm commented 5 years ago

A little bit of progress has been made... I am able to retrieve data with the following code:

    const fedSignin = await Auth.federatedSignIn(domainOrProviderName, { token, expires_at: expiresIn }, { name: body.username });
    console.log(fedSignin);
    const curCred = await Auth.currentCredentials();
    console.log(curCred);

    const client = new AWSAppSyncClient({
      url: awsExports.aws_appsync_graphqlEndpoint,
      region: awsExports.aws_appsync_region,
      auth: {
        type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
        jwtToken: token,
        credentials: curCred,
      },
      disableOffline: true,
    });

    const newClient = await client.hydrated();
    const result = await newClient.query({
      query: graphqlTag(queries.listAcroGameTables),
      fetchPolicy: 'network-only',
    });
    console.log(result.data);

I am really trying to stay away from declaring a new AWSAppSyncClient. The code I am trying to use is: const listQuery = await API.graphql(graphqlOperation(queries.listQuery)); console.log(listQuery);

The problem is that I get the "no user logged in error" when I try to use the API. graphql method.

Again I appreciate all the help. Is there a way to call a hydrate function or set a property inside the amplify sdk that will set the user for API.graphql(graphqlOperation()) to see? Thanks in advance. Robbie

manueliglesias commented 5 years ago

@satch69rm

Seems like your AppSync API is configured for AMAZON_COGNITO_USER_POOLS auth, in this scenario you don't pass credentials, you just pass a jwt token.

Also, which pieces are running in your backend and which pieces in your frontend?

elorzafe commented 5 years ago

@satch69rm

Can you try doing this with your jwtToken?

Amplify.configure({
  API: {
    graphql_headers: async () => ({
        'Authorization': () => { return: <yourToken> }
    })
  }
});

https://aws-amplify.github.io/docs/js/api#set-custom-request-headers-for-graphql

elorzafe commented 5 years ago

Closing this issue because of inactivity, feel free to open a new issue if you still have concerns.

github-actions[bot] commented 3 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.