I am using AWS amplify SDK for React native.
Using the below method in the SDK signing into Cognito user pool.
Auth.federatedSignIn(
COGNITO_SAML_PROVIDER,
{ token: samlToken, expires_at: 0 },
{ email, name: '' },
);
Then retrieving the keys using currentCredentials to access AWS API gateway.
credentials = await Auth.currentCredentials();
const requestTokens = {
access_key: credentials.accessKeyId,
secret_key: credentials.secretAccessKey,
session_token: credentials.sessionToken,
};
Problem:
After idle period of 30 mins the SDK doesn't refresh the session_token and uses the expired token for subsequent request and we run into issue "the security token included in the request is invalid"
Is there a way or some parameter to set in the SDK so that the token gets refreshed periodically?
Related
My application is using OAuth to access the Youtube Data API. My OAuth callback is written in node and uses the OAuth2Client class from the "googleapis" npm package to exchange the authorization code for the access and refresh tokens.
Everything was working fine up to last week until suddenly I started getting the "invalid_grant" response during the authorization code exchange. I have tried everything to resolve this and am running out of ideas. My callback executes as a cloud function so I don't think that it would be out of sync with NTP.
My OAuth consent screen is in "Testing" mode and my email address is included in the test users. The odd thing is that even though the authorization code exchange fails, my Google account's "Third-party apps with account access" section lists my application as if the handshake succeeded.
Is there a limit to how many refresh tokens can be minted for my application? I am testing my implementation of incremental authorization so I have been going through the OAuth flow often.
Edit
I've included my code for generating the auth URL and exchanging the authorization code below. The invalid_grant occurs during the call to "oauth2.getToken"
async startFlow(scopes: string[], state: string): Promise<AuthFlow> {
const codes = await oauth2.generateCodeVerifierAsync();
const href = oauth2.generateAuthUrl({
scope: scopes,
state,
access_type: 'offline',
include_granted_scopes: true,
prompt: 'consent',
code_challenge_method: CodeChallengeMethod.S256,
code_challenge: codes.codeChallenge
});
return { href, code_verifier: codes.codeVerifier };
}
async finishFlow(code: string, verifier: string): Promise<Tokens> {
const tokens = await oauth2.getToken({ code, codeVerifier: verifier })
return {
refresh_token: tokens.tokens.refresh_token!,
access_token: tokens.tokens.access_token!,
expires_in: tokens.tokens.expiry_date!,
token_type: 'Bearer',
scopes: tokens.tokens.scope!.split(' ')
};
}
"oauth2" is an instance of OAuth2Client from "google-auth-library". I initialize it here:
export const oauth2 = new google.auth.OAuth2({
clientId: YT_CLIENT_ID,
clientSecret: YT_CLIENT_SECRET,
redirectUri: `${APP_URI}/oauth`
});
Looking at the logs, the only out of the ordinary thing I notice is that the application/x-www-form-urlencoded body looks slightly different than the example https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code
The POST request to "https://oauth2.googleapis.com/token" ends up looking like this:
code=4%2F0AX4XfWiKHVnsavUH7en0TywjPJVRyJ9aGN-JR8CAAcAG7dT-THxyWQNcxd769nzaHLUb8Q&client_id=XXXXXXXXXX-XXXXXXXXXXXXXXX.apps.googleusercontent.com&client_secret=XXXXXX-XXXXXXXXXXXXXXX-XX_XXX&redirect_uri=https%3A%2F%2Fapp.example.com%2Foauth&grant_type=authorization_code&code_verifier=KjOBmr4D9ISLPSE4claEBWr3UN-bKdPHZa8BBcQvcmajfr9RhWrgt7G429PLEpsP7oGzFGnBICu3HgWaHPsLhMkGBuQ2GmHHiB4OpY2F0rJ06wkpCjV2cCTDdpfRY~Ej
Notice that the "/" characters are not percent-encoded in the official example, but they are in my requests. Could this actually be the issue? I don't see how the official google auth library would have an issue this large.
The most common cause for the invalid_grant error is your refresh token expiring.
If you check oauth2#expiration you will see the following
A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of "Testing" is issued a refresh token expiring in 7 days.
Once you set your project to production your refresh tokens will stop expiring.
Is there a limit to how many refresh tokens can be minted for my application?
No but you have a limit of 100 test users.
I have configured my React Native application to use a Cognito user pool that is used for user identity management and authentication using AWS Amplify. I am using Custom Authentication for user management. I am able to register, log in and perform other user management-related tasks. I also have an API gateway and a few Lambda Functions which I want to access through my React Native app. When I sign in, I receive a JWT Token which I want to send to the API gateway to access my Lambdas, but no matter what I do I get an 'unauthorized' 403 or 401 message from my API Gateway.
My question is: How can I expose the API gateway/ Lambdas to the Cognito user pool users and Why the token generated by Cognito itself is unauthorized to access my api gateway.
P.S. - I used postman with the right Auth URL and settings, the postman token itself is authorized to access the API gateway and lambdas. (The user credentials are the same as I use with the React Native app)
I have spent a few days, any pointers in the right direction would be very helpful.
Thanks in advance.
NPN
Amplify Config:
const awsmobile = {
aws_project_region: 'us-XXXX-X',
aws_cognito_region: 'us-XXXX-X',
aws_user_pools_id: 'us-XXXX-XXXXXX',
aws_user_pools_web_client_id: 'XXXXh1i5nXXXX',
//aws_user_pools_web_client_secret: 'XXXXXoofuu0lXXXX',
oauth: {
domain: 'XXXXXXXX.us-XXXX-X.amazoncognito.com',
scope: ["email", "openid", "aws.cognito.signin.user.admin"]
},
aws_cognito_username_attributes: ['EMAIL'],
aws_cognito_social_providers: ['GOOGLE'],
aws_cognito_signup_attributes: ['XXXXX', 'XXXXX', 'EMAIL', 'XXXXXX'],
aws_cognito_mfa_configuration: 'OFF',
aws_cognito_mfa_types: [],
aws_cognito_password_protection_settings: {
passwordPolicyMinLength: 8,
passwordPolicyCharacters: ['REQUIRES_LOWERCASE', 'REQUIRES_UPPERCASE', 'REQUIRES_NUMBERS', 'REQUIRES_SYMBOLS'],
},
aws_cognito_verification_mechanisms: ['EMAIL'],
};
export default awsmobile;
import { Auth } from 'aws-amplify';
const login = async (username: string, password: string) => {
const response = await Auth.signIn(username, password);
console.log(response.data.signInUserSession.accessToken.jwtToken);
return response;
};
I am trying to make API (Lambda and API gateway) for sign in and verify auth using OTP for password-less authentication. The target is to make front end using angular and mobile application using Flutter but there is no support of AWS Amplify for flutter. So going through to create those API to serve my purpose. The frontend code(Auth.signIn and Auth.sendCustomChallengeAnswer) works great but using same code the verify auth API is not working. Sharing my code.
Sign In API:
await Auth.signIn(phone);
Verify Auth API: (Returned c['Session'] from DynamoDB which is stored in during signIn)
let otp = body['otp'];
const poolData = {
UserPoolId: '------ pool id -------',
ClientId: '------ client id -------'
};
const userPool = new CognitoUserPool(poolData);
const userData = {
Username: '+12014222656',
Pool: userPool
};
this.cognitoUser1 = new CognitoUser(userData);
this.cognitoUser1['Session'] = c['Session'];
await Auth.sendCustomChallengeAnswer(this.cognitoUser1, otp);
const tokenDetails = await Auth.currentSession()
response = {
'statusCode': 201,
'body': JSON.stringify({
message: 'Verification successful',
body:tokenDetails
})
}
After debugging frontend Auth.signIn response and Lambda API Auth.signIn response i investigated that an extra "storage" object returned when signing in from frontend and appended on this.cognitoUser1 before sending through Auth.sendCustomChallengeAnswer . See the attached screenshot below:
Is this the reason for successful verifying OTP from frontend? If so, what about making API (using Lambda and API gateway) and where it stores this storage object. Stuck here. Any suggestion and help will be appreciated.
You can set your own storage: https://docs.amplify.aws/lib/auth/manageusers/q/platform/js#managing-security-tokens
We've got scripts on Bing to automatically adjust ad bids based on ad performance and client goals, which are stored in a Google spreadsheet.
We had a contractor set this up initially, and it worked. But I guess that the contractor was using a temp Google account and when it went away the bidders stopped working. Because it did work before, it's likely a configuration error on my part that's breaking it now, but the contractor pointed us to the steps I was already following to no avail (https://learn.microsoft.com/en-us/advertising/scripts/examples/authenticating-with-google-services#option2).
Stuff already tried
double checked for errant whitespace around the client ID and client secret
created new client secrets
created new client IDs
made sure that the project name, application name, and OAuth client id name were all the same
created whole new projects from scratch (configured to match the article cited above) to see if that would kick something loose
tried a different token URL (https://oauth2.googleapis.com/token) that appears in the client_secret JSON downloaded from Google
function main() {
const credentials = {
accessToken: '',
client_id: 'REDACTED.apps.googleusercontent.com', // from Google developer console
client_secret: 'REDACTED', // from Google developer console
refresh_token: 'REDACTED' // created at https://developers.google.com/oauthplayground
};
var access_token = '';
if (credentials.accessToken) {
access_token = credentials.accessToken;
}
var tokenResponse = UrlFetchApp.fetch('https://www.googleapis.com/oauth2/v4/token', { method: 'post', contentType: 'application/x-www-form-urlencoded', muteHttpExceptions: true, payload: { client_id: credentials.clientId, client_secret: credentials.clientSecret, refresh_token: credentials.refreshToken, grant_type: 'refresh_token' } });
var responseCode = tokenResponse.getResponseCode();
var responseText = tokenResponse.getContentText();
if (responseCode >= 200 && responseCode <= 299) {
access_token = JSON.parse(responseText)['access_token'];
}
throw responseText;
// use the access token to get client targets from the spreadsheet
A JSON encoded access token is the expected response, but instead, we get HTTP 400 with the message "The OAuth client was not found."
Manually creating an access token on the OAuth playground (https://developers.google.com/oauthplayground) works as a stopgap, but this should work. This has worked. :P
The fix in this case switching the Application Type on console.developers.google.com > Credentials > OAuth consent screen to Internal instead of Public.
That wasn't in the steps provided by Microsoft, and I'm not sure if that will have implications down the road, but at least we're off the manual process for now.
I'm new to office 365 and having problem with accessing rest api.
I'm trying to test the rest api of Calendar and Mail API, so I decided to use Postman. However, to test those APIs, I need an access token in Authorization header. To figure out how to get a token, I decided to get the sample project here , configure, run and sign in on this local site to get the token cached in local storage and use that token for further requests in Postman. However, all requests I tested returned '401 unauthorized request'.
What I did:
Register a new app on Azure ADD associated with O365 account
Add full app permissions and delegated permissions.
Update 'oauth2AllowImplicitFlow' to true in manifest file.
Clone sample project
In app.js, I change the alter the content of config function as following
function config($routeProvider, $httpProvider, adalAuthenticationServiceProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeController',
controllerAs: 'home',
requireADLogin: true
})
.otherwise({
redirectTo: '/'
});
// The endpoints here are resources for ADAL to get tokens for.
var endpoints = {
'https://outlook.office365.com': 'https://outlook.office365.com'
};
// Initialize the ADAL provider with your tenant name and clientID (found in the Azure Management Portal).
adalAuthenticationServiceProvider.init(
{
tenant: 'mytenantname.onmicrosoft.com',
clientId: '<my cliend Id>',
endpoints: endpoints,
cacheLocation: 'localStorage'
},
$httpProvider
);
};
Then I ran the app, it sign me in just fine and I can also get the token, but that token is also unauthorized to request.
I decoded the token and saw the value of 'aud', it didn't return "https://outlook.office365.com/". In this url, the author said that "This should be "https://outlook.office365.com/" for the Mail, Calendar, or Contacts APIs"
So what did I miss ?
How you call the Office 365 API in AngularJS?
When signing the user in, you will only get the id_token to authenticate the user.
The aud of id_token is the tenant id (GUID).
To call the Office 365 API, you need to use AugularJS http request.
Here is a sample of sending email using Microsoft Graph API in AngularJS:
// Build the HTTP request to send an email.
var request = {
method: 'POST',
url: 'https://graph.microsoft.com/v1.0/me/microsoft.graph.sendmail',
data: email
};
// Execute the HTTP request.
$http(request)
.then(function (response) {
$log.debug('HTTP request to Microsoft Graph API returned successfully.', response);
response.status === 202 ? vm.requestSuccess = true : vm.requestSuccess = false;
vm.requestFinished = true;
}, function (error) {
$log.error('HTTP request to Microsoft Graph API failed.');
vm.requestSuccess= false;
vm.requestFinished = true;
});
Before calling the API, ADAL.js will acquire another token - access token which you can used to send the email.
UPDATE#1
I also downloaded the sample you mentioned. To run this sample, please ensure you have the Exchange Online > Read and writer user mail Permission assigned in your application.