In AWS Cognito or Amplify Auth, can I create a user from a uid, without user interaction, similar to the Firebase Auth "custom token" approach? - amazon-cognito

I'm migrating a web app from firebase to Amplify. In firebase, you can silently sign-up / sign-in a user without any user interaction or password, as long as you somehow already have a unique identifier of the user. I wonder if Amplify has a equivalent flow. The process is something like this:
// backend:
function exchangeUidForToken(uid: string) {
const jwt = await firebaseAdmin.auth.createCustomToken(uid);
return jwt;
}
// frontend:
function authByUid(uid: string) {
const jwt = await backendFunctions.exchangeUidForToken(uid);
await firebase.auth.signInWithToken(jwt);
// user is now signed in
}
So if you have a unique identifier from your other logic, you can auth the user. The same code can be used for both sign-up and sign-in, because all you're doing is translate a fixed uid into the corresponding user.
Is something similar available in Amplify?

Related

nextauth with aspnetcore backend

I need a sanity check on what I'm trying to do here.
I want to build a webapp with nextjs where people can log in with discord and as a backend API I want to use a aspnetcore web api.
I got next-auth to work with discord pretty quickly in the frontend. However I'm struggling on how to identify my frontend to my backend.
My plan at the moment is to have my backend create another JWT token and save that somewhere and then use it as the Authorization header in calls to the backend api.
next-auth has callbacks where I can edit the session and the token. So what I plan to do at the moment is just call the backendapi/createJwtToken endpoint, save it to the already existing next-auth token and then into the next-auth session.
Then I could access it anywhere and don't have to refresh until the session is gone.
I can do that with next-auth callbacks
callbacks: {
async session({ session, token, user }) {
session.backendApiToken = token.backendApiToken;
return session;
},
async jwt({ token, account }) {
if (account) { // this fires only on sign in
token.backendApiToken = "ABC - get it from backend/createToken";
}
return token;
},
Is this okay? I know how to create and validate tokens in an aspnetcore api.
Is something unsecure or strange about saving an encoded apiToken in the next-auth token? Or is this absolutely normal?

Authenticate External App to Salesforce instance

I am building a mobile application that will need to fetch data from my salesforce instance. I have no problem with SOQL to grab the appropriate data. However, I do not want the user of the mobile app to have to log in to get a token, which I need to use to access the data.
Is it possible to authenticate the app via appId and client secret in the application to allow the appropriate use/access of the APIs? This would be similar to authenticating an app to a Parse or Firebase instance without requiring an authenticated user.
Thanks!
This is an example in nodejs/Express , in this example i get the accounts:
var express = require('express');
var router = express.Router();
var nforce = require('nforce');
/* GET home page. */
router.get('/', function(req, res, next) {
var accounts =[];
// create the connection with the Salesforce connected app
var org = nforce.createConnection({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
redirectUri: process.env.CALLBACK_URL,
mode: 'single'
});
// authenticate and return OAuth token
org.authenticate({
username: process.env.USERNAME,
password: process.env.PASSWORD+process.env.SECURITY_TOKEN
}, function(err, resp){
if (!err) {
console.log('Successfully logged in! Cached Token: ' +
org.oauth.access_token);
// execute the query
org.query({ query: 'select id, name from account' }, function(err, resp){
if(!err && resp.records) {
// output the account names
for (i=0; i<resp.records.length;i++) {
//console.log(resp.records[i].get('name'));
accounts.push(resp.records[i].get('name'));
}
res.render('index', { title:'Accounts',accounts:accounts });
}
});
}
if (err) console.log(err);
});
//console.log(accounts);
});
module.exports = router;
You need to get you api crendentials for authenticate , it does not matter what language are you using the concept is the same.
USERNAME : Your Salesforce User name
PASSWORD: Your Salesforce Password
SECURITY_TOKEN: Your user security token , if you don't have it you can go to My Settings -Personal -Reset my security token and Salesforce will send you the token to your email.
The other parameters are parameters you get from your app , so you have to register the app to get the security tokens.
For create a connected apd You go to : Setup -Build-Create Apps in the section of Connected Apps create a new one. the connected api generate a consumer key and a Consumer secret.
CLIENT_ID: Is the consumer key
CLIENT_SECRET:Is the Consumer secret
CALLBACK_URL: The callback url in my example is : http://localhost:3000
This is not natively possible. All access to data/meta data in salesforce goes through a salesforce user account.
User accounts auth via username/pass, or via SSO (oAuth/SAML), or "Delegated Auth" (a pre-SAML auth service).
Creating a "Connected App" is a feature, enabled by the salesforce admin, which enables your mobile app to connect via oAuth, along with a public/private key pair.
However, Login is still required.
Perhaps you could place middleware between salesforce and your API - the middleware would connect to salesforce using a salesforce user account, while the API that it exposes accepts your public/private key.

How to pass Firebase Auth Token from client to server?

The website that I'm working on uses Firebase authentication and different users that login have different permissions as to which pages they can visit.
The way signing in is setup is similar to this post:
User Logins in with two parameters - "id" and "email"
Server uses these to create a custom "uid", then uses the Firebase Admin SDK to create a custom token that is sent back to the client.
The client logs in with the Javascript Firebase SDK - firebase.auth().signInWithCustomToken()
Now that the user is logged in, they can click different pages - i.e. '/foo', '/bar'
The issue I'm running into is that when they visit new pages, I'm trying to pass the token from the client back to the server (almost identical to how its done in this Firebase Doc ), verify the token & check if it has permission to view the webpage.
I'm trying to figure out the best (& most secure) way to do this. I've considered the following option:
Construct a URL with the token, but I've heard this isn't good practice because the token is getting exposed and session hijacking becomes a lot easier.
I've been trying to pass the token in the request header, but from my understanding you can't add headers when the user clicks on a link to a different page (or if its redirected in javascript). The same issue applies to using POST.
What can I do to securely pass this information to the server and check permissions when a user clicks on a link to a different page?
You can get the accessToken (idToken) on client side by:
var accessToken = null;
firebase.auth().currentUser
.getIdToken()
.then(function (token) {
accessToken = token;
});
and pass it in your request headers:
request.headers['Authorization'] = 'Bearer ' + accessToken;
and on your server side get the token with your prefered method and authenticate the request with Firebase Admin SDK, like (Node.js):
firebaseAdmin.auth()
.verifyIdToken(accessToken)
.then(decodedIdToken => {
return firebaseAdmin.auth().getUser(decodedIdToken.uid);
})
.then(user => {
// Do whatever you want with the user.
});
Nowadays, it looks like we're meant to use httpsCallable() client-side to get an object pre-authorized to talk to your endpoint.
eg:
// # ./functions/index.js
exports.yourFunc = functions.https.onCall((data, context) => {
// Checking that the user is authenticated.
if (!context.auth) {
// Throwing an HttpsError so that the client gets the error details.
throw new functions.https.HttpsError('failed-precondition', 'The function must be called ' +
'while authenticated.');
}
// ... rest of your method
});
// ./src/models/addMessage.js
const firebase = require("firebase");
require("firebase/functions");
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
projectId: '### CLOUD FUNCTIONS PROJECT ID ###'
databaseURL: 'https://### YOUR DATABASE NAME ###.firebaseio.com',
});
var functions = firebase.functions();
// This is the new code:
var yourFunc = firebase.functions().httpsCallable('yourFunc');
yourFunc({foo: bar}).then(function(result) {
// ...
});
From firebase documentation

How to use Firebase's email & password authentication method to connect with AWS to make Fine Uploader S3 work?

I decided to use Fine Uploader for my current AngularJS project (which is connected to hosted on Firebase) because it has many core features that I will need in an uploader already built in but, I am having trouble understanding how to use Firebase's email & password authentication method to communicate with AWS (Amazon Web Services) to allow my users to use Fine Uploader S3 to upload content. Based on Fine Uploader blog post Uploads without any server code, the workflow goes like:
Authenticate your users with the help of an identity provider, such as Google
Use the temporary token from your ID provider to grab temporary access keys from AWS
Pass the keys on to Fine Uploader S3
Your users can now upload to your S3 bucket
The problem is that I won't be using OAuth 2.0 (which is used by Google, Facebook or Amazon to provide user identities) to allow my user's to sign into my app and upload content. Instead I will be using Firebase's email & password authentication.
So how can I make Firebase's email & password authentication method create a temporary token to grab temporary access keys from AWS and pass those keys on to Fine Uploader S3 to allow my users to upload content to S3?
To connect AWS with an outside application, Cognito is going to be a good solution. It will let you generate an OpenID token using the AWS Node SDK and your secret keys in your backend, that you can then use with the AWS JavaScript SDK and WebIdentityCredentials in your client.
Note that I'm unfamiliar with your specific plugin/tool, but this much will at least get you the OpenID and in my work it does let me connect using WebIdentityCredentials, which I imagine is what they are using.
Configure Cognito on AWS
Setup on Cognito is fairly easy - it is more or less a walkthrough. It does involve configuring IAM rules on AWS, though. How to set this up is pretty project specific, so I think I need to point you to the official resources. They recently made some nice updates, but I am admittedly not up to speed on all the changes.
Through the configuration, you will want to setup a 'developer authenticated identity', take note of the 'identity pool id', and the IAM role ARN setup by Cognito.
Setup a Node Server that can handle incoming routes
There are a lot of materials out there on how to accomplish this, but you want to be sure to include and configure the AWS SDK. I also recommend using body-parser as it will make reading in your POST requests easier.
var app = express();
var bodyParser = require('body-parser');
var AWS = require('aws-sdk');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
Create POST Function to talk with Cognito
Once you have your server setup, you then reach out to Cognito using getOpenIdTokenForDeveloperIdentity. In my setup, I use authenticated users because I expect them to come back and want to be able to continue the associations, so that is why I send in a UserID in req.body.UserIDFromAngularApp.
This is my function using express.router().
.post(function(req, res) {
if(req.body.UserIDFromAngularApp) {
var cognitoidentity = new AWS.CognitoIdentity();
var params = {
IdentityPoolId: 'your_cognito_identity_pool_id',
Logins: {
'your_developer_authenticated_identity_name': req.body.UserIDFromAngularApp
}
};
cognitoidentity.getOpenIdTokenForDeveloperIdentity(params, function(err, data) {
if (err) { console.log(err, err.stack); res.json({failure: 'Connection failure'}); }
else {
console.log(data); // so you can see your result server side
res.json(data); // send it back
}
});
}
else { res.json({failure: 'Connection failure'}); }
});
If all goes well, that will return an OpenID Token back to you. You can then return that back to your Angular application.
POST from Angular, Collect from Promise
At the very least you need to post to your new node server and then collect the OpenID token out of the promise. Using this pattern, that will be found in data.Token.
It sounds like from there you may just need to pass that token on to your plugin/tool.
In case you need to handle authentication further, I have included code to handle the WebIdentityCredentials.
angular.module('yourApp').factory('AWSmaker', ['$http', function($http) {
return {
reachCognito: function(authData) {
$http.post('http://localhost:8888/simpleapi/aws', {
'UserIDFromAngularApp': authData.uid,
})
.success(function(data, status, headers, config) {
if(!data.failure) {
var params = {
RoleArn: your_role_arn_setup_by_cognito,
WebIdentityToken: data.Token
};
AWS.config.credentials = new AWS.WebIdentityCredentials(params, function(err) {
console.log(err, err.stack);
});
}
});
}
}]);
This should get you on your way. Let me know if I can help further.
Each OAuth provider has a slightly unique way of handling things, and so the attributes available in your Firebase authenticated token vary slightly based on provider. For example, when utilizing Facebook, the Facebook auth token is stored at facebook.accessToken in the returned user object:
var ref = new Firebase(URL);
ref.authWithOAuthPopup("facebook", function(error, authData) {
if (authData) {
// the access token for Facebook
console.log(authData.facebook.accessToken);
}
}, {
scope: "email" // the permissions requested
});
All of this is covered in the User Authentication section of the Web Guide.

Laravel: how to check if a user is logged with oauth?

I'm implementing social login with oauth using the package oauth-4-laravel in my laravel application.
Following the instructions of the package I'm able to connect with facebook or with google.
Now I don't want to store user data but still I want a user to access a page only if legged with facebook or google.
I have to check if a user is logged with oauth in a route filter. Something like this
Route::filter('auth', function()
{
if (!OAuth::check()) return Redirect::guest('login');
});
How do I do that? Or should I use another method?
Typically even when you use OAuth as authentication method, your application will still have to store user_id or name, and their email isn't it? If so, you can still apply laravel authentication like so:
//After the OAuth authentication
$user = User::where('email', $email)->firstOrFail(); //$email is the email returned from OAuth
//without acessing DB
$user = new User();
$user->email = $email; //this is an eg, can be replace with whatever user's properties you have.
Auth::login($user); //login the user using laravel
//To logout user manually
Auth::logout();
//In your filters.php
Route::filter('auth', function()
{
if (Auth::guest())
return Redirect::guest('login');
});