Introduction

Web application that provides an SSO gateway to unify institutional and third-party SSO providers.

Discovery Endpoints

OAuth2 / OpenId Connect discovery (metadata) endpoints can be found at the following well-known paths.

  • OAuth2

    • URI(s): https://[tier: dev,pprd].gateway.login.vt.edu/.well-known/oauth-authorization-server

      • Exclude tier for production instance (e.g. 'https://gateway.login…​')

  • OpenId Connect

    • URI(s): https://[tier: dev,pprd].gateway.login.vt.edu/.well-known/openid-configuration

      • Exclude tier for production instance (e.g. 'https://gateway.login…​')

Setting up your App

Using the Gateway service is a multi-step process.

  1. Create an Enterprise Directory group - or use an existing group - that will be the backing group for your developer team. Note: you must be an admin on the group used for your team. Each team member must be a member of the backing group. Select the desired tier based on needs (must use the same App Manager tier).

  2. Create a Developer Team via App manager. Select the desired tier below based on needs.

    1. Select Create Developer Team (if you don’t have one already)

    2. Choose a group from the dropdown

  3. Create an app under the newly created team

    1. Click the Create App button on the App Manager homepage.

    2. Choose a Developer Team from the dropdown.

    3. Choose a name for your team.

    4. Create App.

    5. You should now be on the Dashboard for the new app.

      1. The Client Id and Client Secret are the credentials used for communicating with the Gateway service.

      2. Register a new O-Protocol Endpoint. This is the callback endpoint in your app/service that will handle auth/tokenn responses from Gateway. e.g. https://my.app.vt.edu/secure

    6. App Manager Tiers

Authentication

The Gateway API requires different authentication methods depending on the endpoint being accessed.

Client Authentication

Endpoints secured by HTTP Basic authentication (i.e. client secret).

  • /oauth2/token  — Token exchange

  • /oauth2/tinfo  — Token info

  • /oauth2/revoke  — Token revocation

Credentials may be specified by either of the following mechanisms:

  1. HTTP Basic scheme

  2. POST parameters client_id and client_secret per [RFC 6749, section 2.3.1](https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1)

User Authentication

Endpoints security by HTTP Bearer authentication (Access Token).

  • /oidc/uinfo  — User info

  • /oauth2/admin/tokens — Administrative token revocation

  • /oauth2/user/tokens  —  User-initiated token revocation

Gateway API

Authorize

GET /oauth2/authorize

OAuth2 AUTHORIZATION endpoint with support for PKCE. The parameters are those supported by the AWS Cognito AUTHORIZATION Endpoint as this endpoint proxies to the AWS endpoint.

Authorization

HTTP Auth is not required.

Query Parameters

Parameter Optional Description

response_type

false

OAuth2 response_type parameter.

client_id

false

OAuth2 client_id parameter.

redirect_uri

false

OAuth2 redirect_uri parameter.

state

true

OAuth2 state parameter.

scope

true

OAuth2 scope parameter.

nonce

true

OIDC nonce parameter.

code_challenge_method

true

OAuth2 PKCE code_challenge_method parameter.

code_challenge

true

OAuth2 PKCE code_challenge parameter.

enable_create_guest

true

Flag indicating that a user should be presented with the option to create a guest account.

onboard_success_create

true

Flag indicating that a user is coming back from Onboard after successfully creating a new account. This is not intended to be set directly by a client and doing so will prevent a user from seeing the Gateway discovery page.

Example Request

$ curl 'http://localhost:8080/oauth2/authorize?response_type=code&client_id=lota&redirect_uri=https%3A%2F%2Flota.example.com&state=LOTA874ABC&scope=profile+openid' -i -X GET

Example Response

HTTP/1.1 302 Found
Location: http://localhost:8080/?state=hhpF3O1f31MppqGr1hVoQs

Example Error Response

HTTP/1.1 302 Found
Location: https://client-inactive.example.com?error=unauthorized_client&error_description=Client%20is%20inactive

Token: Code Exchange

POST /oauth2/token

OAuth2 TOKEN endpoint for the code flow with support for PKCE. The parameters are those supported by the AWS Cognito TOKEN endpoint as this endpoint proxies to the AWS endpoint.

Authorization

The client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization via HEADER. The secret is Basic Base64Encode(client_id:client_secret).

Form Parameters

Parameter Optional Description

grant_type

false

OAuth2 grant_type parameter.

redirect_uri

false

OAuth2 redirect_uri parameter.

code

false

OAuth2 code parameter.

code_verifier

true

OAuth2 PKCE code_verifier parameter.

Example Request

$ curl 'http://localhost:8080/oauth2/token' -i -u 'jolene:j' -X POST \
    -d 'grant_type=authorization_code&code=PR0X1ED&redirect_uri=https%3A%2F%2Fjolene.example.com'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 2317

{"token_type":"bearer","expires_in":3000,"scope":"openid email name","access_token":"eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkNjViOWExNy1hYjUwLTQ4NDctYWM4Ny00YzM0Y2ZiY2Q2NGEiLCJhdWQiOiJqb2xlbmUiLCJzY29wZSI6WyJvcGVuaWQiLCJlbWFpbCIsIm5hbWUiXSwiaXNzIjoic29tZWJvZHkiLCJhY3RpdmUiOnRydWUsImV4cCI6MTczMzc4NDg5MiwiaWF0IjoxNzMzNzgxODkyLCJ0dGwiOjMwMDAsImp0aSI6IlVaQlQzTkxCWVNNWTQzTEhEMzRHVlNLSEZYVktHU0dBTiJ9.uKqKf1km_zNe9tCyJPXmPPaLE3huUpjsRzSGPpGacwW4WCSp7o2-h8yWRhKepwEu6fCPxjgPNQ3tSXUMreOMUxc83MJVy9IXhkC_VFvrJ5IcaYEReABJ9Drst0wREeJwVzQf8a_UK43OHcx6JJaM8T4NxgKGPcqYLbfMYPMolLP0LX5BehHmrflLaHSh5QVupNiR-PdpctoARn13iY4mQyguluSf5SBDfc2ODAnVy1hWr2-7B3U4dBa7bz9lzNrC81mgbiNbC9HJ4R1-yBkhoCYnp02Y7PvH7oKDsovBE2M8gVJqQb0_uIRkzqGnruNFFdTnWFvnjMwhnad1lV7u5g","refresh_token":"eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkNjViOWExNy1hYjUwLTQ4NDctYWM4Ny00YzM0Y2ZiY2Q2NGEiLCJhdWQiOiJqb2xlbmUiLCJzY29wZSI6WyJvcGVuaWQiLCJlbWFpbCIsIm5hbWUiXSwiaXNzIjoic29tZWJvZHkiLCJhY3RpdmUiOnRydWUsImV4cCI6MTczMzc4Nzg5MiwiaWF0IjoxNzMzNzgxODkyLCJ0dGwiOjYwMDAsImp0aSI6IlNBRUNMWlRYV0w3S1IyREtESDgzOEtESFQ2Tk1YVEJaM0lJNFJHREhIVjQzSVZBRiJ9.hWOLN2jjI-xlbSRvIPVVjCe5ppeD5H2XuFNFhl8flHgZoxftNhe4Bi0oraHJ0f6hSI6dHvSY0j7FNYSjjnz2JEZYICJ3O5YRqCuWwiaL-zcDcW-b4qtlJVQ4JcaAuFB-swVIop7d6Vwn_6tErVVIQeAYFfu4G3ZJangxZUcYqmrW4rMtKuw1w38DMzKhYdF5rLvVWnBDyEd6r2ZyXuxoiGlyXLkNq0cqBAZHh5jNkBA_R9K94U-2yWf7HdJ_PaGr1aogsPOGiNk3JN0jNNCqt43ckl4aGHhwq4prlsRxk8nZLsUZcFZOhu7B6dzq_Pkm3dx0l66YGxCwyyQAP29ZpA","id_token":"eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkNjViOWExNy1hYjUwLTQ4NDctYWM4Ny00YzM0Y2ZiY2Q2NGEiLCJpc3MiOiJzb21lYm9keSIsImFjdGl2ZSI6dHJ1ZSwidHRsIjozMDAwLCJub25jZSI6IkhES0QtOEg3JEhELUtESEE4TCIsImF1ZCI6ImpvbGVuZSIsInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwibmFtZSJdLCJuYW1lIjoiSm9sZW5lIEpvbGUiLCJleHAiOjE3MzM3ODQ4OTIsImlhdCI6MTczMzc4MTg5MiwianRpIjoiN0tSMlQyRUFYNlFCTFREODM4SERLRExEM0lWQUZTQUVDTFpUWFdMIiwiZW1haWwiOiJqb2xlbmVAdnQuZWR1In0.zyROhClrlgK7mbVwxWNjlGYXY6Iv8l9xTAS7p2xqBz2HkdrEOgoAAPiYywOjpOe8-_Scgd-UFCr4hWCtDkZwTHJ-pM38NCBiwVGub-om2_EDnIztTDWEMTFE3UkTyCfKisvchIZsE6OftaJJm0Xd53ckRcB2ucUVT7F7WkoKwcnuW2vCKMQ1OCDOdewllVP4_54WS65j-y_dXQyg4VY2QOcTECyHvY2_HxHfwMOm1HecXE1GzUgNQMRumggLer19kScjlCMo_TXJyvhCLsKpEJ6inknO8g3sfBi3YjanF1YOE3fjW_TnOlW0lKBPOLfxnjsqilcytbt6pAGor21_-A"}

Example Error Response

HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 105

{
  "error" : "unsupported_grant_type",
  "error_description" : "Grant type must be authorization_code"
}

Token: Refresh Token Exchange

POST /oauth2/token

OAuth2 TOKEN endpoint for handling refresh token requests.

Authorization

The client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization via HEADER. The secret is Basic Base64Encode(client_id:client_secret).

Form Parameters

Parameter Optional Description

grant_type

false

OAuth2 grant_type parameter.

refresh_token

false

OAuth2 refresh_token parameter.

scope

true

OAuth2 scope parameter

Example Request

$ curl 'http://localhost:8080/oauth2/token' -i -u 'rho:r' -X POST \
    -d 'grant_type=refresh_token&refresh_token=eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI5YzhhODRiZS0zMDg3LTQxZjItOTEwYy1mYzViODM5OGIwMzQiLCJhdWQiOiJyaG8iLCJzY29wZSI6WyJ0aGUtc2NvcGUiXSwiaXNzIjoic29tZWJvZHkiLCJhY3RpdmUiOnRydWUsImV4cCI6MTczMzc4Nzg5MiwiaWF0IjoxNzMzNzgxODkyLCJ0dGwiOjYwMDAsImp0aSI6IlZZTEpIT0FURVo2V1M0QjZRV1JVWERTN0dIUkpYNFdaUTdZSklVVlNKWloifQ.ngVkpilAMxkj0Iq3-frmFiegLRGPmSUQ1f_taSF9pZ6XbwkAr4ZX0Auqhw6xleJrbyShWJ50JrA07kaZ1dQXz76xuI3LMFW4_YqBlSzsauaLHd4GsA2nbYnTom6DoKkA9iPof22zhBlMuCco840jJijc8sTmNKaR-zR46mqRSMh6mlkrjKvI1yF68EAoGP2ZvBTF4nvq7VtJ5hJPR5BbzB3V7Nrrw3f0RF6ZpoaeknWdSEWRtlUjXSCDzguQnpxTm48jCoNsCneuRt0u8lTlhO24uZvlWDp2KyQPRjEaBlsn050ivowQb5A4Nq6ThNZHwkAoH7XnEFhB1qDtX7TlGg&scope=the-scope'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 1448

{"token_type":"bearer","expires_in":3000,"scope":"the-scope","access_token":"eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI5YzhhODRiZS0zMDg3LTQxZjItOTEwYy1mYzViODM5OGIwMzQiLCJhdWQiOiJyaG8iLCJzY29wZSI6WyJ0aGUtc2NvcGUiXSwiaXNzIjoic29tZWJvZHkiLCJhY3RpdmUiOnRydWUsImV4cCI6MTczMzc4NDg5MiwiaWF0IjoxNzMzNzgxODkyLCJ0dGwiOjMwMDAsImp0aSI6ImJiZDUwYmQ5LTEwMDYtNDliZi05ZDVhLTBlZTk0YWJlNTQwOSJ9.VXdp7m-aRxthgJnw5i4UUnFPizV-xy_HNP18Q6Lo1dwO9Ur0Jf0nRq0P1uD6uZxoLxnnWlHzVsMnAh2IyMQe9fNDKdbw9WfI98Mkn5zq6MRlRs5lkOvpxrrI1A9rhgfxSCdAy4wWjS1V9R_WqVNGJd9McVag19mNwS7ys0eOBanPRmg2f7o_BB7CgLLksd2_oHh3ZDvij8h47M0MvHxRnKvBws22ZYY5q04owUZwwdxo1DyC3QmdkaNs7PNXsH2-I5znfaWc6nZqgACYbRoSm4cA0ME-q08YV2CQiKPpAGcBFmlvnYqlBr7riSYD1DUrg-wkHx7r4jkzfVuDQZqQIQ","refresh_token":"eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI5YzhhODRiZS0zMDg3LTQxZjItOTEwYy1mYzViODM5OGIwMzQiLCJhdWQiOiJyaG8iLCJzY29wZSI6WyJ0aGUtc2NvcGUiXSwiaXNzIjoic29tZWJvZHkiLCJhY3RpdmUiOnRydWUsImV4cCI6MTczMzg0MTg5MiwiaWF0IjoxNzMzNzgxODkyLCJ0dGwiOjYwMDAwLCJqdGkiOiI3NmI0ZTc5My1jODFmLTRhYWItOTFhOS00NDAzOWYyMDU1MTkifQ.hdY9yk6yZrMd8AVspyWkV2snld-MzgWDCFpHisQSBVKgbUX8lYJTANbxAJKvtKUQbV8eDBAYdSX5EpZNhW7KzFBtGtmbZs4OM0Ox7qfeWVrJSNKAtykufC6lwEkdTo99hYrKwuPnf3OejpV2XxxF21nrqi1frADmgvlK-rxix8VbhoFrfaTleh0aiaDIZTs_1wSf5vTRjcALpp06ZAdNfhh4NgPljVJTU-5J9rpQyVC_H5RsQMGdpQ04Qnpq0DzDvrPD6Y04Nb1wejKISWOEGYZ4fyFbFgve7fTMqeYY3B0eBrATdcaiktwLhkvjc0TPa6Yimi5ZCuxKwrVK9Z3EnQ"}

Example Error Response

HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 80

{
  "error" : "invalid_grant",
  "error_description" : "Invalid refresh token"
}

Token: Client Credentials Grant

POST /oauth2/token

OAuth2 TOKEN endpoint for the client_credentials flow as described here.

Authorization

The client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization via HEADER. The secret is Basic Base64Encode(client_id:client_secret).

Form Parameters

Parameter Optional Description

grant_type

false

OAuth2 grant_type parameter. Value must be client_credentials.

scope

true

OAuth2 scope parameter.

Example Request

$ curl 'http://localhost:8080/oauth2/token' -i -u '12345678-90b0-1002-a0a1-ffbbbb923df0:s' -X POST \
    -d 'grant_type=client_credentials&scope=c'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 804

{"token_type":"bearer","expires_in":3000,"scope":"c","access_token":"eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI0ZWIzNmY5Mi1mODlkLTQ0OGYtOThlMy1mNDYwZTdmYWRjNDUiLCJhdWQiOiIxMjM0NTY3OC05MGIwLTEwMDItYTBhMS1mZmJiYmI5MjNkZjAiLCJzY29wZSI6WyJjIl0sImlzcyI6InNvbWVib2R5IiwiYWN0aXZlIjp0cnVlLCJleHAiOjE3MzM3ODQ4OTEsImlhdCI6MTczMzc4MTg5MSwidHRsIjozMDAwLCJqdGkiOiJmNzcwMTYwMC01YTlkLTQ5NTQtODJkMi0yMjU2MmExNzg5ZDIiLCJ1c2VybmFtZSI6InNpZ21hIn0.Y_FDc2pC1XKH7aZpmxFlhnAAWgX5dPHtVcFpU_Uyuvkx9RR0yLW0b-y-VUooNBzc9Uw8U6jJLXHtOhjJU1PfE162r9rV8DhpmxHMpH8K41htXs787Db9scFdxTnYCLW8Sl1ZIPdS8xWepU8WMNEQ7zuNs27I84Lm5FgcMsVoehR0B9ePNsCUqKnBNgk7QZ683MmR9b23CE78I8z4PrJ_ohk7HTnhkBtKsvG1_3azNnuu7FO5EPyvwwtp1VdeRtHac9eELwD9m_da_2N9Ry7ClFCk6YNPnayhAPxiDLEBlh7R6Z5y3o06E0wdCn2hRI5ktKv8xnIbfEgQAqykoBbRrg"}

Example Error Response

HTTP/1.1 401 Unauthorized
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Basic
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 79

{
  "error" : "invalid_client",
  "error_description" : "Invalid credentials"
}

Revoke: Client-Initiated

POST /oauth2/revoke

Authorization

The client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization via HEADER. The secret is Basic Base64Encode(client_id:client_secret).

Form Parameters

Parameter Optional Description

token

false

The token that the client wants to be revoked.

token_type_hint

true

Token type hint.

Example Request

$ curl 'http://localhost:8080/oauth2/revoke' -i -u 'client-id-a:clientAPassword' -X POST \
    -d 'token=eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJjbGllbnQtaWQtYSIsImF1ZCI6ImNsaWVudC1pZC1hIiwic2NvcGUiOiJvcGVuaWQiLCJleHAiOjE3MzM3ODY4ODMsImlhdCI6MTczMzc4MTg4MywidHRsIjo1MDAwLCJqdGkiOiJ0b2tlbi10by1yZXZva2UtaWQifQ.kT3Pby8bMB8O0j-Y1qE1hrj9QY5e5AysZiQJua5Bf7FwPPhDnlIn_qK7KRohzjPvo3OSbcFEu7rLG_ZAX3ovmvhMHTrlcGdenyuDwyQHYvjoq92WYM9KrvFNVEt3JFPJyGqnNPghhzDArhaBuEW_ztZVa3V88Y7nDOs3TP8Xs-wIgC1oSd5IDtTkTopfFLJ6zxxeXk1T-0wu0MDt-Y4JllNkWyf0WFXAx9UWd5egAp335IWb5fwqbTTpBciLj0vW-yma8B3g7ELm4Nch8gJfSzaPxB7tTVhVYKU6SmNh66e8XERhPH8czlJK1zLqb8VdBFXvLCU_2qaGxvFH_IUupA'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: text/plain;charset=UTF-8
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

Example Error Response

HTTP/1.1 503 Service Unavailable
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 108

{
  "error" : "operation_failed",
  "error_description" : "Token still exists with ID: token-to-revoke-id"
}

Revoke: Client-Initiated Batch

POST /oauth2/client/tokens

OAuth2 revocation endpoint for revoking ALL tokens that were created for the authenticated client.

Authorization

The client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization via HEADER. The secret is Basic Base64Encode(client_id:client_secret).

Example Request

$ curl 'http://localhost:8080/oauth2/client/tokens' -i -u 'client-id-ra:clientRaPassword' -X POST

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: text/plain;charset=UTF-8
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

Example Error Response

HTTP/1.1 401 Unauthorized
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Basic
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 79

{
  "error" : "invalid_client",
  "error_description" : "Invalid credentials"
}

Revoke: User-Initiated

POST /oauth2/user/tokens

User-initiated OAuth2 revocation endpoint for removing all tokens belonging to the requesting user. If the optional client_id parameter is provided, all tokens issued to the user for the given client will be removed. Otherwise, all tokens with a user uid matching the user UID of the access token used for authentication will be removed.

Authorization

Bearer <access_token>. Pass the access token using the authorization header field.

Form Parameters

Parameter Optional Description

client_id

true

ID of a client used to narrow the user token revocation.

Example Request

$ curl 'http://localhost:8080/oauth2/user/tokens' -i -X POST \
    -H 'Authorization: Bearer eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZGpka2FES0ZrZCIsImF1ZCI6InNvbWUtY2xpZW50Iiwic2NvcGUiOiJvcGVuaWQiLCJleHAiOjE3MzM3ODY4ODMsImlhdCI6MTczMzc4MTg4MywidHRsIjo1MDAwLCJqdGkiOiJBTEtESERMS0RIS0Q5Njg3SkhLSCJ9.prgGJp5RtEzDl9LEFW0t4lNrxUXBKcBl6vACFeZuNHVaJ9826vsbyndONOQp0nKbYXjCjJ8ZgkcK3gXjrbNapyNoeVCKPNoSn1nleAxszXjcthNJS9CtRV4UWqenQtHT0GLobEAA5ikx4vX6N-kokwoaWBtEKkLGHwRYGr3VZkSL42pfKjnxBzAi8S2xH1-aB0mNVScz3prgC4AFQqwAQ84SOX9itJy516rQGuIR2kJyWho7uhDYrp7csf5GteheCdibJbONf__3EzMAdjFxzHon32ZiByquz7xBR1gKx9_58NBWcz9qmrQF5yeA0bJy2olbZq_am7kxqwsGBkBmPQ' \
    -d 'client_id=some-client'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: text/plain;charset=UTF-8
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

Example Error Response

HTTP/1.1 503 Service Unavailable
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 102

{
  "error" : "operation_failed",
  "error_description" : "1 tokens remain after revocation attempt"
}

Revoke: Admin-Initiated

POST /oauth2/admin/tokens

Administrative token revocation endpoint with the following options:

  • Revoke ALL tokens issued by a specific client (client_id).

  • Revoke ALL tokens issued to a specific user (uid).

  • Revoke ALL tokens with a specific sub claim (sub).

  • Revoke ALL tokens issued to a user by a specific client (client_id, uid)

Note: At least 1 parameter is required.

Authorization

Bearer <access_token>. Pass the access token using the authorization header field.

Form Parameters

Parameter Optional Description

client_id

true

ID of a client to revoke tokens for.

sub

true

Subject claim of the tokens to be revoked.

uid

true

UID attribute of person whose tokens should be revoked.

Example Request

$ curl 'http://localhost:8080/oauth2/admin/tokens' -i -X POST \
    -H 'Authorization: Bearer eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJhZG1pbiIsImF1ZCI6ImFkbWluLWNsaWVudCIsInNjb3BlIjpbIm9wZW5pZCIsImdhdGV3YXk6b2F1dGgyL3Rva2Vucy9hZG1pbiJdLCJleHAiOjE3MzM3ODY4ODMsImlhdCI6MTczMzc4MTg4MywidHRsIjo1MDAwLCJqdGkiOiJBRE1JTjFVU0VSIn0.q-UlOeXalT4XbpwD2lS5lXBKQ-1LA96uemkRqJhScg9evwmSIZPQXf_lVclDaetx15ejqEaCkGbubqDKibtoZL_l4laXB_pwgxNfdY7biiFAN8IrSE2hlH-CjHTllr4dw5ki15ybmvyP9P9_zMT4xr4ZRsegshAkPBsPhHVC4zHD7t_rdVikuCLj9YEtqws6F4Am5XQZ8jJfKvPpPpNpjnZtmlOv7Qus3mtSpDVXiXiS5hq0LmhLgwScV5gRRssG_J9Ut0VJSz_UlOze1Mg6frePWE7IiXjJQiQEZuHhLwBwauaF21UxmHuHO_8sCLJ0sG6838T23AO_CAuwwSLQaw' \
    -d 'client_id=iss-client&uid=114839'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: text/plain;charset=UTF-8
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

Example Error Response

HTTP/1.1 400 Bad Request
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
X-Frame-Options: DENY
Content-Length: 102

{
  "error" : "invalid_request",
  "error_description" : "sub or uid, and/or client_id is required."
}

Token Info

POST /oauth2/tinfo

Authorization

The client must pass its client_id and client_secret in the authorization header through Basic HTTP authorization via HEADER. The secret is Basic Base64Encode(client_id:client_secret).

Form Parameters

Parameter Optional Description

token

false

The token to look up.

token_type_hint

true

Token type hint.

Example Request

$ curl 'http://localhost:8080/oauth2/tinfo' -i -u 'client-id-token-info-pos:client_pw' -X POST \
    -d 'token=eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIxU09NRSNTVUJKRUNUMiIsImF1ZCI6ImNsaWVudC1pZC10b2tlbi1pbmZvLXBvcyIsInNjb3BlIjoib3BlbmlkIiwiZXhwIjoxNzMzNzg2ODkzLCJpYXQiOjE3MzM3ODE4OTMsInR0bCI6NTAwMCwianRpIjoidG9rZW4taWQtdG9rZW4taW5mby1wb3MifQ.K3WuwaCHYSpGuQZsWtJ-Vdvb3xSRXI77FFulgBsGAUxSYEpUKMKDzpDIlU86xeREibvNqAYnAMzGGP8Gwl53ravqDTeNXj-ACM_N0bRHAZapse-JP-rb2BwUMh5zSlvwa2MIpwsqGP55_irmu18eaxQVlfxKbvUDQdRXwNcMSEK33SpUj6_6ywBfrDxmVwpahGT8_67feUhbXQ9tfkVsXuDTUsyFvC0wgVz-9QOeHbSUQXYyrBmpn-O3fq7xdNF1WZmZAm1-HOKdhe_mgrYxZ0cAaNRRmo_-chiRTtFq-Lk4ugq9ydgvo9tnHcaLMqYtlukhD_nHiuW7hiqX0sPJrA'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 151
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

{"sub":"1SOME#SUBJECT2","aud":"client-id-token-info-pos","scope":"openid","exp":1733786893,"iat":1733781893,"ttl":5000,"jti":"token-id-token-info-pos"}

Sample Expired Token

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Content-Length: 22
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

{
  "active" : false
}

User Info

GET /oidc/uinfo

OpenID Connect UserInfo endpoint The parameters are those supported by the AWS Cognito USERINFO endpoint as this endpoint simply proxies to the AWS endpoint.

Authorization

Bearer <access_token>. Pass the access token using the authorization header field.

Example Request

$ curl 'http://localhost:8080/oidc/uinfo' -i -X GET \
    -H 'Authorization: Bearer eyJraWQiOiIyNzE4MzgyMTM0MDE2NzEyMzAwOTE4IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJtY2t4QWlUZHNBa3hNZWciLCJhdWQiOiJzb21lYm9keSIsInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwibmFtZSIsImwiXSwiaXNzIjoic29tZWJvZHkiLCJpZF90b2tlbiI6IkNZVXRNa3NPbE9sTktDeGxmRE1sT2UyVCIsImFjdGl2ZSI6dHJ1ZSwiZXhwIjoxNzMzNzgxOTA2LCJpYXQiOjE3MzM3ODE4NzYsInR0bCI6MzAsImp0aSI6IkJPQkFDQ0VTU1RPS0VOMDk0NTdER0QifQ.5BIHTCSFYIGCzPFoWZ_G11YkytHZq5RtlhfY_RBQcmnM711mnPy149qriXX-OupTnRWLgBTHuerdJa3wtA5UpCKJjW2UHwykYUti0AtpS3jUpkrfYGtZYHiQzRZxISCAqHrbblJh_scTXr7r-sFc2dvDDylHu4GCZefSx-R3tXO0dNNR89AXo0BVavxbwTrbjbmdFuXSSk-IApZFlO_rzrCXAuBsM1_7LWIy-iiviXUIV0gZwBV2HfE4oK5asEK6dZRjdLtyKUAiuhiXMSDJWNzD3AV_9s4fz_JQiLRGzAmiP_PFYVBo0CIxMbEZdcbfiBulGessO5zkVahdW-QHsA'

Example Response

HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 220

{"sub":"mckxAiTdsAkxMeg","aud":"somebody","scope":[],"iss":"somebody","name":"Bob Bobberann","active":true,"exp":1733781906,"l":"Bobsville","iat":1733781876,"ttl":30,"jti":"CYUtMksOlOlNKCxlfDMlOe2T","email":"bob@vt.edu"}

Example Error Response

HTTP/1.1 403 Forbidden
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Bearer error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
X-Content-Type-Options: nosniff
X-XSS-Protection: 0
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

Known Compatibility Issues

  1. Spring Security < 5.2.0.RELEASE does not handle the JWK response correctly and will cause token exchange to fail. Use version 5.2.0 or greater, if at all possible. If that is not an option, you may have to write a custom NimbusAuthorizationCodeTokenResponseClient to handle the tokenResponse correctly.