Skip to content

Instantly share code, notes, and snippets.

@renegr
Created November 4, 2016 18:10
Show Gist options
  • Save renegr/0dbc9b05efc4d7305fd1764770e3059d to your computer and use it in GitHub Desktop.
Save renegr/0dbc9b05efc4d7305fd1764770e3059d to your computer and use it in GitHub Desktop.
OpenID Connect Client in Eve
# OpenID Connect - Client
OpenID Connect is a protocol used for authentication and authorization.
We are going to implement a reusable "component" to interact with
an OpenID Provider. Our OpenID Provider will be Keycloak, therefore
many implementation Details are Keycloak specific.
Therefore you'll find two parts:
- 0. -> Using the OpenID Connect Component
- 1. -> Implementation Details for the OpenID Connect Protocol & Keycloak
## 0. Usage
### 0.1 Configuration
We start by adding an configuration record.
The implementation (in Section 1.) will do the rest.
```
commit
[#oidc-configuration base-url: "http://localhost:4100/auth/realms/master"
redirect-uri: "http://localhost:8080/#/examples/oidc_client.eve"
client-id: "eve"
scope: "offline_access openid"]
```
As we can see, we are expecting a running Keycloak instance on localhost:4100.
### 0.2 Sending & Receiving authorized JSON requests
(WIP) Sending an authorized request should be as simple as this:
```
search
config = [#oidc-configuration current-user]
commit @oidc
[#authorized-request #fetch-user-info method: "POST" using: config url: "http://localhost:4100/auth/master/some/fancy/request"]
```
We expect a **current-user** on our #oidc-configuration record, to send an authorized-request.
(WIP) Receiving the result of this request:
```
search @oidc
[#authorized-request #fetch-user-info response]
commit @browser
[#div text: "We have now received an authorized result and can display the response"]
```
### 0.3 Rendering the status
(WIP) Showing some user Details.
```
search @session
session = [#oidc-configuration current-user]
bind @browser
[#div text: "The current user {{session}} is logged in."]
```
(Debug) Show infos about the available access_token & refresh tokens
```
search
[#oidc-configuration tokens: [access_token refresh_token]]
bind @browser
[#div text: "The Access Token is {{access_token}}"]
```
The following block will show the Login link. Only available, when not logged in:
```
search @session
not([#oidc-configuration current-user])
[#oidc-configuration domain: [login-url]]
bind @browser
[#a href: "{{login-url}}" text: "Click here to login"]
```
## 1. Keycloak OIDC Implementation Details
These are the implementation details for a proper OpenID Connect client, like ours:
### 1.1 Autocomplete a #oidc-configuration
For the time being, we will configure the login-url.
```eve
search
config = [#oidc-configuration base-url client-id redirect-uri scope state]
not(config.domain)
redirect-uri-encoded = urlencode[text: "{{redirect-uri}}"]
bind
config <- [domain: [login-url: "{{config.base-url}}/protocol/openid-connect/auth?response_type=code&client_id={{config.client-id}}&scope={{scope}}&state={{state}}&redirect_uri={{redirect-uri-encoded}}"]]
```
### 1.2 Set or Restore the "STATE"
The state is a random hash-value, that will be used in the initial handshake between client and provider.
The first step in the handshake, will redirect the browser to the OpenID Provider - thus leaving
our application. Therefore we have to store our state in a way, we can retrieve later, when our browser
points to our application again (e.g.: Cookies, LocalStorage).
At the moment, we lack this feature in **Eve** (afaik), so we will fake it, and use some constant for our state:
Setting the store
```
search
config = [#oidc-configuration]
not(config.state)
bind
config <- [state: "SOMERANDOMSTATE"]
```
Restoring the store
**WIP** As mentioned above, we should try to restore our state from local cache, when the OpenID Provider
returns to our application successfully.
### 1.4 Reacting to the OIDC Handshake
The OpenID Provider returned to our application, but added two Query parameters: **code** and **state**.
**state** needs to match our **state** (the one we have set - or restored - in 1.2).
When we have a match, then it we can request our actual **Tokens** (access_token, refresh_token), that
we can use to send authorized requests to some API (like the one of keycloak, or any other secured API that
uses the same Keycloak instance for authentication).
To do so, we send the **code** to some API endpoint, asking kindly for the tokens:
```eve
search @event @session
qstate = if [#url-change query-param: [key:"state" value] ] then value
qcode = if [#url-change query-param: [key:"code" value] ] then value
oidc-config = [#oidc-configuration state base-url client-id redirect-uri]
commit @http
[#request #oidc-token method: "POST" url: "{{base-url}}/protocol/openid-connect/token" body:"code={{qcode}}&client_id={{client-id}}&redirect_uri={{redirect-uri}}&grant_type=authorization_code" headers: [Content-Type: "application/x-www-form-urlencoded"] oidc-config]
```
When keycloak is happy with the request, we can extract the **access_token** and **refresh_token** from
the response and store it in our #oidc-configuration:
**(WIP)**: To finalize this step, we need to extract the information about the currently signed in user.
For that we have to parse the JSON Web Token (access_token, id_token, refresh_token). -> Missing Feature in Eve.
```
search @http @session
[#request #oidc-token response: [json] oidc-config]
lookup[record: json, value:[access_token expires_in refresh_token id_token token_type]]
commit
oidc-config <- [tokens: [access_token expires_in refresh_token]]
```
## Todos
This example needs some more tweaks to work like a proper "Keycloak client". Here is a list of missing parts:
- create a random string for **state** > missing String function in Eve
- setting the current-user (by decoding jwt, and extracting the information) > missing JWT parsing function in Eve
- Implement the #authorized-request functionality > I guess Eve provides all features, to implement this. This is a two-step request: (a) refresh the access_token - when needed (b) send the actual request with the new (or old) access_token
- When keycloak redirects to our application, we no longer have **oidc_client.eve** loaded in the IDE, instead we have "Eve Quick Start Tutorial" -> ATM you have to navigate to the oidc_client.eve manually. Might be a keycloak problem? Stripping of the hash in the location? Needs some more investigation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment