Apereo CAS - REST API Integrations

This blog is managed and hosted on GitHub. If you wish to update the contents of this post or if you have found an inaccuracy and wish to make corrections, we recommend that you please submit a pull request to this repository.


REST protocol support in Apereo CAS has been available since the early days of CAS 3.x. Since then, a lot of additional REST-based features and extensions are brought into the software to enable one to not only authenticate and/or exchange tokens but also add service definitions for relying parties or fetch attributes from remote REST endpoints, etc. The focus of this tutorial is to provide a brief overview of some of the REST-based features of CAS.

Our starting position is based on:


Let’s assume that we have the following service definition in CAS JSON service registry:

  "@class": "org.apereo.cas.services.RegexRegisteredService",
  "serviceId": "https://app.example.org",
  "name": "ExampleApp",
  "id": 1,
  "description": "This service definition defined our example application.",

Let’s also instruct CAS to fetch attributes (i.e. email) from a static/stubbed attribute repository source:


Next, to enable the CAS REST protocol the overlay must primarily be prepped with the following modules:

compile "org.apereo.cas:cas-server-support-rest:${project.'cas.version'}"
compile "org.apereo.cas:cas-server-support-rest-services:${project.'cas.version'}"

Exchange Tokens

Let’s invoke the REST API to authenticate a user and get back a ticket-granting ticket:

curl -k -X POST -H "Content-Type: Application/x-www-form-urlencoded" \
  https://sso.example.org/cas/v1/tickets \
  -d "username=casuser&password=Mellon"

…where the response would be:

  <head><title>201 CREATED</title></head>
  <body><h1>TGT Created</h1>
    <form action="https://sso.example.org/cas/v1/tickets/TGT-2-abcdefg"
      method="POST">Service:<input type="text" name="service" value="">
      <br><input type="submit" value="Submit">

The ticket produced in the response is embedded inside an HTML form. We can adjust the Accept header to produce a more JSON-friendly response:

curl -X POST -H "Content-Type: Application/x-www-form-urlencoded" \
  -H "Accept: application/json" https://sso.example.org/cas/v1/tickets \
  -d "username=casuser&password=Mellon"

The ticket-granting ticket that is produced can be used to obtain a service ticket:

curl -X POST -H "Content-Type: Application/x-www-form-urlencoded" \
  -H "Accept: application/json" https://sso.example.org/cas/v1/tickets/ \

The service ticket can then be validated so we could obtain the user profile:

curl -k https://sso.example.org/cas/p3/serviceValidate\

…where the response would be:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

You could also specify a format=json parameter to produce a more JSON-friendly response:

curl -k https://sso.example.org/cas/p3/serviceValidate\

Registering Applications

REST calls to CAS to register applications must be authenticated using basic authentication where credentials are authenticated and accepted by the existing CAS authentication strategy, which in our case would be casuser and Mellon.

Furthermore, the authenticated principal must be authorized with a pre-configured role/attribute name and value that is designated in the CAS configuration via the CAS properties:


The above outlines only users who carry an email attribute with a value that matches the above pattern can be authorized to add application definitions to CAS. In our case, we should be able to successfully do so with our sample casuser since the test account has a stubbed email attribute with a value of casuser@example.org that matches the above pattern.

Finally, the body of the request must be the service definition that shall be registered in JSON format and of course, CAS must be configured to accept the particular service type defined in the body.

So, the final call to CAS would be as such:

curl -k -H "Content-Type: application/json" -X POST \
  https://sso.example.org/cas/v1/services \
  -u casuser:Mellon -d@/path/to/app2.json

…where our app2.json would be as:

  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "https://app2.example.org.+",
  "name" : "ExampleApp2",
  "id" : 2,
  "description": "This is our second application"

Upon success, the CAS server would produce a 200 status code and its audit logs would indicate the successful registration of the application:

WHO: casuser
WHAT: AbstractRegisteredService(serviceId=https://app2.example.org.+...
WHEN: Mon Jun 12 14:46:58 MST 2019
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1

If you attempt the same operation with an unauthorized user:

curl -i -H "Content-Type: application/json" \
  -X POST https://sso.example.org/cas/v1/services \
  -u otheruser:somePassword -d@/path/to/app2.json

…you might see the following in the response with a 403 status code:

Request is not authorized

RESTful Attribute Resolution

CAS can be configured to fetch attributes from a remote REST endpoint. This functionality stands on its own, and does not require the presence of any extensions or modules in the overlay. It is offered by default, and activated only if the following CAS configuration is defined:


The authenticating user id is passed in form of a request parameter under username. The response is expected to be a JSON map as such:

  "name" : "JohnSmith",
  "age" : 29,
  "groups": ["g1", "g2", "g3"]

Upon a successful authentication attempt, CAS would reach out to the REST endpoint to fetch attributes. The results are then merged with our stubbed collection of attributes and aggregated into one collection that would be available for attribute release. Specifically, in the end, the final collection of attributes for our casuser would be:

  "name" : "JohnSmith",
  "age" : 29,
  "email" : "casuser@example.org",
  "groups": ["g1", "g2", "g3"]


I hope this review was of some help to you and I am sure that both this post as well as the functionality it attempts to explain can be improved in any number of ways. Please know that all other use cases, scenarios, features, and theories certainly are possible as well. Feel free to engage and contribute as best as you can.

Happy Coding,

Misagh Moayyed

Related Posts

CAS 6.1.0 RC5 Feature Release

...in which I present an overview of CAS 6.1.0 RC5 release.

Apereo CAS - Are We Logged In Yet?

Learn how to modify and extend a CAS deployment to determine whether an SSO session is still valid and tied to a user authentication session.

CAS 6.1.0 RC4 Feature Release

...in which I present an overview of CAS 6.1.0 RC4 release.

Apereo CAS - Multifactor Provider Selection

Learn how to configure CAS to integrate with and use multiple multifactor providers at the same time. This post also reveals a few super secret and yet open-source strategies one may use to select appropriate providers for authentication attempts, whether automatically or based on a menu.

Apereo CAS - Dockerized Hazelcast Deployments

Learn how to run CAS backed by a Hazelcast cluster in Docker containers and take advantage of the Hazelcast management center to monitor and observer cluster members.

Apereo CAS - Configuration Security w/ Jasypt

Learn how to secure CAS configuration settings and properties with Jasypt.

CAS 6.1.0 RC3 Feature Release

...in which I present an overview of CAS 6.1.0 RC3 release.

Apereo CAS - Webflow Decorations

Learn how you may decorate the Apereo CAS login webflow to inject data pieces and objects into the processing engine for display purposes, peace on earth and prosperity of all mankind, etc. Mainly, etc.

Apereo CAS - SAML2 Metadata Query Protocol

Learn how you may configure Apereo CAS to fetch and validate SAML2 metadata for service providers from InCommon's MDQ server using the metadata query protocol.

Saving Time is Time Consuming

May you live in the best of times. May you live in the startup times.