I'm new to keycloak and was trying to setup a role based authentication using keycloak
with Nodejs but each time I login with my correct username and password which do exist in realm I get this bearer-only grant issue. I have tried all of the solutions and even checked if the access type on Keycloak is Bearer-only but no that is confidential tried setting the bearer-only to true and false as well but nothing worked for me
{
"realm": "realm_name",
"auth-server-url": "Keycloak_auth_url",
"ssl-required": "none",
"resource": "resource",
"verify-token-audience": false,
"public-client":true,
"grant_type":"password",
"credentials": {
"secret": secret_credentials
},
"confidential-port": 0,
"policy-enforcer": {},
"scope":"openid"
}
This is my keycloak.json file
app.get("/", keycloak.protect(), function (req, res) {
console.log(req)
}
)
This is my simple function for protecting a route
You configured your client to use password grant, which doesn‘t use an authentication code. Using this grant, the client gets an access token and optional a refresh token by posting it‘s clients credentials together with the resource owners credentials to the authorization server.
Depending on the type of application that your client is, choose an according grant type.
Nevertheless password grant shouldn’t be used at all, a recent update of the OAuth 2.0 current best practices stated. See https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-18
Related
I am looking for the help regarding the linking of ADFS with GitLab. Their documentation mentiones only setup with Google and Okta, but no ADFS which makes me crazy. The AD is running at Windows Server 2019, but, I have no access to it since it runs at other organization. Also, I don't have a test account of whatever, I can't test any changes. I'm keeping guessing for 3 days already. The target is to provide an access to Gitlab hosted at our company for our customer, but, with their AD SSO. We need to provide access from both SSOs, ours and customer's.
I have succesfully implemented SSO login from ours Keycloak using OAuth, it is completely fine.
Then, we sent the next data to the admin of customer, like:
ID: https://git.#####.net/
· ReplyURL / Ressource: https://git.########.net/users/auth/openid_connect/callback
· Protocol: OIDC https://docs.gitlab.com/ee/administration/auth/oidc.html#keycloak
· Applikationstyp: Web App
· Claims / Rules: “openid”, “profile”, “email”
Federation Metadata: Nein
Later, from the admin of customer I received back the link to JWKS Keys, Federation Metadata XML, and link to .well-known configuration and UserID that ADFS generates. But, I tried to setup OAuth using ID and link, and I felt like the secret is missing. I was getting "token expired or invalid, and in logs DiscoveryFailed(NotFound). That's why I decided to try SAML instead.
So, the questions:
is it not possible to have two OAuth at once, right?
is it possible to setup OAuth without of secret?
if it's not possible, how do I setup SAML at GitLab correctly?
Which certificate fingerprint should I use, encryption or signature?
which claims and other things must be set in trust in ADFS?
is target URL right?
what else do I miss?
The current configuration looks like this:
gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect', 'saml']
gitlab_rails['omniauth_block_auto_created_users'] = false
gitlab_rails['omniauth_auto_link_saml_user'] = true
gitlab_rails['omniauth_providers'] = [
{
name: "openid_connect",
label: "##### Login", # optional label for login button, defaults to "Openid Connect"
args: {
name: "openid_connect",
scope: ["openid", "profile", "email"],
response_type: "code",
issuer: "https://user.###########.at/auth/realms/########",
client_auth_method: "query",
discovery: true,
uid_field: "preferred_username",
client_options: {
identifier: "#######-gitlab",
# secret: "<YOUR CLIENT SECRET>",
redirect_uri: "https://git.########.net/users/auth/openid_connect/callback"
}
}
},
{
name: "saml",
label: "###### Login", # optional label for login button, defaults to "Saml"
args: {
assertion_consumer_service_url: "https://git.#####.net/users/auth/saml/callback",
idp_cert_fingerprint: "AF:92:5D:AD:DF:4A:7F.....",
idp_sso_target_url: "https://sts.#########.at/adfs/ls",
issuer: "https://git.#####.net/",
name_identifier_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
}
}
]
I have extracted idp_cert_fingerprint from both certificates present at XML files.
I am not sure if claim is right, so, I would appreciate any help regarding configuring of these thing. What should I do to make it run?
Thank you!
I am building a CLI tool and want to create a new programmatic user for each end user.
I.e. Joe Bloggs signs up with username and password but also has a client_id and client_secret which can be used in the CLI.
Is it possible to create this kind of user in Auth0 and if so, how can I create it programmatically?
It looks like I can use this to create users via the API and do something like:
axios({
method: "POST",
baseUrl: "https://<tenant>.eu.auth0.com,
uri: "/api/v2/users",
body: {
"email": "john.doe#gmail.com",
"phone_number": "+199999999999999",
"user_metadata": {},
"blocked": false,
"email_verified": false,
"phone_verified": false,
"app_metadata": {},
"given_name": "John",
"family_name": "Doe",
"name": "John Doe",
"nickname": "Johnny",
"picture": "https://secure.gravatar.com/avatar/15626c5e0c749cb912f9d1ad48dba440?s=480&r=pg&d=https%3A%2F%2Fssl.gstatic.com%2Fs2%2Fprofiles%2Fimages%2Fsilhouette80.png",
"user_id": "abc",
"connection": "Initial-Connection",
"password": "secret",
"verify_email": false,
"username": "johndoe"
}
})
However, this appears to be for creating an end user: Create a new user for a given database or passwordless connection. as opposed to a CLI type user which can use a client_id / secret.
Does anybody know if I can create this kind of user in Auth0?
The client_id and client_secret that Auth0 issues to Applications (known in the API as /Clients) are for machine-to-machine interactions with Auth0, not with your own service. They allow a trusted backend service to manage the users within Auth0. Or, they allow an Application to initiate a user's OAuth2 authentication flow.
It sounds like you are looking to avoid an OAuth2 authentication flow and provide a static API key, not for Auth0, but for your own service. Auth0 may be overkill in this case, but you can roll your own solution using Auth0, or any user store. One suggestion is to manually generate an API token for new Auth0 users and store them in the users' app_metadata. When your CLI provides a username and API key to your backend service, your trusted backend service can use its Auth0 client_id and client_secret look up the user in Auth0 and confirm that the API key in the app_metadata matches.
Also note the existence of the Resource Owner Password Flow. It would allow your CLI to provide a username and password directly to Auth0 on behalf of your CLI user. The API token that you generate can be set as the user's password.
EDIT : I've set a server on a vm, without Docker, and everything worked well, it looks like VM+Docker is too much layer.
I have a node backend, with a route protected with :
app.get('/api/user', keycloak.protect(), function(req, res) {
res.json({ message: 'This is an USER endpoint payload' });
});
I have this keycloak.json :
{
"realm": "MyRealm",
"auth-server-url": "http://keycloak.com:8008/auth/",
"ssl-required": "none",
"resource": "sso_agt",
"public-client": true,
"confidential-port": 0
}
When I use this route, i'm redirected to the auth page. When i'm logged, it redirects me to the right url, but I have denied access, with this error in npm console :
Could not obtain grant code: Error: Unable to refresh with expired refresh token
In my keycloak console, i have a WARN type=CODE_TO_TOKEN_ERROR
I run keycloak with docker, on a Ubuntu Server VM.
Refresh tokens are no-expiration passwords, when combined with the clientId and client service allow for the generation of actual access tokens. Once a refresh token is marked as invalid, there is no way to get a new one without navigating the user through implicit login flow with the scope: offline set.
I've set a server on a vm, without Docker, and everything worked well, it looks like VM+Docker is too much layer.
First I'm describing how I setup my applications then I will describe how I'm using the APIs.
Setup
In my Azure Active Directory, I have two applications registered: UI and Backend
UI has the client ID clientId1 and backend has client ID clientId2 (it's a GUID, but for simplicity)
Both are under the same tenant tentant1 (single tenant)
Backend (Web API)
Backend has an exposed API with scope "api://clientId2/access_as_user" and authorized client "clientId1" with the scope just mentioned selected
I'm using passport and passport-azure-ad (I pretty much copied https://github.com/Azure-Samples/active-directory-javascript-nodejs-webapi-v2).
My config:
const config = {
identityMetadata: "https://login.microsoftonline.com/tenant1/v2.0/.well-known/openid-configuration",
clientID: "clientId2",
validateIssuer: false,
loggingLevel: 'info',
passReqToCallback: false,
loggingNoPII: false
};
I get this message when starting the server:
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":16052,"level":40,"msg":"Production environments should always validate the issuer.","time":"2020-04-11T13:25:44.283Z","v":0}
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":16052,"level":30,"msg":"In BearerStrategy constructor: created strategy with options {\"identityMetadata\":\"https://login.microsoftonline.com/tenant1/v2.0/.well-known/openid-configuration\",\"clientID\":\"clientId2\",\"validateIssuer\":false,\"loggingLevel\":\"info\",\"passReqToCallback\":false,\"loggingNoPII\":false,\"clockSkew\":300,\"allowMultiAudiencesInToken\":false,\"audience\":[\"clientId2\",\"spn:clientId2\"]\"isB2C\":false,\"_isCommonEndpoint\":false}","time":"2020-04-11T13:25:44.285Z","v":0}
Listening on port 5000
UI (Angular SPA)
UI has permissions was granted automatically permission to access Microsoft Graph (profile, user.read, user.read.all -- last one I think I granted). The permissions are in "API permissions"
I went ahead and also granted access to the Backend access_as_user
For the UI code I'm using the MSAL library and again I pretty much copied the repo (https://github.com/Azure-Samples/active-directory-javascript-singlepageapp-angular)
In the protectedResourceMap field I added the following
['https://graph.microsoft.com/v1.0/me', ['user.read']],
['http://localhost:5000', ['api://clientId2/access_as_user']],
I am able to log in and read my user profile, but when trying to access http://localhost:5000/hello (protected), I'm getting the error the title of this question
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":20720,"level":30,"msg":"authentication failed due to: jwt audience is invalid","time":"2020-04-11T13:38:08.700Z","v":0}
--
I can see the Bearer Token coming (in the UI and backend), the server decodes the token (I can see all my profile info in the server logs), but it's saying the JWT is invalid?!
I'm not defining an audience, yet I can see in the token when it gets decoded the audience with aud: 'api://clientId2'.
I can also see when the backend starts it shows the audience as [clientId2, sps:clientId2] by default (step4 on the backend). When I define in the config audience: 'api://clientId2', I get a 403 with the message:
{"name":"AzureAD: Bearer Strategy","hostname":"DESKTOP-NCVLN56","pid":12644,"level":30,"msg":"In Strategy.prototype.jwtVerify: We did not pass Req back to Callback","time":"2020-04-11T16:19:30.398Z","v":0}
Any help would be appreciated. Thank you.
Turns out their code in the repository is not using proper configuration to verify the scope access...
https://github.com/Azure-Samples/active-directory-javascript-nodejs-webapi-v2/blob/master/index.js#L41
if (req.authInfo['scp'].split(" ").indexOf("demo.read") >= 0) {
I needed to change the scope from "demo.read" to "access_as_user".
In my case it was just that the clock of my VM where the application was running on was 15mins behind. So the time of the token was created was in the future...
I am trying to implement a Node.js client application authenticating against Keycloak, and using an external IDP, using the keycloak-nodejs-connector. I have been following the documentation located here for using it.
However, after authenticating, the client application throws the error: "Cannot exchange code for grant in bearer-only mode". This is confusing me because the client is not configured for bearer-only mode, it is configured for confidential mode.
The client application is successfully redirecting me to the external IDP where I am able to log in. If I look in the Keycloak admin console, I also see an active session for myself after logging in. However, the client application still throws the error.
Here is my client configuration pulled from the Keycloak admin console:
{
"realm": "master",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "local",
"verify-token-audience": true,
"credentials": {
"secret": "redacted"
},
"use-resource-role-mappings": true,
"confidential-port": 0
}
Here is the implementation in my app.js file for Node:
var Keycloak = require('keycloak-connect');
let keycloakMiddleware = new Keycloak({idpHint: 'SSO'});
app.use( keycloakMiddleware.middleware() );
app.get( '/', keycloakMiddleware.protect(), complaintHandler);
I have keycloak.json in the same directory as app.js and it is picking up the above client configuration details.
I ran into the same problem. What I figured out is that when constructing the Keycloak instance, you have to either set cookies=true, or pass in a session store. So one of these:
const session = require('express-session');
const store = new session.MemoryStore();
const keycloakMiddleware = new Keycloak({ idpHint: 'SSO', store });
or
const keycloakMiddleware = new Keycloak({ idpHint: 'SSO', cookies: true });
If you choose the latter, you'll also need to use cookie-parser or something like it. And either way, you need to use express-session, as far as I can tell.
app.use(require('cookie-parser')); // only if using cookies=true, i think
app.use(session({ secret }));
app.use(keycloakMiddleware.middleware());