Skip to content

Webfleet-Solutions/oauth-java-example

Repository files navigation

Authorization Code Flow Java Example

This sample code shows a Java Spring Web application accessing Webfleet Solutions APIs using OAuth 2.0 authorization code flow.

Java CI with Gradle license

Description

Features

This application features:

  • Authenticate an OAuth 2.0 client
  • Consume a Webfleet Solutions API
  • Refresh access token
  • Web interface
  • Form based authentication

Note

This project is not production ready, lacks proper security mechanisms. Secure channel communication, safe data storage and others are out of the scope for this project.

Client authentication

Flow starts on /service endpoint in ServiceController, simply redirecting the user-agent (browser) to Webfleet Solutions authentication server authorization endpoint indicating the flow to follow (response_type=code).

Authorization request example triggering user's authentication:

Parameter Mandatory Description
response_type ✔️ OAuth 2.0 grant flow, we are using code to signal we are triggering an authorization code flow
client_id ✔️ Client identifier provided by Webfleet solutions during registration process
redirect_uri ✔️ Callback uri user-agent should be redirected to after successful authentication
state ✔️ Random value used for validation during callback request
scopes optional Scopes parameter with requesting scopes. See Webfleet Solutions API documentation to learn about required scopes
GET /auth/realms/webfleet/protocol/openid-connect/auth?scope=<YOUR_SCOPES>&redirect_uri=<YOUR_REDIRECT_URI>&client_id=<YOUR_CLIENT_ID>&response_type=code&state={random} HTTP/1.1
Host: https://login.webfleet.com

Replacing placeholders with the appropriate values the request will trigger user authentication on Webfleet Solutions authentication server requesting the user to introduce the credentials.

Webfleet Solutions Login Page

In case the provided client_id is not correct, the following screen will appear.

Webfleet Solutions Client Not Found Page

Once the user has authenticated its user-agent is redirected to the uri informed in the redirect_uri parameter. In this sample it points to the CallbackController. Modify webfleet.redirecturi setting in application.yml to match your setup.

Webfleet Solutions authentication server will add a an authorization code as query parameter (code) to the callback uri which can be used to obtain access and refresh tokens.

Note

For security reasons authorization code can only be exchanged once and has a validity of 10min. (600 seconds).

Obtaining access and refresh tokens

To obtain access and refresh tokens we need to exchange the previously received authorization code after a successful user authorization, this is shown in the /callback endpoint implemented in CallbackController.

Authorization code exchange request example:

POST /auth/realms/webfleet/protocol/openid-connect/token HTTP/1.1
Host: https://login.webfleet.com
Content-type: application/x-www-form-urlencoded
Accept: application/json

grant_type=authorization_code&client_id=<YOUR_CLIENT_ID>&client_secret=<YOUR_CLIENT_SECRET>&code={code}&redirect_uri=<YOUR_REDIRECT_URI>
Parameter Mandatory Description
grant_type ✔️ OAuth 2.0 grant flow, we are using authorization_code following authorization code flow
client_id ✔️ Client identifier provided by Webfleet solutions during registration process
client_secret ✔️ Client secret provided by Webfleet solutions during registration process
code ✔️ Authorization code obtained during the authentication process
redirect_uri ✔️ Redirect uri associated to the OAuth client provided during the partner registration process
scope ✔️ List of OAuth 2.0 scopes. The use of the scope "offline_access" is needed to obtain offline tokens

A successful response from the previous request would be something like:

{
  "access_token": "string",
  "token_type": "bearer",
  "refresh_token": "string",
  "expires_in": 0,
  "scope": "string",
  "services": [],
  "jti": "string"
}
  • access_token : Used to authorize Webfleet Solutions APIs requests
  • refresh_token : Used to obtain a new access_token, MUST be stored safely (recommendation: use symmetric encryption to persist it)
  • token_type : How this token is used to authenticate requests. Default 'bearer' meaning must be informed using a bearer authorization header.
  • expires_in : Access token expiration time duration in seconds
  • scope : Scopes granted to the provided access token
  • services : Custom property carrying Webfleet Solutions information
  • jti : Access token identifier

Note

Beware access and refresh tokens have their own expiration times.

Typically access tokens are short lived being valid for just a few hours, while refresh tokens are long lived and may have an expiration time of months or years.

Refresh tokens MUST be stored in a secure place. This token can be exchanged for a new access token so effectively granting access to user's data. In case of leak, please notify Webfleet Solutions as soon as possible.

Requesting Webfleet Solutions API

To request a protected resource from a Webfleet Solutions API we need a valid not expired access token informed using an Authorization header using a Bearer token (RFC6750). In this example we are requesting the available logging user's info because is a common request that all our clients should have. However, you can try any request to any API you have access to.

GET /auth/realms/webfleet/protocol/openid-connect/userinfo HTTP/1.1
Host: https://login.webfleet.com
...
Authorization: Bearer <ACCESS_TOKEN>
...

Access token

This token may have expired or may expire during the process, especially if this process spans over multiple requests to Webfleet Solutions APIs, in such cases use a refresh token previously stored to obtain a new access token. This process is covered by the next section.

Refreshing access token using a refresh token

Once an access token has expired, a refresh token can be used to request a new access token without requesting the resource owner to authenticate again.

This is shown in /refresh endpoint in RefreshTokenController

Refresh token

This is similar to previous step in where an access token is obtained using an authorization code, remark there is no authorization code in this flow, instead we use a refresh token which we can use on Webfleet Solutions authentication server with a different flow, OAuth 2.0 Refresh token grant flow, to issue a new access token.

POST /auth/realms/webfleet/protocol/openid-connect/token HTTP/1.1 
Host: https://login.webfleet.com
Content-type: application/x-www-form-urlencoded
Accept: application/json

grant_type=refresh_token&client_id=<YOUR_CLIENT_ID>&refresh_token={refresh_token}
Parameter Mandatory Description
grant_type ✔️ OAuth 2.0 grant flow, we are using refresh_token following authorization code flow to request a new access token
client_id ✔️ Client identifier provided by Webfleet solutions during registration process
refresh_token ✔️ Refresh token representing resource owner's previous authorization for issuing access tokens on its behalf

A successful response will be something like:

{
  "access_token": "string",
  "token_type": "bearer",
  "refresh_token": "string",
  "expires_in": 0,
  "scope": "string",
  "services": [],
  "jti": "string"
}
  • access_token : Used to authorize Webfleet Solutions APIs requests
  • refresh_token : Used to obtain a new access_token, MUST be stored safely (recommendation: use symmetric encryption to persist it)
  • token_type : How this token is used to authenticate requests. Default 'bearer' meaning must be informed using a Bearer Authorization header.
  • expires_in : Access token expiration time duration in seconds
  • scope : Scopes granted to the provided access token
  • services : Custom property carrying Webfleet Solutions information
  • jti : Access token identifier

Note

Refreshing an access token returns a new refresh_token. New refresh token must replace previously stored ones.

Revoking refresh tokens

Revocation of refresh tokens is implemented following OAuth 2.0 Token revocation (RFC7009). Given WFS authentication server uses JSON Web Token specification (RFC7519) to issue signed self-contained tokens, only refresh tokens can be centrally revoked, access tokens stay valid until they have expired and cannot be revoked.

OAuth clients may revoke any refresh token issued to them, thus not requiring customer consent to revoke access to a customer granted refresh token.

Revoking a refresh token requires the following parameters in a form encoded request.

Parameter Mandatory Description
token ✔️ Refresh token to be revoked

Example using Basic authentication to inform client credentials

POST /auth/realms/webfleet/protocol/openid-connect/revoke
Host: https://login.webfleet.com
Authorization: Basic PHlvdXJfY2xpZW50X2lkPjo8eW91cl9jbGllbnRfc2VjcmV0PiA=
Content-Type: application/x-www-form-urlencoded

token=eyJhbGciOiJ...

A successful response will always return 200 OK HTTP status meaning the refresh token was revoked.

As defined in RFC7009 revocation response will return 200 OK HTTP status even for invalid tokens, revoking an invalid token has no purpose since its invalidation is already achieved.

Setup

You must have contacted Webfleet Solutions before trying this application, follow the registration process which will provide you with a pair of OAuth client credentials. To fully run the example application you will also need a valid Webfleet Solutions subscription and user with the appropriate rights.

Available application credentials

The application is secured using simple form based authentication. Find below the available credentials.

  • username: admin
  • password: password

Application users are hard coded and stored in memory, modify WebSecurityConfig to fit your needs.

Configuration

Multiple settings can be tuned in application.yml. By default the application starts a jetty instance listening on port 9080, this can be modified changing server.port setting in application.yml.

Running

The application uses Spring Boot and gradle, to run the application using gradle

./gradlew bootRun

Alternatively you may run it as a java application whose main class is com.webfleet.oauth.Application

Note

WFS_CLIENT_ID and WFS_CLIENT_SECRET environment variables must be defined before executing the application.

Docker

A Docker descriptor is provided to easily run the application without installing any other dependencies than Docker.

Replace your client credentials with the placeholders in the below command to build and run the container.

docker build -t oauth-java-example .
&& docker run
-p 9080:9080
--env WFS_CLIENT_ID=<YOUR_CLIENT_ID>
--env WFS_CLIENT_SECRET=<YOUR_CLIENT_SECRET>
--name oauth-java-example
--rm
oauth-java-example 

Note

Depending on your operative system you may experiment trouble with the gradlew file end of line. Execute ./gradlew wrapper command in your terminal before executing the docker build to set the end of line format according to your operative system.

License

This code is licensed under MIT License.

About

A sample code for Webfleet Solutions OAuth clients

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published