Using Spring Authorization Server as an Auth Solution on Koyeb
25 minIntroduction
OAuth 2.0 is an industry-standard protocol for authorization for applications and services. However, running and customizing your own identity provider, like Keycloak, can be a challenge, especially for smaller organizations. The Spring Authorization Server is a secure, lightweight, and customizable alternative to build your own identity provider.
In this guide, we'll walk through how to create an application with identity and authorization provided by Spring Authorization Server. We will use start.spring.io to generate application templates to create a secure production environment in a matter of minutes instead of hours!
You can deploy and preview the applications from this guide by clicking the Deploy to Koyeb buttons below. You must set the appropriate environment variable values during the deployment configuration. View the application repository for more information on how to set the correct values.
To deploy the server, use the following button:
Afterwards, to deploy the client, click this button:
Requirements
To successfully follow this tutorial, you will need the following:
- Java 17 or newer installed on your local machine
- A GitHub account to host your code and deploy your application using the Koyeb's git-driven deployment method
- A Koyeb account to build, deploy and run the application
Steps
To complete this tutorial and deploy a Spring Boot application with a configured Spring Authorization Server on Koyeb, you need to follow these steps:
- From start.spring.io to Production in 5 minutes
- Set up the Spring Authorization Server
- Save user credentials in PostgreSQL
- Create a user management API
From start.spring.io to production in 5 minutes
First create a new directory on your local computer to hold the project files:
Next, head over to start.spring.io to create a new Spring Boot project. The above link preselects all of the options we want, namely:
- Maven as the build tool and project manager
- Java as the language
- 3.2.1 as the Spring Boot version
- The following project metadata:
- Group: (default:
com.koyeb
): can be anything you want - Artifact:
auth-client
- Name:
auth-client
- Description: can be anything you want
- Package name:
com.koyeb.auth-client
- Packaging: Jar
- Java version: 17
- Group: (default:
- The following dependency:
- Spring Web
Click on Generate
to download the project files. Download the .zip
file to the new project directory you created above.
Extract the project files from the zip archive and delete the zip:
Your project directory should now have the following structure:
Now that we have a set of project files, we can get started with a basic application.
Create a hello world application
To get started, we'll first create a HelloController.java
file in the auth-koyeb/auth-client/src/main/java/com/koyeb/authclient/
directory. Open the file in your editor and paste the following contents:
After the initial package and import declarations, we define a new HelloController
class. The @GetMapping("/")
annotation indicates that this class should respond to requests sent to the root path of your application. The body will contain "Hello World".
To test this out, start the Spring Boot application using the Maven wrapper in the /auth-koyeb/auth-client
directory. You must be in the same directory as the script for it to execute correctly:
After building the project, the Spring Boot application will be available at http://localhost:8080
. If you visit with your browser, you should see the "Hello World" message we crafted.
Press CTRL-C to stop the application when you are finished.
Prepare the Koyeb deployment
Next, create a system.properties
file in the auth-koyeb/auth-client
directory. Inside, set the version of Java to 17:
Koyeb's Java builder will consult this to determine which version of Java to use during building and deployment.
If you haven't done so already, create a new repository for your project on GitHub. Now we can initialize a new Git repository for the project, commit our changes, and push them to the new GitHub repo:
Note: Be sure to initialize the repository in the auth-koyeb
directory instead of the auth-koyeb/auth-client
directory. We will use a single repository for the server and client applications.
Your project files should now be synced up to GitHub, ready to deploy.
Deploy to Koyeb
To deploy your new application, open the Koyeb control panel and complete the following steps:
- On the Overview tab, click Create Web Service to begin configuration.
- Select GitHub as the deployment method.
- Select your project from the GitHub repository list.
- Change the name of your service to
auth-client
. - In the Builder section, select Buildpack. Click the Override toggle associated with the Work directory option and enter
auth-client
in the field. - Change the App and Service name to
auth-client
. This determines where the application will be deployed to. For example,https://auth-client-YOUR_USERNAME.koyeb.app
. - Click Deploy to begin the deployment process.
Your project will be cloned from GitHub, built, and deployed. You will be redirected to the deployment screen where you can track its progress and find the public URL of your application:
Checkpoint 1
Once the project is deployed, if you visit the public URL of your application, you should see a "Hello World" in your browser!
Set up the Spring Authorization Server
In this section, we will create a minimal Spring Authorization Server that uses an in-memory database. We will push it to Koyeb and then update the auth-client
application to use the authorization server as identity provider.
To create a new Spring Authorization Server, go to start.spring.io again. This time we will use the following options:
- Maven as the build tool and project manager
- Java as the language
- 3.2.1 as the Spring Boot version
- The following project metadata:
- Group: (default:
com.koyeb
): can be anything you want - Artifact:
auth-server
- Name:
auth-server
- Description: can be anything you want
- Package name:
com.koyeb.auth-client
- Packaging: Jar
- Java version: 17
- Group: (default:
- The following dependencies:
- PostgreSQL Driver
- OAuth2 Authorization Server
- JDBC API
Click on Generate
to download the project. Select your project directory (auth-koyeb
) as the download destination.
Again, unzip the project files, creating a new directory structure beside the existing auth-client
directory, and then delete the zip file:
Configure authentication in the authorization server
Now that the auth-server
files are available, we can create a UserDetailsService
in the AuthServerApplication.java
file. We will exclude the DataSourceAutoConfiguration.class
so that Spring Boot doesn't try to autoconfigure a database.
Open the AuthServerApplication.java
file in the auth-koyeb/auth-server/src/main/java/com/koyeb/authserver/
directory and replace the contents with the following:
This addition to the AuthServerApplication
class creates a new InMemoryUserDetailsManager
that is responsible for responding to authentication requests. We use the InMemoryUserDetailsManager
with a single user configured:
- Username:
user
- Password:
secret
The password is encrypted with bcrypt and the user is given the USER
role.
A small detour: what are authentication and authorization?
Before we continue, let's take a moment to clarify the difference between authentication and authorization.
In simple terms, authentication is the process of verifying who a user is. After a user's identity is established, authorization defines what they have access to.
In our example, the user can prove who they are by providing the credentials (Username: user
, password: secret
) thereby authenticating themselves. The user can then access all resources granted to the USER
role.
As we are using the Spring Authorization Server, we need to implement the authentication part ourselves. Spring makes this easy by letting us define a UserDetailsService
bean as we did above.
Test the authentication
To test the authorization, move into the auth-koyeb/auth-server
directory and run the application with Maven wrapper:
If you visit http://localhost:8080
in your browser, you should see a login screen. Log in with the username: user
and the password: secret
.
Note: Because we not yet configured the post-authentication redirect to something more appropriate, you will be redirected to a WhiteLabel error page. This is expected and it indicates that the authentication was successful.
Press CTRL-C to stop the application when you are finished.
Integrate the auth-client and the auth-server
Now we have both of the core components required for our application, the client application and the authorization server. The next step is to connect them.
Configure the auth-server
In the auth-koyeb/auth-server/src/main/resources
directory, rename the application.properties
file to application.yaml
to use YAML markup. Inside, paste the following application details:
This configures the authorization server to listen on port 8099 and registers a new OAuth2 client with the expected details of our client application.
In more detail:
koyeb-client
: defines a new OAuth2 client configuration.require-authorization-consent: false
: disables the need to consent to authorization after login.registration
: defines a newRegisteredClient
.client-authentication-methods: "client_secret_basic"
: tells theauth-server
that this client can authorize itself with basic authentication.client-id: "auth-client"
andclient-secret: "{bcrypt}...."
: define the credentials that theauth-client
application needs to submit when starting an authorization flow.redirect-uris
: defines the URLs that theauth-server
may redirect to after successfully authenticating the user.authorization-grant-types: authorization_code
: specifies that theauth-client
needs to redirect the user to the authorization server to authenticate themselves. After user authentication, the authorization server redirects back to theauth-client
application with an authorization code.scopes
: can limit the scope of user information the client can request from theauth-server
.server.forward-headers-strategy
: configures correct header forwarding when deploying behind a reverse-proxy that handles the domain name.
Configure the auth-client
Next, we'll configure the auth-client
to use the authorization server. Add the following dependency to the auth-koyeb/auth-client/pom.xml
file between the <dependencies>
tags:
Afterwards, rename the application.properties
file to application.yaml
in the auth-koyeb/auth-client/src/main/resources
directory to use YAML markup. Inside, paste the following application details:
This configures the values that the auth-client
will supply when authenticating a user.
Test the integration
Now, we can test the integration between our two components.
First, move back into the auth-koyeb/auth-server
directory and restart the authentication server:
Now, in a second terminal window, go to the auth-koyeb/auth-client
directory and start the client application as well:
Checkpoint 2
With both applications running, visit the client application at http://127.0.0.1:8080.
Note: It is important that you use 127.0.0.1
instead of localhost
so that the cookies for the two applications don't interfere with one another.
You should be redirected to http://localhost:8099/login
. Sign in with username: user
and password: secret
.
You should be authenticated as expected and redirected back to http://127.0.0.1:8080
where you can see the "Hello World" greeting!
Press CTRL-C in both terminal windows when you are finished to stop the applications.
Prepare the Koyeb deployment
Before deploying the application to Koyeb, we need to create a system.properties
file for the auth-server
application. Create a new file in auth-koyeb/auth-server
called system.properties
and paste the following inside:
Deploy the Spring Authorization Server to Koyeb
Add the new changes to the Git repository and push them to GitHub:
Note: When you push the new changes to the repository, the changes to your client application will automatically be deployed to Koyeb. Because we haven't completed the configuration, you should expect this new deployment to fail. We will update the client component to make it work correctly momentarily.
Once the changes are in your repository, open the Koyeb control panel and complete the following steps to deploy the authorization server:
- On the Overview tab, click Create Web Service to begin configuration.
- Select GitHub as the deployment method.
- Select your project from the GitHub repository list.
- In the Builder section, select Buildpack. Click the Override toggle associated with the Work directory option and enter
auth-server
in the field. - Change the App and Service name to
auth-server
. This determines where the application will be deployed to. For example,https://auth-server-YOUR_USERNAME.koyeb.app
. - Click Deploy to begin the deployment process.
Your project will be cloned from GitHub, built, and deployed. You will be redirected to the deployment screen where you can track its progress and find the public URL of your application.
If you visit the server application's URL, you should see the login screen and be able to log in with the user: user
and the password: secret
. This will redirect you to the same WhiteLabel error page from earlier.
This is not the behavior we want. For this to work, we need to update the application.yaml
files for both the auth-server
and auth-client
applications to use our Koyeb domains.
Update the application.yaml files
First, update the application.yaml
file in the auth-koyeb/auth-client/src/main/resources/
directory. We need to change the issuer-uri
value from http://localhost:8099
to the domain name where the authorization server is hosted. You can find this on the authorization server's page in Koyeb.
Assuming that you called the service auth-server
during creation, it should have the following format:
The updated portion of the file will look like this:
Next, open the application.yaml
file in the auth-koyeb/auth-server/src/main/resources/
directory.
Here, the part we need to update is the redirect-uris
list. Copy the current value and replace the http://127.0.0.1:8080
portion of the URL with the auth-client
URL from Koyeb. You can find this on the client's page in Koyeb.
Assuming that you called the service auth-client
during creation, the client's URL in Koyeb should have the following format:
With the /login/oauth2/code/spring
path, the complete URL you need to add will look like this:
The updated portion of the file will look like this:
Commit the files to the repository and push them to GitHub:
When you push the changes to GitHub both of your applications will be automatically deployed with the updated code.
Checkpoint 3
If you now visit the URL for your client application again (https://auth-client-<YOUR_KOYEB_ORG>.koyeb.app
), you should be once again redirected to https://auth-server-<YOUR_KOYEB_ORG>.koyeb.app
.
Log in with username: user
and password: secret
and you should be correctly redirected back to https://auth-client-<YOUR_KOYEB_ORG>.koyeb.app
where the "Hello World" greeting is served.
Save the user credentials in PostgreSQL
Next, we will configure the Spring Authorization Server to use a PostgreSQL database running on Koyeb to store our user credentials and enable registration.
Set up the schema
First, create a schema.sql
file in the auth-koyeb/auth-esrver/src/main/resources/
directory that configures the necessary schema for the Authorization Server:
This creates the following tables:
users
authorities
groups
group_authorities
group_members
It also creates an index on the authorities
table for faster lookups.
The schema has the following structure:
Create a JdbcUserDetailsManager
Next, we'll rework the server application so that it uses a PostgreSQL database as its data source instead of the in-memory database.
Replace the contents of the AuthServerApplication.java
file in the auth-koyeb/auth-server/src/main/java/com/koyeb/authserver/
directory with the following:
The new code does the following:
- Removes the
DataSourceAutoConfiguration.class
exclusion since we want Spring to set up aDataSource
bean for us now. - Create a
JdbcUserDetailsManager
bean that allows you to manage users and groups that are saved in our database via the JDBC API. - Uses an
ApplicationRunner
bean to create the same user as we did before with theuser:secret
credentials, if the user does not already exist in the database.
Set up a managed PostgreSQL database on Koyeb
Next, we can provision a PostgreSQL database on Koyeb. In the control panel, go to the Database Services page and click Create Database Service
. Choose a descriptive name and your preferred region. You can leave the rest of the settings as they are.
Once you create the database, you will be redirected to the connection details page. Click the "Java" to change the view and then click the copy icon on the right.
Open the auth-koyeb/auth-server/src/main/resources/application.yaml
file in your text editor and add the sql
and datasource
sections under the spring
key. Don't remove any of the existing configuration.
Paste the connection URL you copied from the Koyeb control panel as the data source URL, removing the JDBC_URI=
prefix and query parameters after the ?
(?user=...
):
This sets the SQL init mode to always
so that the schema.sql
we created is executed on startup. The datasource
configuration supplies the connection information for the database.
Note: You should never commit production credentials to GitHub. You should use an environment variable as we are doing here.
Deploy to Koyeb
Before we deploy the new code to Koyeb, we should configure an environment variable with our database password.
Visit your auth-server
application in the Koyeb control panel. Click on the Settings tab for the auth-server
service. Towards, the bottom of the page, click to expand the Advanced section.
Click Add Variable in the Environment variables section to add a new environment variable. Name it DATABASE_PASSWORD
to match the value we used in the application.yaml
file above. Set the type to Secret and set value to the password for your database, copied from the database details page. Click Apply when you are finished to save the new configuration.
Next, commit your changes the Git repository and push it to GitHub:
The new version will be deployed automatically. You can check the progress of the deployment in control panel.
Create a user management API
Now that our Authentication and Authorization flow works and can be persisted with a database, we can add the ability to manage users.
We will create a simple API to manage users directly from the browser by using a subset of methods available in the JdbcUserDetailsManager class.
Open the AuthServerApplication.java
file in the auth-koyeb/auth-server/src/main/java/com/koyeb/authserver/
directory again. First, we'll go over the individual changes in detail. Afterwards, we'll provide the complete content that you can paste into your file (including necessary import
lines that we won't be covering explicitly).
Begin by adding the @EnableMethodSecurity
Authorization annotations to the AuthServerApplication
class to allow us to preauthorize on the method and controller level (like @PreAuthorize("hasRole('ADMIN')")
).
Next, adjust the JdbcUserDetailsManager
implementation. We want to call the following methods:
setEnableAuthorities(false)
: disables loading authorities (roles) from the authorities table on the user object level.setEnableGroups(true)
: enables support for loading group authorities.
To do this, we need to change the UserDetailsManager
block to the following:
Next, create a PasswordEncoder
that will be used to hash the passwords. The default is BCryptPasswordEncoder
Finally, adjust the initializeUsers
method to do the following:
- rename the initial user to
admin
- remove the
roles("USER")
method call in theUserBuilder
- create the groups:
GROUP_USER
andGROUP_ADMIN
- add the
admin
user to both groups
The initializeUsers
method will look like this with these changes:
To implement all of the above changes, paste the following contents into the AuthServerApplication.java
file:
Implement the user management API
Next, we'll add the API endpoints to manage users to a new file called UserManagementController.java
in the auth-koyeb/auth-server/src/main/java/com/koyeb/authserver/
directory.
Start the file off with the following content:
The parts to note are the following:
@PreAuthorize("hasRole('ADMIN')")
: this will limit the ability to execute these methods to users that have theROLE_ADMIN
authority.@RestController
: this creates a Spring controller bean that puts the response data in the response body.
Next, add the methods that expose the most important JdbcUserDetailsManager
functions for retrieving user and group data from the database. Put these towards the bottom of the UserManagementController
class:
To start the AuthServerApplication
locally and test the changes, you can execute the following. Because the project is now configured with a database, we need to provide our database password with the DATABASE_PASSWORD
environment variable, just like our Koyeb deployment does:
Now, go to http://localhost:8099
in your browser and log in with username: admin
and password: secret
.
While you'll be taken to a WhiteLabel error page upon authentication, if you now go to http://localhost:8099/users/admin
you should get the details of the admin
user. When pretty printed for readability, the JSON response should look something like this:
Next, visit http://localhost:8099/groups
to see all of the available groups:
If you go to http://localhost:8099/groups/USERS/users
, you can see all of users that are a member of the GROUP_USERS
group:
Visiting http://localhost:8099/groups/USERS/authorities
will give you all of the authorities that are assigned to the USERS
group:
Press CTRL-C to stop the application when you are finished.
Create and update users and groups
Next, we will add methods to create a user, create a group, and add a user to a group.
Open up the UserManagementController.java
file in the auth-koyeb/auth-server/src/main/java/com/koyeb/authserver/
directory again. Add the following methods to the UserManagementController
class to enable this functionality:
Basically, these methods do the following:
createUser
: uses the sameUserBuilder
asinitializeUsers
in theApplicationRunner
:- It sets the password to a hashed value using
passwordEncoder.encode(password)
. - Then adds the user to the
GROUP_USER
group. - Finally, it returns the
UserDetails
object by calling theloadUser(userName)
method.
- It sets the password to a hashed value using
createGroup
: creates a group with theROLE_{role}
authority and then returns the list of authorities that the group has.addUserToGroup
: adds the{userName}
user to the{groupName}
group and returns all users currently in that group.
Start up the server again using the same command as last time:
Now, if you go to http://localhost:8099/users/create/peter:parker
, a new user will be created with the username: peter
and password: parker
. You will be given their user details:
Next, create a new group by visiting http://localhost:8099/groups/create/AVENGERS:AVENGER
. This creates a new group called GROUP_AVENGERS
with the ROLE_AVENGER
authority:
You can then add peter to the AVENGERS
group by going to http://localhost:8099/groups/AVENGERS/add/peter
:
Press CTRL-C to stop the application when you are finished.
Our user management is working as expected locally. We can deploy this additional functionality to Koyeb by committing the changes and pushing them to GitHub:
Once deployed, the same user management features will be available in the deployed version of your applications.
Conclusion
In this tutorial, we've demonstrated how to deploy Spring Boot applications using to Koyeb from a GitHub repository with continuous delivery.
We developed both a client and server application to walk through the authentication and authorization flows available. We then configured the Spring Authorization Server to use a Koyeb managed PostgreSQL database as the persistence layer. Afterwards, we showed how to authorize and manage users with JdbcUserDetailsManager
, creating a foundation that you can use to build your own identity provider.
If you want to continue to learn about the Spring Authorization Server, some good resources include Enterprise Security with Spring Authorization Server 1.0 by Rob Winch @ Spring I/O and the Spring Authorization Server Reference. If you have any questions or suggestions regarding this guide, feel free to reach out to us on Slack, or to the author on Twitter: twitter.com/tschuehly.
Check out our Java documentation and Java one-click app to learn more about deploying Java applications on Koyeb.