Call an API on AWS API Gateway using Cognito Credentials from Android - android

I am trying to use AWS API Gateway generated android SDK to call an API using amazon Cognito for authentication made using AWS API Gateway. Cant understand how to call the api's. Any pointers on how to make an API call from android using the generated API Gateway Android SDK. Have went through a lot of articles.

It might seem a bit confusing to start with. But it is similar to a normal SDK we use.
Let's say you have a user post in your API, and you want to create a user with few parameters like name, email, phone number according to the json your API's accept, your code will look something like
You create an instance of your SDK with:
credentialsProvider = new CognitoCachingCredentialsProvider(
context,
"identityPoolID",
AMAZON_COGNITO_REGION
);
factory = new ApiClientFactory().credentialsProvider(credentialsProvider)
.endpoint("<endpoint>");
INSTANCE.client = INSTANCE.factory.build(<class>.class);
You create an object of the User with:
UserModel output = new UserModel();
output.setFirstName("something");
output.setEmail("abc#xyc.com");
And then you make a user post with:
client.usersPost(output);
Hope it's clear.

Related

How to use auth with CognitoUserSession and ApiClientFactory?

I'm trying to authenticate against an Amazon Cognito Api, however it's not working...
Creating a CognitoUserPool for registering and signing in works. But how to proceed form here on?
In onSuccess(cognitoUserSession: CognitoUserSession) gives me a session, from which I can get a jwtToken (userSession.accessToken.jwtToken).
How to use the session in combination with the ApiFactor?
val api: DevetrackcommercialplaygroundClient = ApiClientFactory()
.apiKey(apiKey)
.build(Client::class.java)
val get= api.getFoo("id") // no auth; works
val post = api.postBar("id", something) // has auth; doesn't work
Always gives me 401. Both, if I set apiKey to the api key and also if I set it to the jwtToken.
So how can I use CognitoUserSession and ApiClientFactory in conjunction?
Seems like ApiGateway is not really meant to be used with user pools as the whole requests would needs to be created manually without any help from the sdk - same goes for the response.
See https://github.com/aws-amplify/aws-sdk-android/issues/767
Maybe this will change at some point in the future:
I agree with you that the Auth integration with API Gateway is not developer friendly and easy to use. We will take this feedback to the team to investigate on how to improve this integration. - kvasukib

Stripe.apiKey not resolving in Android

I'm using Stripe as a payment processor in my Android app and trying to charge a card as described by the documentation: https://stripe.com/docs/charges
My issue specifically is that it can not resolve Stripe.apiKey, or can not resolve symbol apiKey
The code that I'm implementing from the documentation:
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_********************";//this is where i hit a wall
// Token is created using Stripe.js or Checkout!
// Get the payment token submitted by the form:
String token = request.getParameter("stripeToken");
// Charge the user's card:
Map<String, Object> params = new HashMap<String, Object>();
params.put("amount", 1000);
params.put("currency", "usd");
params.put("description", "Example charge");
params.put("source", token);
Charge charge = Charge.create(params);
I have also imported import com.stripe.android.*; at the top of my file.
In my Gradle file I have imported the Stripe libraries:
compile 'com.stripe:stripe-android:2.0.2'
Why isn't Android able to resolve Stripe.apiKey?
The code you provided is server-side Java code for creating a charge using a token. It is not meant to be used from an Android application.
A payment flow with Stripe is divided in two steps:
client-side, in your frontend code, you collect and tokenize the user's payment information (using Checkout or Stripe.js for a web application, or the iOS / Android SDKs for a native mobile application)
server-side, in your backend code, you use the resulting token in an API request, e.g. to create a charge or a customer object.
The first step is done with your publishable API key (pk_...). The second step is done with your secret API key (sk_...).
You must never share the secret API key with your frontend code, otherwise an attacker could retrieve it and use it to issue API requests on your behalf.
To solve Stripe.apikey cannot resolve, change Stripe.apiKey to
com.stripe.Stripe.apiKey = "Your secret";
Try: Stripe stripe = new Stripe("pk_test_6pRNASCoBOKtIshFeQd4XMUh");
For more info check out: https://stripe.com/docs/mobile/android#credit-card-form

Office 365 Social APIs Access Denied

I am working with Office 365 and the Sharepoint 2013 APIs. I am using Azure AD to authenticate a user and have a test application setup inside AAD that has all the delegated permissions set to enabled in the configure tab for Sharepoint 2013. I am making these calls from a native android application and have been able to successfully authenticate with Microsoft's ADAL(ActiveDirectoryAuthenticationLibrary) using this oauth authority url: https://login.windows.net//oauth2/token?api-version=1.0. I then access my test share point site and get back a list with https:////_api/Web/Lists?getByTitle('')/Items using the Oauth token that I received from back from using ADAL. That all works well and fine, but when I try to access the Social APIs with the same token process I get a 401 Unauthorized. The url that I am using to get the current users information is: https:////_api/social.following/my. What am I doing wrong that is causing the lists api work and the social api to fail? Any help is greatly appreciated!
Are you requesting a new token for the resource before calling that resource?
The ADAL library must acquire a new Access token for each resource you are requesting. Our library automatically does the redemption of the refresh token for the new Access token if you call acquireToken() using the new resource endpoint. This is hinted at in the API docuemtation.
Example:
mAuthContext = new AuthenticationContext(ToDoActivity.this, Constants.AUTHORITY_URL,
false);
mAuthContext.acquireToken(activity, resource, clientId, redirectUri, loginHint, prompt, extraQueryParameters, callback)
//do work with the token
// now get token for new_resource
mAuthContext.acquireToken(activity, new_resource, clientId, redirectUri, loginHint, prompt, extraQueryParameters, callback)
You can use an example here which will help you see how this can be done: https://github.com/AzureADSamples/NativeClient-Android

How do I restrict Google App Engine Endpoints API access to only my Android applications?

I am an Android developer building my first Google App Engine (java) back-end for my apps. I don't want anybody else to access this API other than my app. (I plan to use App engine for verifying InApp purchases in my Android app). My data is not relevant to users so,
I don't want users to be able to access my API even if they are logged in with their Google accounts (on web or Android devices).
I followed the steps mentioned in - "Specifying authorized clients in the API backend"
(https://developers.google.com/appengine/docs/java/endpoints/auth)
like generating client IDs and add them in #Api (clientIds and audiences)
except "Add a User parameter" - since I don't need user authentication.
Then I deployed App engine and I am still able to access the API through API explorer (https://your_app_id.appspot.com/_ah/api/explorer)
(I haven't added API_EXPLORER client ID)
I tested with the APK that was built with the endpoint libs before adding client IDs and can still access the API.
Is adding a "User parameter" to all endpoint APIs a must? to achieve my purpose (restrict API to only my Android apps).
Can I pass null as userAccount name from Android client and ignore user parameter value on server (since it will be null)? Will this ensure that the API is accessible only from my android apps (since the client ID is generated for my package name and SHA1 of the APK?)
Should I use something like a service account for this purpose?
The documentation says for Android, both Android and Web client IDs must be added and audience must be the same as web client ID. Does this open access to any other web client? can I skip mentioning web client ID and still achieve my purpose?
Appreciate your time and help.
...... updating with my further investigation ...
I did the following:
Added User parameter to APIs on backend - but did not check for null value. API can still be accessed without passing any credentials (from Android debug APK and API explorer)
Then, I tried
mCredential = GoogleAccountCredential.usingAudience(this, "server:client_id:" + WEB_CLIENT_ID);
mCredential.setSelectedAccountName(null);
and passed this credential to API builder (as suggested in some other posts)
Caused FATAL EXCEPTION. So, we can't pass null account name.
I could call the API using API explorer without OAuth. But when I enabled OAuth, it gave error saying this client ID is not allowed! ( I haven't yet added com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID in client_ids{})
Then I added code to throw OAuthRequestException on the backend if the user is null. This resulted in API explorer getting errors without OAuth. It works with OAuth enabled after adding API_EXPLORER_CLIENT_ID to client_ids)
Added code to pass valid user account name(email) from my Android app. Then, I am able to access API only with my release APK. Even the debug APK gets exceptions! - which is what I expected..So, I assume no other Android apps will be able to access this API.
So, not checking for null user on back-end API is a bad idea (as suggested in other posts). It is as good as not mentioning any client_ids and not having User param.
Only question I have at this moment is: If some one can figure out the WEB_CLIENT_ID from the APK, will they be able to use it to build a web client to access my API (I haven't mentioned client secret anywhere in the code. So I am thinking this is not possible).
I did search Google groups and Stackoverflow, but still it is not clear.
(Authenticate my “app” to Google cloud endpoints not a “user”)
Authenticate my "app" to Google Cloud Endpoints not a "user"
(How do I protect my API that was built using Google Cloud Endpoints?)
How do I protect my API that was built using Google Cloud Endpoints?
(Restrict access to google cloud endpoints to Android app)
Restrict access to google cloud endpoints to Android app
I had a similar issue, not between Android and App Engine, but between a separate server and App Engine. The way I handled it was to add a signature hash field as a parameter to each API call. If the request had an improper signature, it would be denied.
For example, suppose your API end-point is example.com/api/do_thing?param1=foo. I would hash the entire url, along with a secret key, and then append the result of the hash to the request: example.com/api/do_thing?param1=foo&hash=[some long hex value].
Then, on the server side, I would first remove the hash from the url request, then run the hash on everything that was remaining. Finally, you check whether the calculated hash matches the one that was sent with the request and if they don't, you can deny the request.
It is very important however that your secret key remain secret. You have to be careful with this on Android because someone could attempt to decompile your APK.
Facing the same problem than you ! Authenticate Android End point without Google User Account is just impossible !
So here is my way to resolv this problem, without any user interaction (Maybe not the right but that works, and you've got strong authentication (SHA1 + Google Account)):
HERE IS MY ANDROID CODE
Get and Build Valid Credential
//Get all accounts from my Android Phone
String validGoogleAccount = null;
Pattern emailPattern = Patterns.EMAIL_ADDRESS; // API level 8+
Account[] accounts = AccountManager.get(context).getAccounts();
for (Account account : accounts) {
if (emailPattern.matcher(account.name).matches()) {
//Just store mail if countain gmail.com
if (account.name.toString().contains("gmail.com")&&account.type.toString().contains("com.google")){
validGoogleAccount=account.name.toString();
}
}
}
//Build Credential with valid google account
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(this,"server:client_id:301991144702-5qkqclsogd0b4fnkhrja7hppshrvp4kh.apps.googleusercontent.com");
credential.setSelectedAccountName(validGoogleAccount);
Use this credential for secure calls
Campagneendpoint.Builder endpointBuilder = new Campagneendpoint.Builder(AndroidHttp.newCompatibleTransport(), new JacksonFactory(), credential);
HERE IS MY API BACKEND CODE:
API Annotation
#Api(
scopes=CONSTANTES.EMAIL_SCOPE,
clientIds = {CONSTANTES.ANDROID_CLIENT_ID,
CONSTANTES.WEB_CLIENT_ID,
com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
audiences = {CONSTANTES.ANDROID_AUDIENCE},
name = "campagneendpoint",
version = "v1"
)
Method code:
public Collection<Campagne> getCampagnes(#Named("NumPortable")String NumPortable, User user) throws UnauthorizedException {
if (user == null) throw new UnauthorizedException("User is Not Valid");
return CampagneCRUD.getInstance().findCampagne(NumPortable);
}
For the moment, it only works on Android (I don't know how we gonna do on IOS..)..
Hope It will help you !
Google provides ways to do this for Android, web and iOS
The steps involves:
Specifying a client Id for apps you want to allow to make requests to your API
Adding a User parameter to all exposed methods to be protected by authorization.
Generating the client library again for any Android clients
Redeploying your backend API.
Updating the regenerated jar file to your Android project for your Android client.
These steps are laid out in clear detail on Google's Using Auth with Endpoints and also on this blog
Facing the same problem, here are the result of my research :
Added Android cliend id with SHA1 fingerprint in Google console
Use of it in the API annotation
BUT :
If i dont add user parameter to methods : the check about android app client id does not work
If I add the USER parameter but do not ask the user to choose its google account to create the credential ... also it does not work ...
Conclusion : It seems to be mandatory to connect a user account for the check about the app client id to be executed ... I really do not understand why because no link exist between the 2 processes
Access this site
Choose your project, go to credentials section
Create a new api key
Create a new android key
Click on "Edit allowed android applications" and enter your SHA1 key; your android package name
Let me know if this solves the issues.

How to have a read access to google.com/contacts from an android handset?

In my android application, I would like to retrieve the birthday field from google.com/contacts, as this field isn't synchronised in the android contacts application.
How can I have a read access to google contacts ?
I saw the Google contacts APIs, did I have to use it ? which one ? the Portable version ?
Or is there a simple way to read these contacts, as Android does when there is a synchronisation ?
Thanks in advance
There used to be a hack before the AccountManager was reased, I started a thread about a year ago on the android developer group, but it has been removed. There was an undocumented method that you had to access through reflection. I can't seem to find it anywhere now, like google has deleted the thread or something. I found something similar below, but it's not the one I had working.
http://donpark.org/blog/2009/01/24/android-client-side-oauth
At worst case, most devices that are out now, should eventual get 2.1. So you could just make them login then validate and get the auth key from google, and if they are on 2.1 use the AccountManager and don't bother them with the credentials. something like below
WebRequest req = HttpWebRequest.Create(
#"https://www.google.com/accounts/ClientLogin? accountType=GOOGLE&Email=them#gmail.com&Passwd=pass&service=gbase&source=sadboy");
WebResponse resp = req.GetResponse();
string all;
using (StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
all = sr.ReadToEnd().Trim();
int auth = all.IndexOf("auth=");
string auth = all.Substring(auth, all.Length - auth);
https://developer.android.com/about/dashboards/index.html
It should be possible since android 2.0 using AccountManager.
There are no tutorials nor samples, I don't have access to any >=2.0 device to try it out.
See http://code.google.com/p/android/issues/detail?id=1073#c28
As I understand you should be able to getAuthToken fo Google account and pass it in Authorization header as here Authorization: GoogleLogin auth=yourAuthToken

Categories

Resources