I have the following setup for my website:
UI - using React
Backend REST API - using PHP
For authentication, I used AWS Amplify. So I host the UI in Amplify console and setup the backend environment for the authentication. In my UI, I have 2 pages:
Home page - "/"
Main page - "/main"
I wrapped the Main component in withAuthenticator from #aws-amplify/ui-react. With this, when i go to "/main" and the user has not signed in, it will show the default SignIn/SignUp from amplify.
My questions are these:
There are some parts on the Main page where I need to hide for non-admin users, say an "Admin" button that is only available for admin users. In Amplify Studio, there is "User Management" where you can create users. As I understand, it uses AWS Cognito for the user pool. But how should I configure a user to be an admin?
Since I am wrapping the UI's main page inside Amplify's authenticator, I can be sure that only authenticated users can access that page and send requests to the backend. To make sure that I am only showing buttons that are for admin users, I am thinking of creating an endpoint called "/profile" that will be called once my Main component loads and it will return an attribute telling me if the user is an admin or not. But how do I check if the user is an admin from inside PHP API?
The logged in user can update his profile like update his name, location, etc. For this, I will create a user_profile table in MySQL to contain these other user attributes. When the user first signup and confirm using Amplify and he's routed to the "/main" page, I'll call the "/profile" endpoint and check first if the user exists in the user_profile table? If not, I'll add that user so he can update his profile later? Is this the right approach?
Since my PHP REST APIs can be called even through say Postman, I also need to check in the backend if the request has the amplify token and check with Cognito if this is a valid token. So for all endpoints, I need to check if the token is valid. Is that correct approach and how to do that?
I am thinking of deploying my PHP REST API on an EC2 instance. I believe since they are all inside the AWS environment, I won't be having issues calling the endpoints from my UI. Is this the right approach?
The same of my MySQL db, I'll deploy to AWS RDS. I hope this is correct.
I hope for your kind guidance on my doubts. Thank you.
So they are a lot of questions for 1 post. It would be better to ask each question in a different post as right now more than technical issue it looks like opinionated architectural discussion.
Reach application can be build and exported into static website. Then all the integrations can be managed by CSR (Client Side Requests). This is a cost efficient and performant way to host react websites. You can host the site on S3+Cloudfront and don't have to manage any servers
For your APIs use API Gateway + AWS Lambda (Your PHP code). You can use token based authentication for your APIs and yes have to check every request if the token is valid.
To check if a user is admin or any other role you can create "groups" in AWS Cognito. Reference to create groups is below
Now what type of user can perform what type of role in your application has to be implemented in your application itself. Cognito can't help you with that part
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-user-groups.html
Related
I'm building an SAAS with a single database. Tenant in this case is called site.
I want to achieve what Stackexchange does where it has a global login as well as a stackoverflow/softwareengineering/etc login. I'm not sure how to store users. A user can have many sites and sites can have many users. The problem with designing a JoinTable is that the user roles are stored in the User table (im using Symfony3.4). I want separate roles per site/tenant.
Another problem I'm trying to figure out is how to go about logging in. I'm using oAuth2 and to login in I sinply call {{url}}/oauth/v2/token?grant_type=password&client_id=client_id&client_secret=client_secret&username=admin&password=pass. How should I make the user log in to a specific tenant/site? Do I add site_id to the query parameters?
Thanks for reading.
This question is very broad, so I'll take a stab at it.
If you are building out a network of sites, each site would ideally have it's own database. This will ensure sandboxing and the ability to easily migrate a site to it's own infrastructure if needed due to scaling or security concerns.
When dealing with user authentication, it sounds like you'll want a single secure user store that acts as the oauth2 server and each of the sites act as a Oauth client. You'll want to use the Authorization Code flow grant type in OAuth.
Essentially, a user visits Site A. Site A sees they are not logged in via the site's session. It redirects to your OAuth server which shows a login (think of the google login). Since Site A also passed in a callback url, once you've signed in, the OAuth server knows where to redirect the user, along with the valid token information. Then Site A takes that token and exchanges it for an access token on the server-side so now you've got authentication data on Site A.
If you are going to implement your own OAuth handshaking, you should utilize an existing server/client library. For PHP, you can look at the League OAuth server library, or use Laravel Passport, if you're using Laravel. There are other similar packages for other frameworks out there.
I've set up a central app (let's call this maindomain.com), where I've setup Passport. This site will be where users register to gain access to all other apps I create.
To test it out, I've followed Matt Stauffer's blog post to create a client app that will use the user data stored on maindomain.com, let's call this app1.com.
I can confirm that my callback and whatnot work fine. When you go to app1.com/login (as per my route) it redirects to maindomain.com and allows you to authorise app1.com to use your login details - beautiful.
As per Matt's post, right now it prints the token to the screen. I need to change this so that it saves to the database - I assume I should just create a column on my user's table and store it there?
I've tested the token and can access the API routes using Postman. However, because at the moment I'm creating web apps that all need to use this centralised user system, I'm not sure how I can use a login form to authorise users and allow them access to their dashboard.
If user's are logging into app1.com do I send a POST request to maindomain.com? Isn't that going to be a problem with CSRF? I've read the documentation but as this is my first venture into Oauth2 I am pretty confused.
If you want your login form to reside on app1.com, your only choice is Password Grant flow - app1.com will get user credentials and make a POST request to oauth/tokens on maindomain.com trying to get an access token. This POST request may happen in front-end or in back-end (more secure - client password will be hidden), that's up to you.
Otherwise, it sounds like your Authorization Code flow is already up and running. You could just keep redirecting users to maindomain.com (Facebook and most other OAuth2 providers choose this way), use the login form there, and then redirect back and fetch access token based on authorization code. Save that code in your app1.com database and allow users to access dashboard using that. When it expires - start the flow again.
Try watching this video by Taylor (the creator of laravel) to get going:
https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13
I created repos for both project and confirmed them working as they should:
API Server:
https://github.com/jeremykenedy/laravel-passport
API Consumer:
https://github.com/jeremykenedy/laravel-consumer
Try making protected API end-points in the routing file api.php and use token scopes if needed to further protect the API endpoints :)
Background
So I've been researching quite a bit for the past week about API's and have been reading about concepts and also programming one.
Currently I have a website which is programmed in PHP using a popular framework called Laravel. The website has a user database and users are able to log into the dashboard on my website, everything works as I want it to for my website side.
Now for the next project of my business i'm focusing on creating my mobile applications (IOS & Andriod).What I need for these mobile applications is being able to login through the application UI (not being redirected to my site with a callback URL) so they are able to view and manage the dashboard.
The method of authentication and authorization that i want to use for my application will go something like
Client asks user to login through UI
User enters credentials
Client sends a request to login to the API
The API checks if the credentials are correct
API creates a token which is stored in token database linked to user ID
API returns 200 OK with a json response or something like this
{ "token" : "OLS25usJIay81hdy81", "expiry" : 3/06/2016 14:00}
Client remembers token and expiry
Whenever a user/client makes a request such as api/v1/mystuff/orders it sends the token with the request(probably through the http headers?)
API verifies token, gets user ID and finds users orders
Questions
I know this is one hell a question and i'm not asking you people to program my entire software haha but what I need to know is
What should I use to create the API (needs to be PHP, and preferably laravel integrated)
What are some good resources to help me program my API
Is there any suggestions/changes you'd recommend?
Requirements
Username/Password authentication
Token Authorization
Login through app UI (Not on my website with a callback)
Notes
My website has a SSL cert.
Laravel is definitely a very good choice to create your API and your plan for authentication and authorization is pretty solid.
I could recommend for you to use the JSON token authentication package for Laravel https://github.com/tymondesigns/jwt-auth
You can see some tutorials here:
https://scotch.io/tutorials/token-based-authentication-for-angularjs-and-laravel-apps
https://www.sitepoint.com/how-to-build-an-api-only-jwt-powered-laravel-app/
I would also recommend this API package https://github.com/dingo/api which will save you a lot of work.
If you need some help you could watch this series https://laracasts.com/series/incremental-api-development from Laracast, which requires a subscription, but it's more than worth it.
I am new to symfony2, and i have read most of the book, it all makes perfect sense i really like the framework.
But, i am trying to achive the following:
I have a login system, this system authenticates on another site via CURL, so the users will not be in my database, a successful login depends on the response i get from an external site.
System flow is:
User enters credentials.
I CURL the external site.
If the external site accepts the credentials, i store their credentials in the database.
I log them in
So, id like to have everything symfony2 offers in therms of automatic redirection, etc etc, i would just like to set the logged in session manually.
How would i go about configuring my security.yml and how do i set the "Logged in" sessions that they set to achieve this?
I have a users entity, with all the methods they recommend in their tutorial.
First you should understand the difference between Authentication and Authorization in symfony
Then what you want is to create a custom authentication provider that will take care of finding who the user is and it's where you should do your curl requests to the other service.
After that you have to deal with Authorization, which is the part that takes care of finding if a user has the privilege of doing/access something, this is where you setup the ACL's.
If you're not storing the users in your database or in-memory but getting them for the service you should also implement a custom user provider that will grab the users from the service.
We have a social networking site where people have contacts and we want it to be integrated with XMPP. We currently use ejabberd XMPP server.
Here are my questions:
How to properly create account? Right now, what I'm thinking is on user registration on our web app, we'd call a script that would execute an ejabberd command to create a user.
User authentication. Upon user login on our website, the user would be automatically logged in on the chat system. How do you do this on the client side with strophe.js? As I understand, you need to provide JID and password for authentication, so I'm thinking that on login, there would be an ajax call to get user's password, then use the response text on strophe.js' login call. Is this secure? Are there other ways to do this?
Presence registration. Our web app has a contacts system, but XMPP has its own way of adding contacts through presence subscription, right? Example: When user1 tries to add user2, an authorization would be asked to user2 before user1 can be a contact of user2. But since we already have a contacts system on our web app, we want to bypass this authorization of XMPP or suppress it and just authorize with a script/command when user2 confirms user1 as a contact on our web site. It's not clear to me yet but a colleague said this is possible on ejabberd's module mod_admin_extra (a command that will create a subscription without having to client-side authorization). Is it possible or do I have to manipulate the ejabberd database manually with a script (provided I transferred from the default Mnesia db to another db, say MySQL).
Thanks in advance.
We (superfeedr) have a similar web app where XMPP is part of the application.
The choice we made is to not replicate the user data accross both the web app storage and the XMPP server. You can build your own authentication mechanism using the web app's data store with ejabberd, it's pretty easy. This way, you only have 1 single place where user data is stored and don't have to create ejabberd users.
By doing this, you can also login your users on the web app without knowing their password or even storing it in clear :) . The easy way is to do the session authentication (via Bosh) on the server and pass on the session id to the HTML response, as described here, by #metajack.
The 3rd part might be the trickiest, but i'm actually quite sure you can bypass this and not use the built-in "rosters"... however it may involve creating your very own component (internal or external).
Alright, here's what we did:
1) Instead of custom authentication/external authentication, we create user accounts on XMPP after a user registers.
2) The answer to this one is session attachment as Julien pointed out. We created a PHP script that would create the session and return the session ID and RID. Called through AJAX on login of user (after the document is ready).
3) As I said on a comment on Julien's post, we used mod_admin_extra. We coupled with mod_rest (w/c allows you to send stanzas/run commands REST style) to create the rosters. There is an *add_rosteritem* command on mod_admin_extra that gets called every time users create contacts on our web site.