| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 | 
							
- [[how-to-jpa]]
 
- = How-to: Implement core services with JPA
 
- :index-link: ../how-to.html
 
- :docs-dir: ..
 
- This guide shows how to implement the xref:core-model-components.adoc[core services] of xref:index.adoc[Spring Authorization Server] with JPA.
 
- The purpose of this guide is to provide a starting point for implementing these services yourself, with the intention that you can make modifications to suit your needs.
 
- * xref:guides/how-to-jpa.adoc#define-data-model[Define the data model]
 
- * xref:guides/how-to-jpa.adoc#create-jpa-entities[Create JPA entities]
 
- * xref:guides/how-to-jpa.adoc#create-spring-data-repositories[Create Spring Data repositories]
 
- * xref:guides/how-to-jpa.adoc#implement-core-services[Implement core services]
 
- [[define-data-model]]
 
- == Define the data model
 
- This guide provides a starting point for the data model and uses the simplest possible structure and data types.
 
- To come up with the initial schema, we begin by reviewing the xref:core-model-components.adoc[domain objects] used by the core services.
 
- [NOTE]
 
- Except for token, state, metadata, settings, and claims values, we use the JPA default column length of 255 for all columns.
 
- In reality, the length and even type of columns you use may need to be customized.
 
- You are encouraged to experiment and test before deploying to production.
 
- * xref:guides/how-to-jpa.adoc#client-schema[Client Schema]
 
- * xref:guides/how-to-jpa.adoc#authorization-schema[Authorization Schema]
 
- * xref:guides/how-to-jpa.adoc#authorization-consent-schema[Authorization Consent Schema]
 
- [[client-schema]]
 
- === Client Schema
 
- The xref:core-model-components.adoc#registered-client[`RegisteredClient`] domain object contains a few multi-valued fields and some settings fields that require storing arbitrary key/value data.
 
- The following listing shows the `client` schema.
 
- .Client Schema
 
- [source,sql]
 
- ----
 
- CREATE TABLE client (
 
-     id varchar(255) NOT NULL,
 
-     clientId varchar(255) NOT NULL,
 
-     clientIdIssuedAt timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL,
 
-     clientSecret varchar(255) DEFAULT NULL,
 
-     clientSecretExpiresAt timestamp DEFAULT NULL,
 
-     clientName varchar(255) NOT NULL,
 
-     clientAuthenticationMethods varchar(1000) NOT NULL,
 
-     authorizationGrantTypes varchar(1000) NOT NULL,
 
-     redirectUris varchar(1000) DEFAULT NULL,
 
-     postLogoutRedirectUris varchar(1000) DEFAULT NULL,
 
-     scopes varchar(1000) NOT NULL,
 
-     clientSettings varchar(2000) NOT NULL,
 
-     tokenSettings varchar(2000) NOT NULL,
 
-     PRIMARY KEY (id)
 
- );
 
- ----
 
- [[authorization-schema]]
 
- === Authorization Schema
 
- The xref:core-model-components.adoc#oauth2-authorization[`OAuth2Authorization`] domain object is more complex and contains several multi-valued fields as well as numerous arbitrarily long token values, metadata, settings and claims values.
 
- The built-in JDBC implementation utilizes a flattened structure that prefers performance over normalization, which we adopt here as well.
 
- [CAUTION]
 
- It has been difficult to find a flattened database schema that works well in all cases and with all database vendors.
 
- You may need to normalize or heavily alter the following schema for your needs.
 
- The following listing shows the `authorization` schema.
 
- .Authorization Schema
 
- [source,sql]
 
- ----
 
- CREATE TABLE authorization (
 
-     id varchar(255) NOT NULL,
 
-     registeredClientId varchar(255) NOT NULL,
 
-     principalName varchar(255) NOT NULL,
 
-     authorizationGrantType varchar(255) NOT NULL,
 
-     authorizedScopes varchar(1000) DEFAULT NULL,
 
-     attributes varchar(4000) DEFAULT NULL,
 
-     state varchar(500) DEFAULT NULL,
 
-     authorizationCodeValue varchar(4000) DEFAULT NULL,
 
-     authorizationCodeIssuedAt timestamp DEFAULT NULL,
 
-     authorizationCodeExpiresAt timestamp DEFAULT NULL,
 
-     authorizationCodeMetadata varchar(2000) DEFAULT NULL,
 
-     accessTokenValue varchar(4000) DEFAULT NULL,
 
-     accessTokenIssuedAt timestamp DEFAULT NULL,
 
-     accessTokenExpiresAt timestamp DEFAULT NULL,
 
-     accessTokenMetadata varchar(2000) DEFAULT NULL,
 
-     accessTokenType varchar(255) DEFAULT NULL,
 
-     accessTokenScopes varchar(1000) DEFAULT NULL,
 
-     refreshTokenValue varchar(4000) DEFAULT NULL,
 
-     refreshTokenIssuedAt timestamp DEFAULT NULL,
 
-     refreshTokenExpiresAt timestamp DEFAULT NULL,
 
-     refreshTokenMetadata varchar(2000) DEFAULT NULL,
 
-     oidcIdTokenValue varchar(4000) DEFAULT NULL,
 
-     oidcIdTokenIssuedAt timestamp DEFAULT NULL,
 
-     oidcIdTokenExpiresAt timestamp DEFAULT NULL,
 
-     oidcIdTokenMetadata varchar(2000) DEFAULT NULL,
 
-     oidcIdTokenClaims varchar(2000) DEFAULT NULL,
 
-     userCodeValue varchar(4000) DEFAULT NULL,
 
-     userCodeIssuedAt timestamp DEFAULT NULL,
 
-     userCodeExpiresAt timestamp DEFAULT NULL,
 
-     userCodeMetadata varchar(2000) DEFAULT NULL,
 
-     deviceCodeValue varchar(4000) DEFAULT NULL,
 
-     deviceCodeIssuedAt timestamp DEFAULT NULL,
 
-     deviceCodeExpiresAt timestamp DEFAULT NULL,
 
-     deviceCodeMetadata varchar(2000) DEFAULT NULL,
 
-     PRIMARY KEY (id)
 
- );
 
- ----
 
- [[authorization-consent-schema]]
 
- === Authorization Consent Schema
 
- The xref:core-model-components.adoc#oauth2-authorization-consent[`OAuth2AuthorizationConsent`] domain object is the simplest to model and contains only a single multi-valued field in addition to a composite key.
 
- The following listing shows the `authorizationconsent` schema.
 
- .Authorization Consent Schema
 
- [source,sql]
 
- ----
 
- CREATE TABLE authorizationConsent (
 
-     registeredClientId varchar(255) NOT NULL,
 
-     principalName varchar(255) NOT NULL,
 
-     authorities varchar(1000) NOT NULL,
 
-     PRIMARY KEY (registeredClientId, principalName)
 
- );
 
- ----
 
- [[create-jpa-entities]]
 
- == Create JPA entities
 
- The preceding schema examples provide a reference for the structure of the entities we need to create.
 
- [NOTE]
 
- The following entities are minimally annotated and are just examples.
 
- They allow the schema to be created dynamically and therefore do not require the above sql scripts to be executed manually.
 
- * xref:guides/how-to-jpa.adoc#client-entity[Client Entity]
 
- * xref:guides/how-to-jpa.adoc#authorization-entity[Authorization Entity]
 
- * xref:guides/how-to-jpa.adoc#authorization-consent-entity[Authorization Consent Entity]
 
- [[client-entity]]
 
- === Client Entity
 
- The following listing shows the `Client` entity, which is used to persist information mapped from the xref:core-model-components.adoc#registered-client[`RegisteredClient`] domain object.
 
- [[sample.jpa.entity.client]]
 
- .Client Entity
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/entity/client/Client.java[]
 
- ----
 
- [[authorization-entity]]
 
- === Authorization Entity
 
- The following listing shows the `Authorization` entity, which is used to persist information mapped from the xref:core-model-components.adoc#oauth2-authorization[`OAuth2Authorization`] domain object.
 
- [[sample.jpa.entity.authorization]]
 
- .Authorization Entity
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/entity/authorization/Authorization.java[]
 
- ----
 
- [[authorization-consent-entity]]
 
- === Authorization Consent Entity
 
- The following listing shows the `AuthorizationConsent` entity, which is used to persist information mapped from the xref:core-model-components.adoc#oauth2-authorization-consent[`OAuth2AuthorizationConsent`] domain object.
 
- [[sample.jpa.entity.authorizationconsent]]
 
- .Authorization Consent Entity
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/entity/authorizationconsent/AuthorizationConsent.java[]
 
- ----
 
- [[create-spring-data-repositories]]
 
- == Create Spring Data repositories
 
- By closely examining the interfaces of each core service and reviewing the `Jdbc` implementations, we can derive a minimal set of queries needed for supporting a JPA version of each interface.
 
- * xref:guides/how-to-jpa.adoc#client-repository[Client Repository]
 
- * xref:guides/how-to-jpa.adoc#authorization-repository[Authorization Repository]
 
- * xref:guides/how-to-jpa.adoc#authorization-consent-repository[Authorization Consent Repository]
 
- [[client-repository]]
 
- === Client Repository
 
- The following listing shows the `ClientRepository`, which is able to find a xref:guides/how-to-jpa.adoc#client-entity[`Client`] by the `id` and `clientId` fields.
 
- [[sample.jpa.repository.client]]
 
- .Client Repository
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/repository/client/ClientRepository.java[]
 
- ----
 
- [[authorization-repository]]
 
- === Authorization Repository
 
- The following listing shows the `AuthorizationRepository`, which is able to find an xref:guides/how-to-jpa.adoc#authorization-entity[`Authorization`] by the `id` field as well as the `state`, `authorizationCodeValue`, `accessTokenValue`, `refreshTokenValue`, `userCodeValue` and `deviceCodeValue` token fields.
 
- It also allows querying a combination of token fields.
 
- [[sample.jpa.repository.authorization]]
 
- .Authorization Repository
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/repository/authorization/AuthorizationRepository.java[]
 
- ----
 
- [[authorization-consent-repository]]
 
- === Authorization Consent Repository
 
- The following listing shows the `AuthorizationConsentRepository`, which is able to find and delete an xref:guides/how-to-jpa.adoc#authorization-consent-entity[`AuthorizationConsent`] by the `registeredClientId` and `principalName` fields that form a composite primary key.
 
- [[sample.jpa.repository.authorizationconsent]]
 
- .Authorization Consent Repository
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/repository/authorizationconsent/AuthorizationConsentRepository.java[]
 
- ----
 
- [[implement-core-services]]
 
- == Implement core services
 
- With the above xref:guides/how-to-jpa.adoc#create-jpa-entities[entities] and xref:guides/how-to-jpa.adoc#create-spring-data-repositories[repositories], we can begin implementing the core services.
 
- By reviewing the `Jdbc` implementations, we can derive a minimal set of internal utilities for converting to and from string values for enumerations and reading and writing JSON data for attributes, settings, metadata and claims fields.
 
- [CAUTION]
 
- Keep in mind that writing JSON data to text columns with a fixed length has proven problematic with the `Jdbc` implementations.
 
- While these examples continue to do so, you may need to split these fields out into a separate table or data store that supports arbitrarily long data values.
 
- * <<registered-client-repository>>
 
- * xref:guides/how-to-jpa.adoc#authorization-service[Authorization Service]
 
- * xref:guides/how-to-jpa.adoc#authorization-consent-service[Authorization Consent Service]
 
- [[registered-client-repository]]
 
- === Registered Client Repository
 
- The following listing shows the `JpaRegisteredClientRepository`, which uses a xref:guides/how-to-jpa.adoc#client-repository[`ClientRepository`] for persisting a xref:guides/how-to-jpa.adoc#client-entity[`Client`] and maps to and from the xref:core-model-components.adoc#registered-client[`RegisteredClient`] domain object.
 
- [[sample.jpa.service.client]]
 
- .`RegisteredClientRepository` Implementation
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/service/client/JpaRegisteredClientRepository.java[]
 
- ----
 
- [[authorization-service]]
 
- === Authorization Service
 
- The following listing shows the `JpaOAuth2AuthorizationService`, which uses an xref:guides/how-to-jpa.adoc#authorization-repository[`AuthorizationRepository`] for persisting an xref:guides/how-to-jpa.adoc#authorization-entity[`Authorization`] and maps to and from the xref:core-model-components.adoc#oauth2-authorization[`OAuth2Authorization`] domain object.
 
- [[sample.jpa.service.authorization]]
 
- .`OAuth2AuthorizationService` Implementation
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/service/authorization/JpaOAuth2AuthorizationService.java[]
 
- ----
 
- [[authorization-consent-service]]
 
- === Authorization Consent Service
 
- The following listing shows the `JpaOAuth2AuthorizationConsentService`, which uses an xref:guides/how-to-jpa.adoc#authorization-consent-repository[`AuthorizationConsentRepository`] for persisting an xref:guides/how-to-jpa.adoc#authorization-consent-entity[`AuthorizationConsent`] and maps to and from the xref:core-model-components.adoc#oauth2-authorization-consent[`OAuth2AuthorizationConsent`] domain object.
 
- [[sample.jpa.service.authorizationconsent]]
 
- .`OAuth2AuthorizationConsentService` Implementation
 
- [source,java]
 
- ----
 
- include::{examples-dir}/main/java/sample/jpa/service/authorizationconsent/JpaOAuth2AuthorizationConsentService.java[]
 
- ----
 
 
  |