I am working on a angularfire project and I would like to know how can I create an user in Firebase 3 and once done, do not authenticate the specified user. In the previous Firebase version we had the method called createUser(email, password). Now we have the method createUserWithEmailAndPassword(email, password) only, it creates and authenticates the specified user.
The answer to the question is: you can't.
We have similar situation where we have 'admin' users that can create other users. With 2.x this was a snap. With 3.x it's a fail as that capability was completely removed.
If you create a user in 3.x you authenticate as that user, and unauthenticate the account that's logged in.
This goes deeper as you would then need to re-authenticate to create another user; so the admin either does that manually or (cringe) stores the authentication data locally so it could be an automated process (cringe cringe, please don't do this)
Firebase has publicly stressed that 2.x will continue to be supported so you may just want to avoid 3.x.
Update:
one of the Firebaser's actually came up with a workaround on this. Conceptually you had an admin user logged in. You then create a second connection to firebase and authenticate with another user, that connection then creates the new user. Rinse - repeat.
Update again
See this question and answer
Firebase kicks out current user
You can do this using cloud function and firebase admin SDK.
Create HTTP function like below.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions
exports.createUser = functions.https.onRequest((request, response) => {
if (request.method !== "POST") {
response.status(405).send("Method Not Allowed");
} else {
let body = request.body;
const email = body.email;
const password = body.password;
const displayName = body.displayName;
admin.auth().createUser({
email: email,
emailVerified: false,
password: password,
displayName: displayName,
disabled: false
})
.then((userRecord) => {
return response.status(200).send("Successfully created new user: " +userRecord.uid);
})
.catch((error) => {
return response.status(400).send("Failed to create user: " + error);
});
}
});
In your client app, call this function using Http request, for example using ajax
$.ajax({
url: "the url generated by cloud function",
type: "POST",
data: {
email: email,
password: password,
displayName: name
},
success: function(response) {
console.log(response);
},
error: function(xhr, status, error) {
let err = JSON.parse(xhr.responseText);
console.log(err.Message);
}
});
Related
I am building a teams app which is using a non-AAD based service to Authenticate. I would like to get the Teams Icon in my Configurable Tab. What are the option I have? I can not register an app, as the Teams app is going to be deployed on different tenants. Can I use microsoftTeams.authentication.getAuthToken for graph api(/teams/${teamsid}/photo/$value) without registering an app but on behalf of user ? or is there any easier way to get the teams icon.
const authTokenRequest: microsoftTeams.authentication.AuthTokenRequest = {
successCallback: function (token: string) {
//const decoded: { [key: string]: any; } = jwt.decode(token);
//localStorage.setItem("name", decoded.name);
localStorage.setItem("token", token);
const response = await axios.get(apiConfig.endpoint + "/api/" + functionName, {
headers: {
authorization: "Bearer " + accessToken?.token || "",
},
});
return response.data;
},
failureCallback: function (error: any) {
console.log("Failure on getAuthToken: " + error);
}
};
microsoftTeams.initialize(() => {
microsoftTeams.getContext((r) => {
microsoftTeams.authentication.getAuthToken(authTokenRequest);
});
});
Through this I get below error:
Attempting to handle auth response: error:invalid_resource|AADSTS500011: The resource principal named api://xxxxx/botid-xxxx was not found in the tenant named xxxx. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You might have sent your authentication request to the wrong tenant., resource:api://xxxxx/botid-xxxx, error mapped to action:resourceDisabled
You must have your app registered to be able to use graph API. It is absolutely no problem that the app will be installed on a different tenant, you just need to select "multitenant" option when registering the app to enable this scenario.
As far as I understand, logo pictures / icons are considered company data, so you need user consent to get it. For this reason, the app needs to be registered, and the user (or user admin) must agree to give the app access to the team info when adding your app.
We are building a react-native chat app. We are implementing a back end authentication solution on google Firebase. The creation of a new user in Firebase Auth triggers a cloud function which should create a new SendBird user with an access token. The access token will be stored in Cloud Firestore, ready for retrieval the next time the user logs in.
We are having trouble implementing the POST request that creates the new user via the platform API. We are using the Request library for node.js. We are able to reach the API endpoint, but the following object is returned: { message: 'SendBird API Endpoint.', error: true }. There is no indication of what the error may be.
This happens when sending the request to the base url. When we send the request to /users or /v3/users, we receive a 403 error.
Any indication as to what may be causing this problem would be greatly appreciated.
Below is the cloud function index.js code
const functions = require('firebase-functions');
const admin = require("firebase-admin");
const request = require('request');
admin.initializeApp();
exports.handleNewUser = functions.auth.user().onCreate((user) => {
var newUserRequestBody = {
"user_id": user.email,
"nickname": user.email,
"profile_url": "",
"issue_access_token": true,
}
request.post({
headers: {
'Content-Type': 'application/json, charset=utf8',
'Api-Token': // API Token
},
url: 'https://api-{application_id}.sendbird.com',
form: newUserRequestBody
}, function(error, response, body){
if (!error && response.statusCode === 200) {
const info = JSON.parse(body);
console.log("request successful");
console.log(response.statusCode);
console.log(info);
}
else{
console.log("request unsuccessful");
console.log(response.statusCode);
console.log(error);
}
});
return null;
});
Did you try with full path of end point to url: (including /v3/users)?
Or you may need to use "baseUrl" like below?
https://github.com/request/request#requestoptions-callback
Also, you need to make sure that you correctly used {application_id} value and {API Token} value.
You can double check this from your dashboard of SendBird.
http://dashboard.sendbird.com > Log in with your ID > select your APP.
There is a section named "App credentials" in "Overview" menu.
You can double check your API-request URL and API-Token value from there.
I am working on an IOS app as my college project. Basically my college has a website which has login form[no sign up forms there], and students using their unique college ID and their own password can login into this website and access things like courses they have registered for, their grades etc. Now in my app i have a log in form and i want the students to be able to login with the same existing ID and password and access the same information as they would be able to do on the website itself. Simply speaking, i want to access the post authentication information on the website in my app. How do i approach this problem?
It depends if your school server allows request from different origins (different domain). If, yes just check when you login what info it posts and to which address. Then send a request to this address with the same info and check the result from the request.
Example:
Just use chrome or firefox dev inspector, fill the login form, send it and check the request done.
Let say the request done is a POST # http://myschool.com/login with username and password form, and the result if successful is a 200 code and a cookie. Then in node js you could do:
const querystring = require('querystring');
const request = require('request');
const form = {
username: 'usr',
password: 'pwd',
};
const formData = querystring.stringify(form);
const contentLength = formData.length;
request(
{
headers: {
'Content-Length': contentLength,
'Content-Type': 'application/x-www-form-urlencoded'
},
uri: 'http://myschool.com/login',
body: formData,
method: 'POST'
},
function (err, res, body) {
// check the result here
}
);
I'm using Torii and ember-simple-auth to manage authentication on my front-side, and Knock and Omniauth-twitter on my server. I had no problem with Facebook, but Twitter using Oauth1.0, I have troubles to figure out the flow.
Here is my Torii config :
# environment.js
ENV['torii'] = {
sessionServiceName: 'sessiontorii',
providers: {
'facebook-oauth2': {
apiKey: 'API_KEY',
redirectUri: 'http://localhost:4200/'
},
'twitter': {
requestTokenUri: 'http://127.0.0.1:3000/auth/twitter'
}
}
My route or controller :
# route.js
twitterLogin() {
var self = this;
this.get('sessiontorii').open('twitter').then(function(response) {
console.log(response);
self.transitionTo('index');
}, function() {
console.log('auth failed');
});
},
A new window is opening and I can login with my Twitter account. My server does the authentication/registration, but I can't figure out how to close this new window and send the token to my front.
Is my flow completely wrong ? Or do I miss something ?
I followed this tutorial, but I wonder if it's not a bit outdated
The issue was that I was sending a wrong type of data from my server. So I updated my torii-provider and the code I was sending. Torii does the job and close the new window when it gets the data. Then, I'm sending the data to my authenticator and confirm the authentication with the JWT code.
I am using the cloudspace angularjs-devise library on the client. When I try to login/register I get a 200 ok response with the plain user object visible in the chrome js console. Refreshing the page seems to lose this information even though I assumed that the service would store this at some point since it also has logout and currentUser methods.
https://github.com/cloudspace/angular_devise
My questions are:
1) Is this service actually storing the user and if so how (i.e. with cookies or localstorage or in memory)?
2) If the service does not store the user how can I store this information in a custom cookie/localstorage and more importantly set the user into the service so that the services "isauthenticated" and "currentuser" methods can be used?
Partial Library Readme Instructions
Just register Devise as a dependency for your module. Then, the Auth service will be available for use.
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
// Configure Auth service with AuthProvider
}).
controller('myCtrl', function(Auth) {
// Use your configured Auth service.
});
Auth.login(creds): Use Auth.login() to authenticate with the server. Keep in mind, credentials are sent in plaintext; use a SSL connection to secure them. creds is an object which should contain any credentials needed to authenticate with the server. Auth.login() will return a promise that will resolve to the logged-in user. See AuthProvider.parse() for parsing the user into a usable object.
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
var credentials = {
email: 'user#domain.com',
password: 'password1'
};
Auth.login(credentials).then(function(user) {
console.log(user); // => {id: 1, ect: '...'}
}, function(error) {
// Authentication failed...
});
});
My partial code:
main.js
var myApp = angular.module('mail_app', ['ngRoute', 'ngResource', 'Devise']);
myApp.config(function($routeProvider, $locationProvider, $httpProvider, AuthProvider) {
console.log("in router")
$locationProvider.html5Mode(true);
$httpProvider.defaults.headers.common['X-CSRF-Token'] =
$('meta[name=csrf-token]').attr('content');
$httpProvider.defaults.headers.common['ClientType'] = 'browser';
// Customise login
AuthProvider.loginMethod('POST');
AuthProvider.loginPath('/api/v1/users/login.json');
// Customise register
AuthProvider.registerMethod('POST');
AuthProvider.registerPath('/api/v1/users.json');
});
SessionsController.js
myApp.controller('SessionsController', ['$scope', 'Auth', '$http', function($scope, Auth, $http) {
console.log("in session controller")
console.log(Auth.isAuthenticated());
$scope.loginUser = function() {
console.log("in login")
var credentials = {
email: $scope.email,
password: $scope.password
};
Auth.login(credentials).then(function(user) {
$scope.authError = 'Success!';
console.log(user); // => {id: 1, ect: '...'}
Auth.currentUser = user;
}, function(error) {
$scope.authError = 'Authentication failed...';
});
};
$scope.registerUser = function(){
console.log("in register function")
var ncredentials = {
email: $scope.newEmail,
password: $scope.newPassword,
password_confirmation: $scope.newPasswordConfirmation
};
Auth.register(ncredentials).then(function(registeredUser) {
console.log(registeredUser); // => {id: 1, ect: '...'};
}, function(error) {
$scope.authError = 'Registration failed...';
});
};
$scope.getCurrentUser = function(){
Auth.currentUser().then(function(user) {
// User was logged in, or Devise returned
// previously authenticated session.
console.log(user); // => {id: 1, ect: '...'}
$scope.id = user.id;
}, function(error) {
// unauthenticated error
});
};
$scope.isUserAuthenticated = function(){
Auth.isAuthenticated();
};
}]);
First of all you need to understand how cookies and sessions work in Rails.
From this article:
Rails uses a CookieStore to handle sessions. What it means is that all
the informations needed to identify a user's session is sent to the
client and nothing is stored on the server. When a user sends a
request, the session's cookie is processed and validated so rails,
warden, devise, etc. can figure out who you are and instantiate the
correct user from the database.
What this means is that on every request, Rails will look up at the session cookie, decode it and get something like
cookie = {
"session_id": "Value",
"_csrf_token": "token",
"user_id": "1"
}
At that point Rails knows that the current user has id=1 and can make a sql query. (Like current_user = User.find(1)).
When a user is logged in, a cookie is created, when the user is logged out - the cookie is destroyed. If Rails doesn't find a cookie or the cookie doesn't have information about the current user, devise will assume that the user is not logged in (current_user is nil)
Even if you login through ajax (to be particular it is through the 'angular_devise' gem in your case) the cookie is created. It is not stored on the server, but in the browser. (This is why if you are logged in one browser, you are not automatically logged in another browser) As you pointed out the library doesn't keep information who is logged in, and this is because the information is stored in a cookie and the library cannot decode the cookie without help from the server.
This is why you will have to make a call to get the current user if the user refreshes the page. (Sorry)
The way to get the current_user is very simple. This is the cleanest solution I found.
# application_controller.rb
def me
render json: current_user
end
# routes.rb
get "me" => "application#me"
// main.js
// I am not familiar with angular_devise lib but you get the point:
// this method fetches from server when myApp is initialized (e.g. on page reload)
// and assigns the current_user so he/she can be used by the app
myApp.run(["AuthService", function(AuthService) {
AuthService.getUserFromServer();
}]);
If you have to load data specific to the user, you will have to load the user first and then the data. Needless to say you will have to use promises.
TL;DR: You will have to ask the server
I am open for questions and comments.
I guess your problem is the refresh. The angular-devise lib is probably assuming you are in a SPA (Singe Page Application) so it should not refresh. With this assumption, angular-devise can store all the information in memory. When you refresh your page, you basically bootstrap the application from zero. And the request to server is probably issued by your code when application is starting. You probably call Auth.currentUser() somewhere on start of the application
Had same problem. Just use that gem
https://github.com/jsanders/angular_rails_csrf
You can also get rid of "protect_from_forgery" in your application controller, but this is very risky.