Skip to content

Commit 76d4dbd

Browse files
authored
v3 (#12)
* removing babel * excluding local resources * updating documentation * updating examples * upgrading implementation
1 parent 03bf52a commit 76d4dbd

17 files changed

+165
-200
lines changed

.babelrc

Lines changed: 0 additions & 12 deletions
This file was deleted.

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,8 @@ typings/
6060
# transpiled sources
6161
src/
6262

63-
.DS_Store
63+
.DS_Store
64+
65+
*.pem
66+
67+
local

README.md

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# keycloak-backend
22
Keycloak Node.js minimalist connector for backend services integration. It aims to serve as base for high performance authorization middlewares.
33

4-
> Note: Version 2.x uses `jsonwebtoken 8.x`
4+
> In order to use this module, the used Keycloak client `Direct Access Grants Enabled` setting should be `ON`
55
66
## Keycloak Introduction
77
The awesome open-source Identity and Access Management solution develop by RedHat.
@@ -22,69 +22,54 @@ Keycloak support those very nice features you are looking for:
2222
More about Keycloak: http://www.keycloak.org/
2323

2424
## Using the keycloak-backend module
25-
### Instantiating
25+
### Configuration
2626
```js
2727
const keycloak = require('keycloak-backend')({
28-
"realm": "your realm name",
29-
"auth-server-url": "http://keycloak.dev:8080",
30-
"client_id": "your client name",
31-
"client_secret": "c88a2c21-9d1a-4f83-a18d-66d75c4d8020", // if required
32-
"username": "your service username",
33-
"password": "your service password"
28+
"realm": "realm-name",
29+
"keycloak_base_url": "https://keycloak.example.org",
30+
"client_id": "super-secure-client",
31+
"username": "[email protected]",
32+
"password": "passw0rd",
33+
"is_legacy_endpoint": false
3434
});
3535
```
36+
> The `is_legacy_endpoint` configuration property should be TRUE for older Keycloak versions (under 18)
3637
37-
### Validating access tokens
38-
#### Online validation:
39-
This method requires online connection to the Keycloak service to validate the access token. It is highly secure since it also check for the possible token invalidation. The disadvantage is that a request to the Keycloak service happens on every validation attempt.
38+
### Generating access tokens
4039
```js
41-
let token = await keycloak.jwt.verify(someAccessToken);
42-
//console.log(token.isExpired());
43-
//console.log(token.hasRealmRole('user'));
44-
//console.log(token.hasApplicationRole('app-client-name', 'some-role'));
40+
const accessToken = await keycloak.accessToken.get()
4541
```
46-
47-
#### Offline validation:
48-
This method perform offline JWT verification against the access token using the Keycloak Realm public key. Performance is higher compared to the online method, the disadvantage is that access token invalidation will not work until the token is expired.
49-
```js
50-
let cert = fs.readFileSync('public_cert.pem');
51-
token = await keycloak.jwt.verifyOffline(someAccessToken, cert);
52-
//console.log(token.isExpired());
53-
//console.log(token.hasRealmRole('user'));
54-
//console.log(token.hasApplicationRole('app-client-name', 'some-role'));
55-
```
56-
57-
### Generating service access token
58-
Efficiently maintaining a valid access token can be hard. Get it easy by using:
42+
Or:
5943
```js
60-
let accessToken = await keycloak.accessToken.get()
61-
```
62-
Then:
63-
```js
64-
request.get('http://serviceb.com/v1/fetch/accounts', {
44+
request.get('http://service.example.org/api/endpoint', {
6545
'auth': {
6646
'bearer': await keycloak.accessToken.get()
6747
}
6848
});
6949
```
70-
> For this feature, the authentication details described in the configuration options are used.
71-
72-
### Retrieve users information by id
73-
Sometimes backend services only have a target user identifier to digg for details, in such cases, you can contact the Keycloak service by:
7450

75-
#### Retrieve user details by id
51+
### Validating access tokens
52+
#### Online validation
53+
This method requires online connection to the Keycloak service to validate the access token. It is highly secure since it also check for possible token invalidation. The disadvantage is that a request to the Keycloak service happens on every validation:
7654
```js
77-
let details = await keycloak.users.details(uid);
55+
const token = await keycloak.jwt.verify(accessToken);
56+
//console.log(token.isExpired());
57+
//console.log(token.hasRealmRole('user'));
58+
//console.log(token.hasApplicationRole('app-client-name', 'some-role'));
7859
```
7960

80-
#### Retrieve user roles by id
61+
#### Offline validation
62+
This method perform offline JWT verification against the access token using the Keycloak Realm public key. Performance is higher compared to the online method, as a disadvantage no access token invalidation on Keycloak server is checked:
8163
```js
82-
let details = await keycloak.users.roles(uid, [
83-
// clients id here for roles retrieval
84-
],
85-
true // include realm roles ?
86-
);
64+
const cert = fs.readFileSync('public_cert.pem');
65+
const token = await keycloak.jwt.verifyOffline(accessToken, cert);
66+
//console.log(token.isExpired());
67+
//console.log(token.hasRealmRole('user'));
68+
//console.log(token.hasApplicationRole('app-client-name', 'some-role'));
8769
```
8870

89-
## Tests
90-
WIP
71+
## Breaking changes
72+
### v3
73+
- The `UserManager` class was dropped
74+
- The `auth-server-url` config property was changed to `keycloak_base_url`
75+
- Most recent Keycloak API is supported by default, old versions are still supported through the `is_legacy_endpoint` config property

example/index.js renamed to example/all.js

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,34 @@
1-
const config = require('./config-example')
2-
const keycloak = require('./../index')(config)
1+
const config = require('../local/config-example')
2+
const keycloak = require('../libs/index')(config)
33
const fs = require('fs');
44

55
(async () => {
66
try {
7-
const someAccessToken = await keycloak.accessToken.get()
7+
// current version of Keycloak requires the openid scope for accessing user info endpoint
8+
const someAccessToken = await keycloak.accessToken.get('openid')
89
// how to get openid info from access token...
910
// info.sub contains the user id
1011
const info = await keycloak.accessToken.info(someAccessToken)
12+
console.log(info)
1113

1214
// verify token online, intended for micro-service authorization
1315
let token = await keycloak.jwt.verify(someAccessToken)
1416
console.log(token.isExpired())
15-
// console.log(token.hasRealmRole('user'))
16-
// console.log(token.hasApplicationRole('nodejs-connect', 'vlm-readonly'))
17+
console.log(token.hasRealmRole('user'))
18+
console.log(token.hasApplicationRole('nodejs-connect', 'vlm-readonly'))
1719

1820
// verify token offline, intended for micro-service authorization
1921
// using this method does not consider token invalidation, avoid long-term tokens here
20-
const cert = fs.readFileSync('public_cert.pem')
22+
const cert = fs.readFileSync('./local/public_cert.pem')
2123
token = await keycloak.jwt.verifyOffline(someAccessToken, cert)
2224
console.log(token.isExpired())
2325
// console.log(token.hasRealmRole('user'))
2426
// console.log(token.hasApplicationRole('nodejs-connect', 'vlm-readonly'))
2527

2628
// how to manually refresh custom access token
2729
// (this operation is performed automatically for the service access token)
28-
token = await keycloak.accessToken.refresh(someAccessToken)
29-
console.log(token.isExpired())
30-
31-
// how to get user details given the user id
32-
const [details, roles] = await Promise.all([
33-
keycloak.users.details(info.sub),
34-
keycloak.users.roles(info.sub)
35-
])
36-
console.log(details, roles)
30+
const response = await keycloak.accessToken.refresh(keycloak.accessToken.data.refresh_token)
31+
console.log(response.data)
3732
} catch (err) {
3833
console.log(err)
3934
}

example/config-example.json

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
{
2-
"realm": "myrealm",
3-
"auth-server-url": "http://keycloak.dev:8080",
4-
"client_id": "nodejs-connect",
5-
"client_secret": "c88a2c21-9d1a-4f83-a18d-66d75c4d8020",
6-
"username": "user",
7-
"password": "password",
8-
"clients": [
9-
"0448d03b-cb1a-4295-9c3d-c4099b934062"
10-
]
2+
"realm": "realm-name",
3+
"keycloak_base_url": "https://keycloak.example.org",
4+
"client_id": "super-secure-client",
5+
"username": "[email protected]",
6+
"password": "passw0rd",
7+
"is_legacy_endpoint": false
118
}

example/public_cert.pem

Lines changed: 0 additions & 10 deletions
This file was deleted.

example/refresh-token.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const config = require('../local/config-example')
2+
const keycloak = require('../libs/index')(config)
3+
4+
keycloak.accessToken.get().then(async (accessToken) => {
5+
// refresh operation is performed automatically on `keycloak.accessToken.get`
6+
const response = await keycloak.accessToken.refresh(keycloak.accessToken.data.refresh_token)
7+
console.log(response.data)
8+
})

example/retrieve-decode-token.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const config = require('../local/config-example')
2+
const keycloak = require('../libs/index')(config)
3+
4+
keycloak.accessToken.get().then(async (accessToken) => {
5+
const token = keycloak.jwt.decode(accessToken)
6+
console.log({ expired: token.isExpired() })
7+
console.log({ content: token.content })
8+
console.log({ hasRole: token.hasApplicationRole('client-name', 'ROLE_NAME') })
9+
})

example/user-info.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const config = require('../local/config-example')
2+
const keycloak = require('../libs/index')(config)
3+
4+
keycloak.accessToken.get('openid').then(async (accessToken) => {
5+
const info = await keycloak.accessToken.info(accessToken)
6+
console.log(info)
7+
})

example/verify-offline.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const config = require('../local/config-example')
2+
const keycloak = require('../libs/index')(config)
3+
const fs = require('fs')
4+
5+
const cert = fs.readFileSync('./local/public_cert.pem')
6+
7+
keycloak.accessToken.get().then(async (accessToken) => {
8+
const token = await keycloak.jwt.verifyOffline(accessToken, cert)
9+
console.log(token.isExpired())
10+
})

0 commit comments

Comments
 (0)