Keycloak.js can not get access token when login with Google and Facebook - keycloak

I'm build a system for our company using Keycloak. I use keycloak.js for by-pass default login page of Keycloak.
function myFunction() {
let kcLogin = keycloak.login;
keycloak.login = (options) => {
options.idpHint = 'facebook';
kcLogin(options).then(auth => {
alert("keycloak Login");
if(auth) {
alert("token" + kc.token);
} else {
alert("auth is null");
}
});
};
keycloak.init({ onLoad: 'login-required' }).then(function(authenticated) {
alert(authenticated ? 'authenticated' : 'not authenticated');
}).catch(function() {
alert('failed to initialize');
});
}
But I can NOT get access token / refresh token after login.
I check: keycloak.token = undefined.
Please help me!
PS: I always get exception of keycloak.init then redirect to facebook login ( or google login )
alert('failed to initialize');
Thank you so much.
Code here: https://github.com/loizenai/SpringBoot-Keycloak-Social-Authentication-Py-Pass-Default-Login/tree/main/SpringBootKeyCloakSocialSignIn

You are trying to configure your backend and frontend with Keycloak.
Either you just have to configure your backend to integrate with your keycloak or Integration your frontend application and your backend will only verify the token.
The current application architecture you are following is an MVC pattern.
Where your spring boot(backend) application controls the integration with Keycloak.
Please refer to this article: Secure spring boot 2 using Keycloak
What you are trying to target follows this kind of architecture pattern:
Secure Vue.js apps with Keycloak | DevNation Tech Talk
In the above reference, I have used the Vue application but you can use your vanilla html/js application as well to integrate with keycloak.
First, try keycloak login flow in your application and then you can enable social login.

Related

Keycloak frontend and backend clients

This is related to keycloak clients. My frontend is connected to public client and backend is connected to confidential client.
I am able to login, get the code, as I am using response_type=code by turning on "Standard Flow Enabled".
This code redirects and returns me Idtoken, refreshtoken and token.
Now I need to communicate with backend which is confidential, I would like to authenticate user using some of the values which I have received from the frontend client.
How can I do that?
Here is my frontend and backend conf
FRONTEND
{
"realm": "xyz",
"auth-server-url": "http://localhost:8333/auth/",
"ssl-required": "external",
"resource": "frontend-app",
"public-client": true,
"confidential-port": 0,
"enable-cors": true
}
BACKEND
keycloak.auth-server-url=http://localhost:8333/auth
keycloak.realm=xyz
keycloak.resource=backend-app
keycloak.principal-attribute=preferred_username
keycloak.bearer-only=true
keycloak.credentials.secret=xxx-xxx-xxx
this is from realm setting
This might help somebody.
My backend service which is springboot project with spring security keycloakAuthenticationProvider does authenticate the token received from the frontend public client.
Call from frontend
axios({
method: 'GET',
url: '/api/authenticate',
headers:{'Authorization': 'Bearer '+keycloak.token+''}
}).then((r) => {
console.log("response",r)
})
Call to backend
#GetMapping("/api/authenticate")
public ResponseEntity<SecureUserDto> authenticate() {
String username = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
User user = userRepository.findWithPrivilegesByUsername(username);
return ResponseEntity.ok();
}
But i still was not able to get it right on postman at ../token end point provided by keycloak server.
Anyways my work is done.

.Net Core Web API Bearer The issuer is invalid

I have written a Blazor WASM app based on the latest Microsoft template. In development mode it all works great but after publishing it to Azure App Service I randomly get a 401 unauthorised when calling the API, looking at the returned headers I get
WWW-Authenticate: Bearer error="invalid_token", error_description="The issuer 'https://*domain*.azurewebsites.net' is invalid"
This is when the client is using the https://domain.azurewebsites.net client. So it matches the web API.
I also have a custom domain attached to the app service, this means there is also https://www.domain.co.uk and https://domain.co.uk both are SSL'd.
I have checked the JWT token and it contains the correct URL for the version of the website I am calling.
Sometimes everything works but 60% of the time it allows the user to login and then fails on the API calls. I can't seem to track it to 1 domain name or pattern like expired logins. If you log out and then log back in, it doesn't clear the issue.
The configure looks like this
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
Any help or hints in the right direction is appreciated
Cheers
Dave
In my case it was caused by Linux environment of App Service. Now documentation has a clear note on that:
For Azure App Service deployments on Linux, specify the issuer explicitly in Startup.ConfigureServices.
This is how I set it:
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
options.Authority = "https://my-site.azurewebsites.net";
#if DEBUG
options.Authority = "https://localhost:5001";
#endif
});

How to get JWT token for current Liferay session

I have configured Liferay v7.3.4 CE to authenticate with AWS Cognito using OpenID Connect Provider, and that all works fine.
I would now like to invoke REST APIs in AWS, from within Liferay, using the JWT token obtained from Cognito during the sign-in process.
It would seem this JWT token should be available within Liferay, correct? If so, a source code example demonstrating how to access this would be very much appreciated.
This token would then be added to the Authorization header of API calls to an instance of the AWS API Gateway secured by the same Cognito instance from which the user has just signed in. But first things first... how would someone programmatically access the JWT token for the current Liferay session?
Hope this makes sense.
I've got this working.
First, I am using Maven (not gradle) to build Liferay projects. To this end, I've added the following to my portlet's pom.xml file:
<dependency>
<groupId>com.liferay</groupId>
<artifactId>com.liferay.portal.security.sso.openid.connect.api</artifactId>
<scope>provided</scope>
</dependency>
Next, in my portlet's render method, I've added the following code:
public void render(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException
{
try {
// get the jwtToken from the renderRequest parameter
String jwtToken = null;
HttpSession session = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(renderRequest)).getSession();
if (session.getAttribute(OpenIdConnectWebKeys.OPEN_ID_CONNECT_SESSION) instanceof OpenIdConnectSession) {
OpenIdConnectSession openIdConnectSession = (OpenIdConnectSession) session.getAttribute(OpenIdConnectWebKeys.OPEN_ID_CONNECT_SESSION);
jwtToken = openIdConnectSession.getAccessTokenValue();
}
// call a REST API with the jwt token
List<Organization> organizations = masterDataClient.fetchOrganizations(jwtToken);
// do other stuff
super.render(renderRequest, renderResponse);
} catch (Exception e) {
throw new PortletException(e);
}
}

How to add policy to Keycloak - UI crashes

I'm trying to enable flow when some admin user by some admin client is able to create users and obtain their access tokens to be used for another clients.
I have KeyCloak setup with token exchange and fine grained authz enabled and configured clients. I'm able to login my admin user by REST api, then exchange token. But when I specify audience I got error.
This one returns token but I need token for another client/audience.
http -f POST https://my-keycloak-server.com/auth/admin/realms/my-realm/protocol/openid-connect/token grant_type=urn:ietf:params:oauth:grant-type:token-exchange requested_subject=1a147915-53fe-454d-906a-186fecfa6974 client_id=api-admin client_secret=23a4ecbe-a9e8-448c-b36a-a45fa1082e6e subject_token=eyJhbGeiOiJSUzI1NiIs......
This one is failing with error.
http -f POST https://my-keycloak-server.com/auth/admin/realms/my-realm/protocol/openid-connect/token grant_type=urn:ietf:params:oauth:grant-type:token-exchange requested_subject=1a147915-53fe-454d-906a-186fecfa6974 client_id=api-admin client_secret=23a4ecbe-a9e8-448c-b36a-a45fa1082e6e subject_token=eyJhbGeiOiJSUzI1NiIs...... audience=my-another-client
{
"error": "access_denied",
"error_description": "Client not allowed to exchange"
}
So I tried to setup fine grained auth for target audience client (enabled it in tab, then tried to add policy for my admin user to be able to exchange token) but when I want to add policy that will allow my admin user to perform token exchange I'm stuck on UI error.
When typing policy name I got 404 when Keycloak is looking for name colisions. Afaik 404 in this case shouldn't block form from posting because it is no name collision. Instead I got instantly redirected with error.
https://my-keycloak-server.com/auth/admin/realms/my-realm/clients/1bafa9a4-f7e2-422c-9188-58ea95db32ef/authz/resource-server/policy/search?name=some-name
In the end of the day I can't add any policy in Keycloak. All the time form validation is ending up with crash caused by 404 policy name not found.
I'm using dockerized keycloak 10.0.0
Any ideas?
I hacked it by live editing Angular JS UI script function that performs verification in line 2403.
this.checkNameAvailability = function (onSuccess) {
if (!$scope.policy.name || $scope.policy.name.trim().length == 0) {
return;
}
ResourceServerPolicy.search({
realm: $route.current.params.realm,
client: client.id,
name: $scope.policy.name
}, function(data) {
if (data && data.id && data.id != $scope.policy.id) {
Notifications.error("Name already in use by another policy or permission, please choose another one.");
} else {
onSuccess();
}
});
}
to
this.checkNameAvailability = function (onSuccess) {
onSuccess();
}
And that end up with successfuly added policy. Still looks like it's UI bug.

invalid Client for exchange code _ identityserver3 _ AppAuth

I'm using AppAuth framework for authentication in my Swift app, I can login but after login and coming back to my app, I can't exchange the code and get error invalid client.
My client configuration is:
var client = new Client
{
ClientId = "IOS.Client",
ClientName = "IOS Client",
RedirectUris = { "com.mysite.accounts:/oauthredirect" },
AllowedGrantTypes = GrantTypes.Code, //AuthorizationCode
AllowedScopes = { "openid", "profile", "offline_access" },
};
I set ClientSecret (SHA-256) and my ClientId is ok but I get error invalid client.
I checked my logs and there is an error: secret validators could not validate secret
what's wrong?
IIRC in IS3 you had to set a client secret. We didn't allow empty ones.
Either you set a secret on client and server, or upgrade to IS4 - IS3 is deprecated since quite some time.
When using IdentityServer3 and AppAuth you should not use special characters in ClientSecret and set your grant AuthorizationCodeWithProofKey.
this link is useful