Custom React GUI for oidc-client-js - reactjs

is there a way to user your custom React GUI with oidc-client-js? I know that if you trigger authentication endpoint using:
// PopUps might be blocked by the user, fallback to redirect
try {
await this.userManager.signinRedirect(this.createArguments(state)); //Shows midleware login form
return this.redirect();
} catch (redirectError) {
console.log("Redirect authentication error: ", redirectError);
return this.error(redirectError);
}
Middleware will try to render its predefined login form:
However I have my own React form and I only need to pass to OICDClient params (email,password) and get back User instance to display UserName etc. Something like:
var loggedUser = await this.userManager.signinCustom(state.loginEmail, state.LoginPassword); //Login using credentials
I don't want to write all the logic by myself I really want to use all functionality from OIDCClient - only with my GUI (loginForm, registerForm, updateUserForm etc).
I'm using scaffolded library from MSDN using command:
dotnet new react -o <output_directory_name> -au Individual
Is there any method/implementation to initialise oidc-client-js from React components and not user default GUI forms?
Thanks a lot!

I might be missing some thing but the whole idea of using a 3rd partly federated auth provider be it your own/your company's SSO (say developed using Identity Server 4) or say Google sign in(say using their Firebase JS kit) or Microsoft sign in, Facebook sign in etc. is that you will be redirected to their authentication endpoint where you then use say your google credentials (if you are using google sign in for example) to sign on to google auth servers. Once you do that then a payload (consisting of an identity token and access token) is returned back to your redirect URL which you must configure for your specific app.
By saying you'd like to provide your own sign-in form you are missing the entire point of using a 3rd party authentication provider. Besides, you/your app shouldn't know about user names and passwords and you don't want to have access to all that information. All that you should be interested in knowing whether the user, who are using one of the federated authentication providers, that you would have configured for your app, are who they claim to be and you then delegate all that heavy lifting to your 3rd party authentication provider.
Besides, say your company has a SSO system of their own then all your company's app will use that SSO system and from a UI perspective you want to show the same login screen so as to give a consistent user experience.
In addition, if you show me a google authentication button and then on clicking that button you show me some weird form that doesn't look like the typical google picklist sign-in form then I'll shut down your app before you can say hello, and, I suspect most user would (and should) do the same. The reason being that when you show me a google sign-in page then I know that you/your app will only get back what you need and I wouldn't ever entrust my google user name and password to any other application.
If you really want to have your own authentication form then you'll have to manage user names and passwords yourself, the way we used to do things probably over 10+ years back.
If you decide to go the route of setting up your own authentication system and then say use identity server 4 then yes you can certainly change the UI and customize it to your heart's content, but that will happen at the server level, not at the level of your react app. Point being that in any SSO system the user will be redirected to the that auth provider's endpoint where they then authenticate (and, optionally, provider permission for your app to use certain claims) and once they do that they they are redirected back to your redirect endpoint with a payload (JWT token).
Lastly, even if you could some how wire up a client side sign in form, I'm not sure you would want to use it. Passing passwords & user names over the wire isn't a good idea. You'll always want to use a server rendered sign in form.

Related

IdentityServer4: How to set a role for Google user?

I have 3 applications:
An IdentityServer4 API which provides Google authentication and also provides an access token to authorize the resource API.
A simple Resource API which provides some data from DB.
A simple Client in React which have 4 buttons:
Login, for Google auth
Logout
Get data - a simple request with the access token to the Resource API and gets the data from Db
Get user data - returns user profile and token (for debug purpose)
I didn't put any sample code because my problem is not code related, it's knowledge that I'm missing and I ask for guidance.
The workflow is working just fine: the user press the Login button, it is redirected to IdentityServer4 API for Google Auth. From there it is redirected to a Callback Page from the Client and from there to the Index page. I receive the user data and the token, I can request data from the Resource API and it's working.
My problem is: How do I give a Role to the Google Users ?
I don't have users saved in DB. I want three types of Users: SuperAdmin, Admin, Viewer and each of these roles have limited Endpoints which can access.
For limiting their access I saw that I can use Claims-based authorization or Role-based authorization.
So, my question is how ca I give a Google User who wants to login in my app, a specific Claim/Role ? What is the workflow ? I must save it first in DB ? Or there exists a service from Google where I can add an email address and select a Role for that address ?
Thank you very much !
After you get the response from Google in your callback you can handle the user and do what ever you want to do with it. Below are the some typical tasks that you can do in callback that I took from documentation page of identityserver4 link:
Handling the callback and signing in the user
On the callback page your typical tasks are:
inspect the identity returned by the external provider.
make a decision how you want to deal with that user. This might be
different based on the fact if this is a new user or a returning
user.
new users might need additional steps and UI before they are allowed
in.
probably create a new internal user account that is linked to the
external provider.
store the external claims that you want to keep.
delete the temporary cookie
sign-in the user
What I would do is creating an new internal user account that is linked to the external provider and add a role to that user.
If you don't want to save users in db, you can add an extra claim to user in callback method and use that claim in token. and i think this link will help with that.

integrating custom solution with identity server

for various business reasons our login progress is basically a workflow composed out of a variable number of steps (where the ID provider login - ie google, facebook etc ) is only a very small part of the entire workflow.
we have an identity server instance set up for various 3rd party integrations (using the client credentials flow).
we have a current new requirement to expose an oauth version of our authentication flows.
i'm wondering if this is somehow supported?
in essence use identity server to validate the client and it's return url and the like - but keeping the actual act of login completely seperate.
if not - I'm guessing that we should self validate client and return url - using a custom grant to return access & refresh tokens to the 3rd party.
IdentityServer and "login application" can be separate. Unfortunately we don't have good documentation for that.
But the specs are basically
Configure the login page URL on the options in startup
We hand you a return URL to the login page
When you are done, call a custom API in the IdentityServer app that sets the sign-in cookie
redirect back to the return URL you got in the first place
As I said, right now you are pretty much on your own. But it has been done before - if you get it working, feel free to contribute that back to the docs.

how to integrate regular username/password login with 3rd party social login for a Spring Boot + Angular single page web app?

I have a Angular + Spring boot single page web app. The server also acts as an Auth Server which issues tokens for the angular app to use to make Restful API calls.
My old login flow uses a grant_type=password POST call to the /oauth/token endpoint to get a Bearer token. And all further API calls on behalf of the user will include the Bearer token as the "Authorization" http header.
Now I need to integrate social login (facebook, twitter, etc.), which means I don't have username/password to generate tokens so I'm not sure how to make it work.
I have been using the following two tutorials as my template:
Spring Security and Angular JS
Spring Boot and OAuth
In the first tutorial's oauth-vanilla example, the username passwork login flow brings up the authorization page. But I'd like to have the traditional username/password form login experience (log user in directly instead of showing the Authorization page).
In the second tutorial, after facebook login, I'd like to use the facebook id to look up my internal user database and create a new user if not exist and logs him in as the user. And use the internal db user's identity and authorities to authorize future API calls to my API server.
I have a stripped down sample at at
https://github.com/dingquan/spring-angular-oauth
I can make POST calls to /oauth/token endpoint and use the returned token to make further api calls to my protected /api/blogs endpoint. But I haven't figure out how to make the following things work:
Username/password login that will create a session cookie so I don't need to send the Authorization bearer token for future API calls to the resource endpoint
After facebook login (the facebook login link is under the username/password login form), calls to my endpoint still fails with 401 error (I have a "test" button that makes a get call to /api/blogs, you can click on it to see the behavior). So what am I missing to make the API call succeed?
=== UPDATE ===
Just to clarify. Here are the goals I'm trying to achieve:
multiple ways of authentication (traditional username/password, third party oauth login such as facebook, possibly cellphone number + SMS code in the future)
we do need our own user model backed by DB to store other user attributes, pure social login is not enough
social login needs to be implicit. Meaning user should not be required to create a user account in our system manually once they login through a 3rd party (facebook, etc.). We're not just grabbing users' social profile data to pre-populate the registration form. We want to create new DB users automatically behind the scene if no existing db user is associated with the given external social account. i.e. if user is logged in through facebook, they don't need to enter username/password. Authentication through facebook will automatically log the user into our system as well and user should be able to access restricted resources after facebook login.
There's some confusion that I might be asking people to put their facebook username/password in a login form hosted by my app and I'll login facebook on behalf of the user. That's not what I was asking for.
You don't need such a complicated configuration. Add #EnableOAuth2Sso to your MainConfiguration and set appropriate application properties.
Here is what I have done in order to use Facebook as a authorization server.
a) Remove clientId and authServer from UserServiceImpl. Otherwise you'll be forced to configure an authorization server that is not needed.
b) Remove AuthorizationServerConfiguration completely.
c) Add #EnableWebSecurity and #EnableOAuth2Sso to your MainConfiguration.
d) Change MainConfiguration::configure to
http
.logout().logoutSuccessUrl("/").permitAll().and()
.authorizeRequests().antMatchers("/", "/login", "/home.html").permitAll()
.anyRequest().authenticated()
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
e) Delete everything else except nested class AuthenticationSecurity from MainConfiguration.
f) Change ResourceServerConfiguration::configure(HttpSecurity) to
http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated();
f) Remove attribute tokenStore and method ResourceServerConfiguration::configure(ResourceServerSecurityConfigurer) from ResourceServerConfiguration.
g) Remove configuration block security and facebook from application.yml. Instead add this
security:
oauth2:
client:
client-id: <CLIENT_ID>
token-name: oauth_token
authentication-scheme: query
client-authentication-scheme: form
access-token-uri: https://graph.facebook.com/oauth/access_token
user-authorization-uri: https://www.facebook.com/dialog/oauth
resource:
user-info-uri: https://graph.facebook.com/me
client-id: <CLIENT_ID>
client-secret: <CLIENT_SECRET>
token-type: code
h) In index.html change login to login.
i) Replace the content of hello.js with this one.
But I'd like to have the traditional username/password form login experience (log user in directly instead of showing the Authorization page).
I would never use a site that requires my credentials without redirecting me to the origin! I don't know you and you are under suspicion being a phishing site.
You should really reconsider your decision.
Btw, I created a pull request with these changes.

Restricting API Calls to a Certain Domain

My app uses JS Facebook API to use Facebook as a login/pass. Here what happens when you try to login.
User click on the Facebook Login Button
Facebook Authenticates
If Success. I grab the Facebook ID and Name of the user
Calls on my REST API on my APP to check and see if the that FBID is registered in my system.
If Registered, I write the session to verify that the user is authenticated.
This is great since I don't have to store usernames and password. But I am worried that someone will just use a REST API debugger like POSTMAN in chrome and just send a Facebook ID and the name of the user and they will be authenticated.
My question is what is the best way to secure my end that will prevent apps like POSTMAN to just input the fields needed to authenticate? Am I missing something? Can anyone recommend a strategy for this?
Or is using CSRF token the only way to combat this? I am using FuelPHP as a backend and doing a single page app using AngularJS with NgRoutes. But every time I enabled the CSRF on fuel, the token passed does not match what it was in the back-end.
I am under the impression that this is due to that the javascript token function is in the main page, where the ng-view. I know this might have something to do with the ngRoutes.
http://fuelphp.com/docs/classes/security.html
Use Fuel's Auth package. It has Opauth integration which does all the above, and for an entire list of social media platforms, not only facebook.
Always try not to reinvent the wheel, assume someone else has had the same challenge, solved at, and shared the solution with the community.

AngularJS recover user session - cookies or token

I'm developing an AngularJS app used by third part applications. The third part application and my AngularJS application have a common database where users preferences/credentials are stored. User can login from the third part application and, by redirecting the user into my application, I need to maintain the user logged in, without asking a new authentication procedure.
I can't use cookies because the two applications are in two different domains.
I can't pass a session TOKEN (correspondant to the user logged iin) in query parameters due to man in the middle risks.
Is it possible to make a POST request to an angularJS page? Third part app call my AngularJS login page POSTing a token in the body request. My app take the token, verifyies it and log-in the user.
Constraints:
App in different domains;
Maintain user logged in;
No sharing cookies;
Try to prevent man in the middle;
No query parameters;
HTTPS protocol;
web based applications.
Am I missing something in the https protocols/sharing sessions?
Are there other solutions supported by AngularJS?
How can I redirect the user from one application to another and maintaining the user logged in in a simple way? Is there a simple flow I haven't figured out?
AngularJS is based on REST api communications. I can ask for a webpage (GET the webpage), but I can't make a POST to an AngularJS page. Is there a way to pass/share some values from the first application to my second app in a secure way?

Resources