LIGHT

  • News
  • Docs
  • Community
  • Reddit
  • GitHub
Star

Client Registration

Before initiating the protocol, the client registers with the authorization server. The method through which the client registers with the authorization server is not defined in OAuth 2.0 specification.

As an extension, we have implemented client registration/on-boarding as a microservice that exposes several endpoints.

Unlike other OAuth 2.0 providers, we have extended the client registration to define the relationship between client and service (service registers itself) and service’s endpoints.

Before digging into the details of implementation, let’s clarify some concepts about the client.

Client Type

OAuth 2.0 defines two client types, based on their ability to authenticate securely with the authorization server (i.e., ability to maintain the confidentiality of their client credentials).

  • confidential

Clients capable of maintaining the confidentiality of their credentials (e.g., client implemented on a secure server with restricted access to the client credentials), or capable of secure client authentication using other means.

  • public

Clients incapable of maintaining the confidentiality of their credentials (e.g., clients executing on the device used by the resource owner, such as an installed native application or a web browser-based application), and incapable of secure client authentication via any other means.

Extended Client Type

Above are standard client types defined in the specification. We have added another two client types to control which client can issue resource owner password credentials’ grant requests or customized grant types, and which client will receive by-reference tokens or by-value tokens.

  • trusted

These clients are marked as trusted and they are the only clients that can issue the resource owner password credentials grant type. For the API management team, please make sure that trusted clients are also confidential. The client and resource must be deployed and managed by the same organization as this flow is not as secure as authorization code and client credentials flows.

When using customized grant types, the client must be marked as trusted as these grant types normally make a lot of assumptions and might not be working at the same security level as authorization code and client credentials grant types.

  • external

For some of the organizations, it is not comfortable to send a JWT to a third party client, user’s device or browser. In this case, the client can be registered as external client type and the token issued to the client will be just a UUID. Once the requests come back to the corporate network, a BFF can go to the AS to exchange the by-reference token to a JWT. A BFF client id can be registered as well optionally so that the AS can authorize only one client can send request to exchange the opaque token to a JWT.

The client type designation is based on the authorization server’s definition of secure authentication and its acceptable exposure levels of client credentials. The authorization server does not make assumptions about the client type.

A client may be implemented as a distributed set of components or services, each with a different client type and security context (e.g., a distributed client with both a confidential server-based component and a public browser-based component). In this case, the client should register each component or service as a separate client.

In a microservices architecture, a service might call other services to fulfill its request; in this case, it should register itself as a service and a client. That means the owner needs to follow both service on-boarding and client on-boarding processes.

Client Profile

This specification has been designed around the following client profiles:

  • web application (web server)

A web application is a confidential client running on a web server. Resource owners access the client via an HTML user interface rendered in a user-agent on the device used by the resource owner. The client credentials as well as any access token issued to the client are stored on the web server and are not exposed to or accessible by the resource owner.

  • user-agent-based application (browser)

A user-agent-based application is a public client in which the client code is downloaded from a web server and executes within a user-agent (e.g., web browser) on the device used by the resource owner. Protocol data and credentials are easily accessible (and often visible) to the resource owner. Since such applications reside within the user-agent, they can make seamless use of the user-agent capabilities when requesting authorization.

  • native application (mobile)

A native application is a public client installed and executed on the device used by the resource owner. Protocol data and credentials are accessible to the resource owner. It is assumed that any client authentication credentials included in the application can be extracted. On the other hand, dynamically issued credentials such as access tokens or refresh tokens can receive an acceptable level of protection. At a minimum, these credentials are protected from hostile servers with which the application may interact. On some platforms, these credentials might be protected from other applications residing on the same device.

The specification only mentioned above client profiles and the following two profiles are added in our OAuth 2.0 implementation.

  • batch application (batch)

Batch jobs are very similar with web application but they are managed by enterprise scheduler and executed in a projected environment. It is considered as confidential client.

  • service (service)

Services are usually protected as resources but in a microservices architecture, a service can also be a client to call other services or resources. These services normally running within light-weight containers in a secured environment. And they are considered as confidential clients.

Client Identifier

The authorization server issues the registered client a client identifier - a unique string representing the registration information provided by the client. The client identifier is not a secret; it is exposed to the resource owner and MUST NOT be used alone for client authentication. The client identifier is unique to the authorization server. In our implementation, it is a UUID generated on the server. Here is an example:

f7d42348-c647-4efb-a52d-4c5787421e72

Client Secret

Clients in possession of a client secret MAY use the HTTP Basic authentication scheme as defined in [RFC2617] to authenticate with the authorization server. The client identifier is encoded using the “application/x-www-form-urlencoded” encoding algorithm , and the encoded value is used as the username; the client secret is encoded using the same algorithm and used as the password. The authorization server supports the HTTP Basic authentication scheme for authenticating clients that were issued a client secret.

The client secret is generated on the client service and sent in the registration response. This is the only time you can receive the client secret. It MUST be write down as there is no way to recover it later on.

For example (with extra line breaks for display purposes only):

     Authorization: Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3

Other Authenticate Class

When registering a client, you can specify which authenticate class will be used in the authenticate_class column. Your own authenticate class can be added as a plugin in the service.yml configuration file. In a typical organization, you might need to support various authentication providers. For example, your API portal supports employees to be authenticated with SPNEGO/Kerberos SSO with AD and customers with a user table in a database.

By default, we have implemented LDAP, SPNEGO/Kerberos, User table and GitHub repo for authentication and authorization. Other authentication method can be easily supported if there are requests from our users.

Unregistered Clients

Due to security reasons, all clients must be registered before being authenticated on the server. Unregistered clients are not supported on this implementation.

Client Micro Service

This service has several endpoints and listening to port 6884.

Here is the specification.

swagger: '2.0'
info:
  version: 1.0.0
  title: OAuth2 Client Registration
  description: OAuth2 Client Registration microservices endpoints.
  contact:
    email: [email protected]
  license:
    name: Apache 2.0
    url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
host: oauth2.networknt.com
schemes:
  - http
  - https
consumes:
  - application/json
produces:
  - application/json
paths:
  /oauth2/client:
    post:
      description: Return a client object
      operationId: createClient
      parameters:
        - in: body
          name: body
          description: Client object that needs to be added
          required: true
          schema:
            $ref: '#/definitions/Client'
      responses:
        '200':
          description: Successful response
          schema:
            $ref: '#/definitions/Client'
      security:
        - client_auth:
            - oauth.client.w
    put:
      description: Return the updated client
      operationId: updateClient
      parameters:
        - in: body
          name: body
          description: Client object that needs to be added
          required: true
          schema:
            $ref: '#/definitions/Client'
      responses:
        '200':
          description: Successful response
          schema:
            $ref: '#/definitions/Client'
      security:
        - client_auth:
            - oauth.client.w
    get:
      description: Return all clients
      operationId: getAllClient
      parameters:
        - name: page
          in: query
          description: Page number
          required: true
          type: integer
          format: int32
        - name: pageSize
          in: query
          description: Pag size
          required: false
          type: integer
          format: int32
        - name: clientName
          in: query
          description: Partial clientName for filter
          required: false
          type: string
      responses:
        '200':
          description: successful operation
          schema:
            type: array
            items:
              $ref: '#/definitions/Client'
      security:
        - client_auth:
            - oauth.client.r
  '/oauth2/client/{clientId}':
    delete:
      description: Delete a client by Id
      operationId: deleteClient
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
      responses:
        '400':
          description: Invalid clientId supplied
        '404':
          description: Client not found
      security:
        - client_auth:
            - oauth.client.w
    get:
      description: Get a client by Id
      operationId: getClient
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
      responses:
        '200':
          description: Successful response
          schema:
            $ref: '#/definitions/Client'
        '400':
          description: Invalid clientId supplied
        '404':
          description: Client not found
      security:
        - client_auth:
            - oauth.client.r
            - oauth.client.w
  '/oauth2/client/{clientId}/service':
    delete:
      description: Delete all associated services for a client by clientId
      operationId: deleteAllClientService
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
      responses:
        '200':
          description: Successful response
        '404':
          description: Client not found
      security:
        - client_auth:
            - oauth.client.w
    get:
      description: Get all associated services and endpoints by clientId
      operationId: getAllClientService
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
      responses:
        '200':
          description: Successful response
        '404':
          description: Client not found
      security:
        - client_auth:
            - oauth.client.r
            - oauth.client.w
  '/oauth2/client/{clientId}/service/{serviceId}':
    post:
      description: Link a service and its endpoints to a client
      operationId: linkClientService
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
        - name: serviceId
          in: path
          description: Service Id
          required: true
          type: string
        - name: body
          in: body
          description: A list of endpoints that needs to be linked to the client
          required: true
          schema:
            type: array
            items:
              type: string
      responses:
        '200':
          description: Successful response
        '404':
          description: Client or service not found
      security:
        - client_auth:
            - oauth.client.w
    delete:
      description: Delete all endpoints of a service for a client
      operationId: deleteClientService
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
        - name: serviceId
          in: path
          description: Service Id
          required: true
          type: string
      responses:
        '200':
          description: Successful response
        '404':
          description: Client or service not found
      security:
        - client_auth:
            - oauth.client.w
    get:
      description: Get linked endpoints of a service from a client
      operationId: getClientService
      parameters:
        - name: clientId
          in: path
          description: Client Id
          required: true
          type: string
        - name: serviceId
          in: path
          description: Service Id
          required: true
          type: string
      responses:
        '200':
          description: Successful response
        '404':
          description: Client or service not found
      security:
        - client_auth:
            - oauth.client.r
            - oauth.client.w
securityDefinitions:
  client_auth:
    type: oauth2
    authorizationUrl: 'http://localhost:8888/oauth2/code'
    flow: implicit
    scopes:
      oauth.client.w: write oauth client
      oauth.client.r: read oauth client
definitions:
  Client:
    type: object
    required:
      - clientType
      - clientProfile
      - clientName
      - clientDesc
      - ownerId
      - scope
    properties:
      clientId:
        type: string
        description: a unique client id
      clientSecret:
        type: string
        description: client secret
      clientType:
        type: string
        description: client type
        enum:
          - confidential
          - public
          - trusted
          - external
      clientProfile:
        type: string
        description: client profile
        enum:
          - webserver
          - browser
          - mobile
          - service
          - batch
      clientName:
        type: string
        description: client name
      clientDesc:
        type: string
        description: client description
      ownerId:
        type: string
        description: client owner id
      scope:
        type: string
        description: client scope separated by space
      customClaim:
        type: string
        description: custom claim string in JSON format
      redirectUri:
        type: string
        description: redirect uri
      authenticateClass:
        type: string
        description: authenticate class
      derefClientId:
        type: string
        description: the client that can call de-reference token endpoint

/oauth2/client/{clientId}@delete

This endpoint is used to delete existing client. The following validation will be performed in the service.

  • If clientId cannot be found in the in-memory grid, then the following error will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }

/oauth2/client/{clientId}@get

This endpoint is used to get a particular client with clientId. The following validation will be performed in the service.

  • If clientId cannot be found in the in-memory grid, then the following error will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }

/oauth2/[email protected]

This endpoint gets all the clients from client service that were filtered and sorted on clientName. A page query parameter is mandatory and pageSize and clientName filters are optional.

  • page

Page number which must be specified. It starts with 1 and an empty list will be returned if the page is greater than the last page.

  • pageSize

Default pageSize is 10, and you can overwrite it with another number. Please don’t use a big number due to performance reason.

  • clientName

This is the only filter available and it supports filter by start with a few characters. For example, “clientName=abc” means any clientName starts with “abc”. The result is also sorted by clientName in the pagination.

The following validation will be performed in the service.

  • If page is missing from the query parameter, an error will be returned.
  "ERR11000": {
    "statusCode": 400,
    "code": "ERR11000",
    "message": "VALIDATOR_REQUEST_PARAMETER_QUERY_MISSING",
    "description": "Query parameter '%s' is required on path '%s' but not found in request."
  }

/oauth2/[email protected]

This endpoint is used to create a new client. This usually will be called from light-portal and the following validations will be performed before a new client is added.

  • Verify that clientId exist in the cache. The clientId is generated as a UUID so this cannot be triggered. It is implemented this way just want to be in sync with other services.
  "ERR12019": {
    "statusCode": 400,
    "code": "ERR12019",
    "message": "CLIENT_ID_EXISTS",
    "description": "Client id %s exists."
  }
  • Verify that ownerId is in user cache in memory. If it doesn’t exist, the following error will be returned.
  "ERR12013": {
    "statusCode": 404,
    "code": "ERR12013",
    "message": "USER_NOT_FOUND",
    "description": "User %s is not found."
  }
  • Make sure the clientType is from a list of valid values. If not, an error message will be returned.
  "ERR11004": {
    "statusCode": 400,
    "code": "ERR11004",
    "message": "VALIDATOR_SCHEMA",
    "description": "Schema Validation Error - %s"
  }
  • Make sure that clientProfile is from a list of valid values. If not, an error message will be returned.
  "ERR11004": {
    "statusCode": 400,
    "code": "ERR11004",
    "message": "VALIDATOR_SCHEMA",
    "description": "Schema Validation Error - %s"
  }

/oauth2/[email protected]

This endpoint is used to update an existing client. This usually will be called from light-portal and the following validations will be performed before a client is updated.

  • Verify that clientId exist in the cache. If clientId doesn’t existing the cache, an error message will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }
  • Verify that ownerId is in user cache in memory. If it doesn’t exist, the following error will be returned.
  "ERR12013": {
    "statusCode": 404,
    "code": "ERR12013",
    "message": "USER_NOT_FOUND",
    "description": "User %s is not found."
  }
  • Make sure the clientType is from a list of valid values. If not, an error message will be returned.
  "ERR11004": {
    "statusCode": 400,
    "code": "ERR11004",
    "message": "VALIDATOR_SCHEMA",
    "description": "Schema Validation Error - %s"
  }
  • Make sure that clientProfile is from a list of valid values. If not, an error message will be returned.
  "ERR11004": {
    "statusCode": 400,
    "code": "ERR11004",
    "message": "VALIDATOR_SCHEMA",
    "description": "Schema Validation Error - %s"
  }

/oauth2/client/{clientId}/[email protected]

This endpoint get all the linked services and endpoints for a particular client.

Here is an example of response body.

{"AACT0001":["/v1/[email protected]"]}
  • Verify that clientId exist in the cache. If clientId doesn’t existing the cache, an error message will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }

/oauth2/client/{clientId}/[email protected]

This endpoint deletes all services and endpoints for a particular client. It is a very dangerous API and you must be careful in using it. It is supposed to be used only when a client is retired.

After the links are removed, the client’s scope will be recalculated which normally means there is no scope for this client.

The response body will contains the old scope and new scope for the client. Here is an example.

{"old_scope":"petstore.r petstore.w","new_scope":""}
  • Verify that clientId exist in the cache. If clientId doesn’t existing the cache, an error message will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }

/oauth2/client/{clientId}/service/{serviceId}@post

This endpoint adds one or more endpoints of a service to a client. It removes all existing links and insert new ones. Once the insert is done, the client’s scope is recalculated based on the updated info.

The response body will contain the old scope and new scope for the client. Here is an example.

{"old_scope":"petstore.r petstore.w","new_scope":"data.w data.r"}
  • Verify that clientId exist in the cache. If clientId doesn’t existing the cache, an error message will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }
  • If serviceId cannot be found in the service cache, then the following error will be returned.
  "ERR12015": {
    "statusCode": 404,
    "code": "ERR12015",
    "message": "SERVICE_NOT_FOUND",
    "description": "Service %s is not found."
  }

/oauth2/client/{clientId}/service/{serviceId}@delete

This endpoint deletes endpoints for a service that is linked to a particular client. Once the action is done, it will recalculate scope for the client to reflect the changes.

The response body will contains the old scope and new scope for the client. Here is an example.

{"old_scope":"petstore.r petstore.w","new_scope":""}
  • Verify that clientId exist in the cache. If clientId doesn’t existing the cache, an error message will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }
  • If serviceId cannot be found in the service cache, then the following error will be returned.
  "ERR12015": {
    "statusCode": 404,
    "code": "ERR12015",
    "message": "SERVICE_NOT_FOUND",
    "description": "Service %s is not found."
  }

/oauth2/client/{clientId}/service/{serviceId}@get

This endpoint gets a list of endpoints of a service linked to a particular client.

The response body will contains a list of linked endpoints. Here is an example.

["/v1/[email protected]"]
  • Verify that clientId exist in the cache. If clientId doesn’t existing the cache, an error message will be returned.
  "ERR12014": {
    "statusCode": 404,
    "code": "ERR12014",
    "message": "CLIENT_NOT_FOUND",
    "description": "Client %s is not found."
  }
  • If serviceId cannot be found in the service cache, then the following error will be returned.
  "ERR12015": {
    "statusCode": 404,
    "code": "ERR12015",
    "message": "SERVICE_NOT_FOUND",
    "description": "Service %s is not found."
  }
  • About Light
    • Overview
    • Testimonials
    • What is Light
    • Features
    • Principles
    • Benefits
    • Roadmap
    • Community
    • Articles
    • Videos
    • License
    • Why Light Platform
  • Getting Started
    • Get Started Overview
    • Environment
    • Light Codegen Tool
    • Light Rest 4j
    • Light Tram 4j
    • Light Graphql 4j
    • Light Hybrid 4j
    • Light Eventuate 4j
    • Light Oauth2
    • Light Portal Service
    • Light Proxy Server
    • Light Router Server
    • Light Config Server
    • Light Saga 4j
    • Light Session 4j
    • Webserver
    • Websocket
    • Spring Boot Servlet
  • Architecture
    • Architecture Overview
    • API Category
    • API Gateway
    • Architecture Patterns
    • CQRS
    • Eco System
    • Event Sourcing
    • Fail Fast vs Fail Slow
    • Integration Patterns
    • JavaEE declining
    • Key Distribution
    • Microservices Architecture
    • Microservices Monitoring
    • Microservices Security
    • Microservices Traceability
    • Modular Monolith
    • Platform Ecosystem
    • Plugin Architecture
    • Scalability and Performance
    • Serverless
    • Service Collaboration
    • Service Mesh
    • SOA
    • Spring is bloated
    • Stages of API Adoption
    • Transaction Management
    • Microservices Cross-cutting Concerns Options
    • Service Mesh Plus
    • Service Discovery
  • Design
    • Design Overview
    • Design First vs Code First
    • Desgin Pattern
    • Service Evolution
    • Consumer Contract and Consumer Driven Contract
    • Handling Partial Failure
    • Idempotency
    • Server Life Cycle
    • Environment Segregation
    • Database
    • Decomposition Patterns
    • Http2
    • Test Driven
    • Multi-Tenancy
    • Why check token expiration
    • WebServices to Microservices
  • Cross-Cutting Concerns
    • Concerns Overview
  • API Styles
    • Light-4j for absolute performance
    • Style Overview
    • Distributed session on IMDG
    • Hybrid Serverless Modularized Monolithic
    • Kafka - Event Sourcing and CQRS
    • REST - Representational state transfer
    • Web Server with Light
    • Websocket with Light
    • Spring Boot Integration
    • Single Page Application
    • GraphQL - A query language for your API
    • Light IBM MQ
    • Light AWS Lambda
    • Chaos Monkey
  • Infrastructure Services
    • Service Overview
    • Light Proxy
    • Light Mesh
    • Light Router
    • Light Portal
    • Messaging Infrastructure
    • Centralized Logging
    • COVID-19
    • Light OAuth2
    • Metrics and Alerts
    • Config Server
    • Tokenization
    • Light Controller
  • Tool Chain
    • Tool Chain Overview
  • Utility Library
  • Service Consumer
    • Service Consumer
  • Development
    • Development Overview
  • Deployment
    • Deployment Overview
    • Frontend Backend
    • Linux Service
    • Windows Service
    • Install Eventuate on Windows
    • Secure API
    • Client vs light-router
    • Memory Limit
    • Deploy to Kubernetes
  • Benchmark
    • Benchmark Overview
  • Tutorial
    • Tutorial Overview
  • Troubleshooting
    • Troubleshoot
  • FAQ
    • FAQ Overview
  • Milestones
  • Contribute
    • Contribute to Light
    • Development
    • Documentation
    • Example
    • Tutorial
“Client Registration” was last updated: April 5, 2021: Issue246 (#256) (50b1c10)
Improve this page
  • News
  • Docs
  • Community
  • Reddit
  • GitHub
  • About Light
  • Getting Started
  • Architecture
  • Design
  • Cross-Cutting Concerns
  • API Styles
  • Infrastructure Services
  • Tool Chain
  • Utility Library
  • Service Consumer
  • Development
  • Deployment
  • Benchmark
  • Tutorial
  • Troubleshooting
  • FAQ
  • Milestones
  • Contribute