SvelteKit and keycloak-js, code_to_token_error and invalid_client_credentials error - keycloak

I'm using keycloak-js to secure my sveltekit UI app.
<script lang="ts">
import { onMount } from "svelte";
import Keycloak from "keycloak-js";
import type { KeycloakInitOptions } from "keycloak-js";
onMount( () => {
let instance = {
url: "http://localhost:8080",
realm: "my-realm",
clientId: "my-client"
};
let keycloak = new Keycloak(instance);
let initOptions: KeycloakInitOptions = { onLoad: "login-required"
};
keycloak.init(initOptions).then(function (authenticated) {
console.info("authorized);
}).catch(function () {
alert("unauthorized");
});
}
);
</script>
I'm receiving this error on my keycloak deployed in docker.
WARN [org.keycloak.events] (executor-thread-69) type=CODE_TO_TOKEN_ERROR, realmId=..., clientId=my-client, userId=null, ipAddress=..., error=invalid_client_credentials, grant_type=authorization_code
Retrieving the token from postman works though.

Based on your error message:
WARN [org.keycloak.events] (executor-thread-69) type=CODE_TO_TOKEN_ERROR, realmId=..., clientId=my-client, userId=null, ipAddress=..., error=invalid_client_credentials, grant_type=authorization_code
it looks like Keycloak is expecting a client secret, which based on your configuration:
let instance = {
url: "http://localhost:8080",
realm: "my-realm",
clientId: "my-client"
};
infers that the client my-client is a confidential one. However, since you are using the javascript adapter, you should actually create a public client instead of a confidential one.
So change the access-type of the client my-client from confidential to public.

Related

How to tell auth0 im authenticated in req.rest file

So I want to make a post request to my nextJS backend and the route i am making the req to a protected route so in my Rest client file (req.rest) I need to tell auth0 im authenticated but i do not know how to do that.
req.rest
POST http://localhost:3000/api/video
Content-Type: application/json
Authorization: Bearer cookie
{
"title": "Video",
"description": "Video description"
}
api/video.js
import { withApiAuthRequired, getSession } from "#auth0/nextjs-auth0";
import Video from "../../database/models/Video";
export default withApiAuthRequired(async function handler(req, res) {
if (req.method === "POST") {
try {
const { user } = getSession(req, res);
const newVideo = new Video({
title: req.body.title,
description: req.body.description,
ownerId: user.sub,
});
await newVideo.save();
res.json(newVideo);
} catch (error) {
res.status(500).json({ error: error.message });
}
}
});
I'm not sure I understand your question. Your API should determine if the user is authenticated by validating the bearer token value you are passing through the Authorization request header, you shouldn't need to pass additional data as separate parameters to authorize the API. If you do need additional data to determine if the user is authorized to consume the API, that should be included inside of the bearer token as a claim.
So I haven't really found a solution but I do have a workaround which is to just make new page on the frontend for requests and send the requests from there.

How to get refresh token after authenticate via pkce flutter app with keycloak using openid_client?

I have the following KeyCloak Client config, to use pkce authentication flow:
Realm: REALM
Client ID: pkce-client
Client Protocol: openid-connect
Access Type: public
Standard Flow Enabled: ON
Valid Redirect URIs: http://localhost:4200/
Advanced Settings:
Proof Key for Code Exchange Code Challenge Method: S256
When authenticating with flutter App with iOS Simulator via openid_client
https://pub.dev/packages/openid_client like this
authenticate() async {
var uri = Uri.parse('http://$localhost:8180/auth/realms/REALM');
var clientId = 'pkce-client';
var scopes = List<String>.of(['profile', 'openid']);
var port = 4200;
var issuer = await Issuer.discover(uri);
var client = new Client(issuer, clientId);
urlLauncher(String url) async {
if (await canLaunch(url)) {
await launch(url, forceWebView: true);
} else {
throw 'Could not launch $url';
}
}
var authenticator = new Authenticator(
client,
scopes: scopes,
port: port,
urlLancher: urlLauncher,
);
var auth = await authenticator.authorize();
var token= await auth.getTokenResponse();
return token;
}
I get the following response:
How do I get a new access token with the refresh token?
I tried:
POST http://localhost:8180/auth/realms/REALM/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
client_id: pkce-client
grant_type: refresh_token
refresh_token: "received refresh token"
but I get:
{"error":"invalid_client","error_description":"Invalid client credentials"}
How do I need to prepare the request to refresh the access token?
Thanks in advance
One cause of the problem could be that you need to include the client_secret as well in the request. This might be needed if the client is a "confidential" client.
Se the discussion here for further details. Refresh access_token via refresh_token in Keycloak

Cannot authenticate via pkce flutter app with keycloak using openid_client

I have the following KeyCloak Client config, to use pkce authentication flow:
Realm: REALM
Client ID: pkce-client
Client Protocol: openid-connect
Access Type: public
Standard Flow Enabled: ON
Valid Redirect URIs: http://localhost:4200/
Advanced Settings:
Proof Key for Code Exchange Code Challenge Method: S256
I try to authenticate in a flutter App with iOS Simulator via openid_client
https://pub.dev/packages/openid_client like this
authenticate() async {
var uri = Uri.parse('http://$localhost:8180/auth/realms/REALM');
var clientId = 'pkce-client';
var scopes = List<String>.of(['profile', 'openid']);
var port = 4200;
var redirectUri = Uri.parse(http://localhost:4200/);
var issuer = await Issuer.discover(uri);
var client = new Client(issuer, clientId);
urlLauncher(String url) async {
if (await canLaunch(url)) {
await launch(url, forceWebView: true);
} else {
throw 'Could not launch $url';
}
}
var authenticator = new Authenticator(
client,
scopes: scopes,
port: port,
urlLancher: urlLauncher,
redirectUri: redirectUri,
);
var auth = await authenticator.authorize();
var token= await auth.getTokenResponse();
return token;
}
But it only gives me this web view:
The Terminal where KeyCloak is running gives me the following lines:
INFO [org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker] (default task-34) PKCE enforced Client without code challenge method.
WARN [org.keycloak.events] (default task-34) type=LOGIN_ERROR, realmId=REALM, clientId=pkce-client, userId=null, ipAddress=127.0.0.1, error=invalid_request, response_type=code, redirect_uri=http://localhost:4200/, response_mode=query
When using Postman it worked and it provided me the Login page:
But I have additional parameters there, which I do not know where to add them in Authenticator(..) when using openid_client, state is automatically added.
state: <state>
code_challenge: <code-challenge>
code_challenge_method: S256
Do I need to add these code_challenge parameters somewhere in the openid_client method?
Or do I need to change the redirect URL when using an App? I tried with the package_name like proposed here (https://githubmemory.com/repo/appsup-dart/openid_client/issues/32), but it did not work either.
See the source code:
: flow = redirectUri == null
? Flow.authorizationCodeWithPKCE(client)
: Flow.authorizationCode(client)
You have specified redirectUri, so authorizationCode flow was used. But you want authorizationCodeWithPKCE flow in this case. So just make sure redirectUri is null and correct PKCE flow (with correct url parameters, e.g. code_challenge) will be used.
You need to send the redirectUri:null and set the port to 3000 ( you can use your port ).
after that you need to add the redirect uri in keycloak like this http://localhost:3000/ .it will do the trick
(what happening is when you send the redirect uri as null value, open_id client use the pkce flow and use the default url)

How to use Amazon Cognito Logout endpoint?

I am using AWS Cognito in my application.
While doing logout i am calling the Logout Endpoint.
But after doing logout, I am still able to generate the id-tokens using the old refresh token.
It means my logout endpoint is not working any more. I am saving the tokens in my local storage, And while doing the logout i am clearing the store manually.
My Question is: How to properly use the logout mechanism of AWS
Cognito?
I'm not sure which framework you are using, but I'm using Angular. Unfortunately there are different ways of using AWS Cognito and the documentation is not clear. Here is my implementation of the Authentication Service (using Angular):
- Note 1 - With using this sign in method - once you redirect the user to the logout url - the localhost refreshes automatically and the token gets deleted.
- Note 2 - You can also do it manually by calling: this.userPool.getCurrentUser().signOut()
import { Injectable } from '#angular/core'
import { CognitoUserPool, ICognitoUserPoolData, CognitoUser } from 'amazon-cognito-identity-js'
import { CognitoAuth } from 'amazon-cognito-auth-js'
import { Router } from '#angular/router'
const COGNITO_CONFIGS: ICognitoUserPoolData = {
UserPoolId: '{INSERT YOUR USER POOL ID}',
ClientId: '{INSERT YOUR CLIENT ID}',
}
#Injectable()
export class CognitoService {
userPool: CognitoUserPool
constructor(
private router: Router
) {
this.createAuth()
}
createAuth(): void {
// Configuration for Auth instance.
const authData = {
UserPoolId: COGNITO_CONFIGS.UserPoolId,
ClientId: COGNITO_CONFIGS.ClientId,
RedirectUriSignIn : '{INSERT YOUR COGNITO REDIRECT URI}',
RedirectUriSignOut : '{INSERT YOUR COGNITO SIGNOUT URI}',
AppWebDomain : '{INSERT YOUR AMAZON COGNITO DOMAIN}',
TokenScopesArray: ['email']
}
const auth: CognitoAuth = new CognitoAuth(authData)
// Callbacks, you must declare, but can be empty.
auth.userhandler = {
onSuccess: function(result) {
},
onFailure: function(err) {
}
}
// Provide the url and parseCognitoWebResponse handles parsing it for us.
const curUrl = window.location.href
auth.parseCognitoWebResponse(curUrl)
}
/**
* Check's if the user is authenticated - used by the Guard.
*/
authenticated(): CognitoUser | null {
this.userPool = new CognitoUserPool(COGNITO_CONFIGS)
// behind the scene getCurrentUser looks for the user on the local storage.
return this.userPool.getCurrentUser()
}
logout(): void {
this.router.navigate(['/logout'])
}
}

Custom authenticator with Ember simple auth + Ember CLI

I'm trying to write a custom authenticator, similar to the one from this example in the docs. The goal is to be able to retrieve the currently logged in user via session.user.
I'm using Ember CLI, so in initializers/authentication.js I have
import Ember from 'ember';
var customAuthenticator = Ember.SimpleAuth.Authenticators.Devise.extend({
authenticate: function(credentials) {
debugger;
}
});
export default {
name: 'authentication',
initialize: function(container, application) {
Ember.SimpleAuth.Session.reopen({
user: function() {
var userId = this.get('user_id');
if (!Ember.isEmpty(userId)) {
return container.lookup('store:main').find('user', userId);
}
}.property('userId')
});
// register the custom authenticator so the session can find it
container.register('authenticator:custom', customAuthenticator);
Ember.SimpleAuth.setup(container, application, {
routeAfterAuthentication: 'landing-pages',
authorizerFactory: 'ember-simple-auth-authorizer:devise'
});
}
};
When I try to authenticate, I get the following error:
TypeError: Cannot read property 'authenticate' of undefined
at __exports__.default.Ember.ObjectProxy.extend.authenticate
Any idea why?
As of Simple Auth 0.6.4, you can now do something like:
index.html:
window.ENV['simple-auth'] = {
authorizer: 'simple-auth-authorizer:devise',
session: 'session:withCurrentUser'
};
initializers/customize-session.js:
import Ember from 'ember';
import Session from 'simple-auth/session';
var SessionWithCurrentUser = Session.extend({
currentUser: function() {
var userId = this.get('user_id');
if (!Ember.isEmpty(userId)) {
return this.container.lookup('store:main').find('user', userId);
}
}.property('user_id')
});
export default {
name: 'customize-session',
initialize: function(container) {
container.register('session:withCurrentUser', SessionWithCurrentUser);
}
};
You would need to do something like this:
Em.SimpleAuth.Authenticators.OAuth2.reopen
serverTokenEndpoint: "http://myapp.com/token"
authenticate: (credentials) ->
new Em.RSVP.Promise (resolve, reject) =>
data =
grant_type: "password"
username: credentials.identification
password: credentials.password
#makeRequest(data).then (response) =>
# success call
, (xhr, status, error) ->
# fail call
What I think might be happening is that you are registering the authenticator with the application and not the authenticator itself?
The problem is that the AMD build does not currently automatically register the extension libraries' components (see https://github.com/simplabs/ember-simple-auth/issues/198). I'll change that in the next release and will probably also adopt the documentation to be more focussed on the AMD build instead of the browserified version. For the moment you'd have to run this in your initializer
container.register(
'ember-simple-auth-authorizer:devise',
Ember.SimpleAuth.Authorizers.Devise
);
container.register(
'ember-simple-auth-authenticator:devise',
Ember.SimpleAuth.Authenticators.Devise
);