### Resource Owner Password Credentials Grant Examples Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Provides examples for obtaining an access token using the resource owner password credentials grant type. It includes requests with both public and confidential clients, demonstrating how to use username and password for authentication. This flow is typically used when the client application has a high degree of trust with the resource owner. ```bash # Request access token with user credentials curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=password" \ -d "username=user" \ -d "password=test" \ -d "client_id=public-client" \ -d "scope=read write" # Response: # { # "access_token": "f9e8d7c6-b5a4-3210-9876-543210fedcba", # "token_type": "bearer", # "refresh_token": "1a2b3c4d-5e6f-7890-abcd-ef0987654321", # "expires_in": 43200, # "scope": "read write" # } # With confidential client curl -X POST http://localhost:8080/oauth/token \ -u "confidential-client:secret-pass-phrase" \ -d "grant_type=password" \ -d "username=user" \ -d "password=test" \ -d "scope=read" ``` -------------------------------- ### Bootstrap Client Registration Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This section describes how to register OAuth2 clients during application startup using the `BootStrap.groovy` file. It shows examples of creating public clients, confidential clients with secrets, and clients with custom token expiration settings. ```APIDOC ## Bootstrap Client Registration Register OAuth2 clients during application startup. This is typically done within the `grails-app/init/BootStrap.groovy` file. ### Description Allows for programmatic registration of OAuth2 clients, including public and confidential clients, with configurable settings like client ID, secret, authorized grant types, scopes, and redirect URIs. Custom token expiration times can also be defined. ### Method N/A (Initialization Script) ### Endpoint N/A (Application Startup) ### Parameters N/A (Programmatic configuration within `BootStrap.groovy`) ### Request Example ```groovy // grails-app/init/BootStrap.groovy import test.oauth2.Client import test.oauth2.User import test.oauth2.Role class BootStrap { def init = { servletContext -> // Create users (if needed for password grant) Role roleUser = new Role(authority: 'ROLE_USER').save(flush: true) User user = new User( username: 'user', password: 'test', enabled: true, accountExpired: false, accountLocked: false, passwordExpired: false ).save(flush: true) // Register public client (no client secret) new Client( clientId: 'public-client', authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'], authorities: ['ROLE_CLIENT'], scopes: ['read', 'write', 'delete'], redirectUris: ['http://localhost:8080/redirect'] ).save(flush: true) // Register confidential client (with client secret) new Client( clientId: 'confidential-client', clientSecret: 'secret-pass-phrase', authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'], authorities: ['ROLE_TRUSTED_CLIENT'], scopes: ['read', 'write', 'delete', 'trust'], redirectUris: ['http://localhost:8080/redirect'] ).save(flush: true) // Client with custom token expiration new Client( clientId: 'token-expiration', authorizedGrantTypes: ['password', 'refresh_token'], accessTokenValiditySeconds: 3600, // 1 hour refreshTokenValiditySeconds: 7200, // 2 hours scopes: ['read'] ).save(flush: true) } } ``` ### Response N/A (Configuration during startup) ### Response Example N/A ``` -------------------------------- ### Refresh Token Grant Example Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Illustrates how to use a refresh token to obtain a new access token when the original access token has expired. This example shows a `curl` command to exchange a refresh token for a new access token, including the client ID. This is a crucial part of maintaining continuous access without requiring the user to re-authenticate frequently. ```bash # Use refresh token to obtain new access token curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=refresh_token" \ -d "refresh_token=xyz789-uvw456-123" \ -d "client_id=public-client" # Response: # { # "access_token": "new-access-token-789", # "token_type": "bearer", # "refresh_token": "new-refresh-token-456", # "expires_in": 43200, # "scope": "read write" # } ``` -------------------------------- ### Client Credentials Grant Flow Examples Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Demonstrates how to obtain an access token using the client credentials grant type. It shows requests for both public clients (without a secret) and confidential clients (with a secret), including an alternative using HTTP Basic Authentication. This flow is suitable for machine-to-machine communication. ```bash # Public client (no secret required) curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=client_credentials" \ -d "client_id=public-client" \ -d "scope=read write" # Response: # { # "access_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", # "token_type": "bearer", # "expires_in": 43199, # "scope": "read write" # } # Confidential client (requires secret) curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=client_credentials" \ -d "client_id=confidential-client" \ -d "client_secret=secret-pass-phrase" \ -d "scope=read write trust" # Alternative: HTTP Basic Authentication curl -X POST http://localhost:8080/oauth/token \ -u "confidential-client:secret-pass-phrase" \ -d "grant_type=client_credentials" \ -d "scope=read write" ``` -------------------------------- ### Authorization Code Grant Flow Examples Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Details the steps involved in the authorization code grant flow, a common method for obtaining access tokens. It outlines the process of redirecting the user to the authorization endpoint, user login and approval, receiving an authorization code via redirect, and finally exchanging the code for an access token. This flow is suitable for web applications where users can log in directly. ```bash # Step 1: Direct user to authorization endpoint # User navigates to: http://localhost:8080/oauth/authorize?response_type=code&client_id=public-client&redirect_uri=http://localhost:8080/redirect&scope=read+write # Step 2: User logs in and approves access # Application redirects to user approval page at /oauth/confirm_access # Step 3: User approves, receives authorization code via redirect # http://localhost:8080/redirect?code=a1b2c3 # Step 4: Exchange authorization code for access token curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=authorization_code" \ -d "code=a1b2c3" \ -d "client_id=public-client" \ -d "redirect_uri=http://localhost:8080/redirect" # Response: # { # "access_token": "abc123-def456-789", # "token_type": "bearer", # "refresh_token": "xyz789-uvw456-123", # "expires_in": 43200, # "scope": "read write" # } ``` -------------------------------- ### POST /oauth/token - Confidential Client with HTTP Basic Auth Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Obtains an OAuth2 token using HTTP Basic Authentication with a confidential client ID and secret. This example demonstrates a refresh token grant type. ```APIDOC ## POST /oauth/token - Confidential Client with HTTP Basic Auth ### Description Obtains an OAuth2 token using HTTP Basic Authentication with a confidential client ID and secret. This example demonstrates a refresh token grant type. ### Method POST ### Endpoint http://localhost:8080/oauth/token ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **grant_type** (string) - Required - The grant type for the token request (e.g., `refresh_token`). - **refresh_token** (string) - Required - The refresh token to be used for obtaining a new access token. ### Request Example ```bash curl -X POST http://localhost:8080/oauth/token \ -u "confidential-client:secret-pass-phrase" \ -d "grant_type=refresh_token" \ -d "refresh_token=xyz789-uvw456-123" ``` ### Response #### Success Response (200) - **access_token** (string) - The obtained access token. - **token_type** (string) - The type of token (e.g., `bearer`). - **expires_in** (integer) - The expiration time of the access token in seconds. - **refresh_token** (string) - The refresh token (if applicable). - **scope** (string) - The scope granted to the token. #### Response Example ```json { "access_token": "generated_access_token", "token_type": "bearer", "expires_in": 3600, "refresh_token": "new_refresh_token", "scope": "read write" } ``` ``` -------------------------------- ### Initialize Spring Security Core and OAuth2 Provider Domain Classes (Bash) Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt These bash commands set up the necessary domain classes for both the Spring Security Core plugin and the Spring Security OAuth2 Provider plugin. The s2-quickstart command creates user and role domains, while s2-init-oauth2-provider and s2-init-oauth2-approval create domains for OAuth2 entities and user approvals. ```bash # Create Spring Security Core domain classes grails s2-quickstart test.oauth2 User Role # Create OAuth2 Provider domain classes grails s2-init-oauth2-provider test.oauth2 Client AuthorizationCode AccessToken RefreshToken # Create user approval domain class grails s2-init-oauth2-approval test.oauth2 UserApproval ``` -------------------------------- ### Accessing Protected Resources Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Illustrates how to access OAuth2-protected resources using an access token provided in the `Authorization` header as a Bearer token. ```APIDOC ## Accessing Protected Resources ### Description Illustrates how to access OAuth2-protected resources using an access token provided in the `Authorization` header as a Bearer token. ### Method GET ### Endpoint http://localhost:8080/securedOAuth2Resources/data ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```bash curl -X GET http://localhost:8080/securedOAuth2Resources/data \ -H "Authorization: Bearer abc123-def456-789" ``` ### Response #### Success Response (200) - **message** (string) - A success message indicating access granted. - **data** (any) - The protected resource data. #### Response Example (Success) ```json { "message": "Access granted", "data": "Protected resource data" } ``` #### Error Responses - **401 Unauthorized** - **error** (string) - Indicates an authentication error (e.g., `invalid_token`). - **error_description** (string) - Provides details about the error (e.g., `Access token expired`). ```json { "error": "invalid_token", "error_description": "Access token expired" } ``` - **403 Forbidden** - **error** (string) - Indicates an authorization error (e.g., `insufficient_scope`). - **error_description** (string) - Provides details about the error (e.g., `Insufficient scope for this resource`). ```json { "error": "insufficient_scope", "error_description": "Insufficient scope for this resource" } ``` ``` -------------------------------- ### Protecting Resources with Annotations Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Shows how to secure Grails controllers and actions using Spring Security annotations to enforce OAuth2 scopes and client roles. ```APIDOC ## Protecting Resources with Annotations ### Description Shows how to secure Grails controllers and actions using Spring Security annotations to enforce OAuth2 scopes and client roles. ### Method Various (Depends on controller actions) ### Endpoint Secured controller actions (e.g., `/securedResource/list`, `/securedResource/delete`, `/securedResource/adminOperation`) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example (Controller code demonstrating annotation usage) ```groovy // grails-app/controllers/myapp/SecuredResourceController.groovy package myapp import grails.plugin.springsecurity.annotation.Secured class SecuredResourceController { // Require OAuth2 authentication with specific scope @Secured("#oauth2.hasScope('read')") def list() { render([status: 'success', data: ['item1', 'item2']] as JSON) } // Require multiple scopes @Secured("#oauth2.hasScope('write') and #oauth2.hasScope('delete')") def delete() { render([status: 'deleted'] as JSON) } // Require client credentials only @Secured("#oauth2.clientHasRole('ROLE_TRUSTED_CLIENT')") def adminOperation() { render([status: 'admin operation completed'] as JSON) } } ``` ### Response Responses depend on the controller action and the outcome of the security checks (access granted, denied due to scope, or unauthorized). ``` -------------------------------- ### Implicit Grant Flow Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Demonstrates the Implicit Grant Flow for obtaining an access token directly without an authorization code. Suitable for public clients. ```APIDOC ## Implicit Grant Flow ### Description Demonstrates the Implicit Grant Flow for obtaining an access token directly without an authorization code. Suitable for public clients. ### Method GET (Redirection to authorize endpoint) ### Endpoint http://localhost:8080/oauth/authorize ### Parameters #### Path Parameters None #### Query Parameters - **response_type** (string) - Required - Must be set to `token` for implicit grant. - **client_id** (string) - Required - The client ID of the application. - **redirect_uri** (string) - Required - The URI to redirect to after user authorization. - **scope** (string) - Optional - The requested scope(s) for the access token. ### Request Example 1. **Direct user to authorization endpoint:** ``` http://localhost:8080/oauth/authorize?response_type=token&client_id=public-client&redirect_uri=http://localhost:8080/redirect&scope=read ``` ### Response #### Success Response (Redirection) Upon successful user login and approval, the user is redirected to the `redirect_uri` with the access token in the URL fragment. #### Response Example (URL Fragment) ``` # http://localhost:8080/redirect#access_token=abc123def456&token_type=bearer&expires_in=43200&scope=read ``` ``` -------------------------------- ### Bootstrap OAuth2 Client Registration Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Registers OAuth2 clients during application startup using a Groovy script. It defines clients with varying configurations, including public and confidential clients, and custom token expiration times. This is essential for setting up the OAuth2 provider. ```groovy // grails-app/init/BootStrap.groovy import test.oauth2.Client import test.oauth2.User import test.oauth2.Role class BootStrap { def init = { servletContext -> // Create users Role roleUser = new Role(authority: 'ROLE_USER').save(flush: true) User user = new User( username: 'user', password: 'test', enabled: true, accountExpired: false, accountLocked: false, passwordExpired: false ).save(flush: true) // Register public client (no client secret) new Client( clientId: 'public-client', authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'], authorities: ['ROLE_CLIENT'], scopes: ['read', 'write', 'delete'], redirectUris: ['http://localhost:8080/redirect'] ).save(flush: true) // Register confidential client (with client secret) new Client( clientId: 'confidential-client', clientSecret: 'secret-pass-phrase', authorizedGrantTypes: ['authorization_code', 'refresh_token', 'implicit', 'password', 'client_credentials'], authorities: ['ROLE_TRUSTED_CLIENT'], scopes: ['read', 'write', 'delete', 'trust'], redirectUris: ['http://localhost:8080/redirect'] ).save(flush: true) // Client with custom token expiration new Client( clientId: 'token-expiration', authorizedGrantTypes: ['password', 'refresh_token'], accessTokenValiditySeconds: 3600, // 1 hour refreshTokenValiditySeconds: 7200, // 2 hours scopes: ['read'] ).save(flush: true) } } ``` -------------------------------- ### Manage OAuth2 Client Details with GormClientDetailsService (Groovy) Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This snippet demonstrates how to use `GormClientDetailsService` to programmatically retrieve, register, and update OAuth2 client details. It assumes a `Client` domain class and relies on Grails' GORM for persistence. The service allows loading client information by ID, registering new clients with specified grants and scopes, and updating client scopes. ```groovy // grails-app/services/myapp/ClientManagementService.groovy package myapp import grails.plugin.springsecurity.oauthprovider.GormClientDetailsService import org.springframework.security.oauth2.provider.ClientDetails import test.oauth2.Client class ClientManagementService { GormClientDetailsService gormClientDetailsService ClientDetails getClientDetails(String clientId) { // Load client details from database return gormClientDetailsService.loadClientByClientId(clientId) } void registerNewClient(String clientId, String secret, List grantTypes, List scopes) { new Client( clientId: clientId, clientSecret: secret, authorizedGrantTypes: grantTypes, scopes: scopes, authorities: ['ROLE_CLIENT'] ).save(flush: true) } void updateClientScopes(String clientId, List newScopes) { Client client = Client.findByClientId(clientId) if (client) { client.scopes = newScopes client.save(flush: true) } } } ``` -------------------------------- ### Obtain Token with Confidential Client (HTTP Basic Auth) Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Demonstrates how to obtain an OAuth2 access token using an HTTP POST request with Basic Authentication. This is typically used for confidential clients to refresh an existing access token. It requires the client ID and secret for authentication and the grant type along with the refresh token. ```bash curl -X POST http://localhost:8080/oauth/token \ -u "confidential-client:secret-pass-phrase" \ -d "grant_type=refresh_token" \ -d "refresh_token=xyz789-uvw456-123" ``` -------------------------------- ### Implicit Grant Flow for Access Token Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Illustrates the implicit grant flow for obtaining an OAuth2 access token directly. This flow is suitable for public clients and involves redirecting the user to an authorization endpoint, followed by the token being returned in the URL fragment upon successful user approval. The redirect URI must be pre-registered. ```bash # Step 1: Direct user to authorization endpoint with implicit grant # User navigates to: http://localhost:8080/oauth/authorize?response_type=token&client_id=public-client&redirect_uri=http://localhost:8080/redirect&scope=read # Step 2: User logs in and approves access # Application shows approval page # Step 3: Access token returned in URL fragment # http://localhost:8080/redirect#access_token=abc123def456&token_type=bearer&expires_in=43200&scope=read ``` -------------------------------- ### Access Protected Resource with Bearer Token Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Shows how to access an OAuth2-protected resource using an access token. The token is provided in the `Authorization` header as a Bearer token. The response indicates success, or specific error codes for invalid tokens, expired tokens, or insufficient scopes. ```bash # Access protected resource with Bearer token in Authorization header curl -X GET http://localhost:8080/securedOAuth2Resources/data \ -H "Authorization: Bearer abc123-def456-789" # Response with valid token: # { # "message": "Access granted", # "data": "Protected resource data" # } # Response with invalid/expired token (401 Unauthorized): # { # "error": "invalid_token", # "error_description": "Access token expired" # } # Response with insufficient scope (403 Forbidden): # { # "error": "insufficient_scope", # "error_description": "Insufficient scope for this resource" # } ``` -------------------------------- ### Add Spring Security OAuth2 Provider Plugin to Grails Project Source: https://github.com/grails-plugins/grails-spring-security-oauth2-provider/blob/master/README.md This snippet shows how to configure your Grails project to include the Spring Security OAuth2 Provider plugin. It specifies the repository to fetch the plugin from and the dependency to add. Ensure you replace '' with the desired plugin version. ```groovy repositories { ... maven { url "http://dl.bintray.com/bluesliverx/grails-plugins" } } dependencies { ... compile 'org.grails.plugins:spring-security-oauth2-provider:' } ``` -------------------------------- ### Custom Token Enhancer Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Details on how to implement a custom `TokenEnhancer` to add custom claims to OAuth2 access tokens. ```APIDOC ## Custom Token Enhancer ### Description Details on how to implement a custom `TokenEnhancer` to add custom claims to OAuth2 access tokens. ### Method N/A (Configuration and implementation) ### Endpoint N/A (Applies to token generation) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example 1. **Configure beans in `resources.groovy`:** ```groovy // grails-app/conf/spring/resources.groovy import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken import org.springframework.security.oauth2.provider.OAuth2Authentication beans = { customTokenEnhancer(CustomTokenEnhancer) } ``` 2. **Implement `TokenEnhancer` interface:** ```groovy // src/main/groovy/myapp/CustomTokenEnhancer.groovy package myapp import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.common.OAuth2AccessToken import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken import org.springframework.security.oauth2.provider.OAuth2Authentication class CustomTokenEnhancer implements TokenEnhancer { @Override OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { def additionalInfo = [:] // Add custom user information if (!authentication.isClientOnly()) { additionalInfo.put('user_id', authentication.principal.id) additionalInfo.put('user_email', authentication.principal.email) } // Add custom client information additionalInfo.put('client_type', authentication.OAuth2Request.clientId.startsWith('public') ? 'public' : 'confidential') additionalInfo.put('issued_at', System.currentTimeMillis()) ((DefaultOAuth2AccessToken) accessToken).additionalInformation = additionalInfo return accessToken } } ``` ### Response Access tokens generated by the OAuth2 provider will now include the custom claims defined in the `CustomTokenEnhancer`. ``` -------------------------------- ### Securing Grails Controllers with OAuth2 Scopes Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Demonstrates how to secure Grails controllers and actions using the `@Secured` annotation based on OAuth2 scopes. This Groovy code snippet shows how to require specific scopes like 'read', 'write', 'delete', or client roles like 'ROLE_TRUSTED_CLIENT' for different actions. ```groovy // grails-app/controllers/myapp/SecuredResourceController.groovy package myapp import grails.plugin.springsecurity.annotation.Secured class SecuredResourceController { // Require OAuth2 authentication with specific scope @Secured("#oauth2.hasScope('read')") def list() { render([status: 'success', data: ['item1', 'item2']] as JSON) } // Require multiple scopes @Secured("#oauth2.hasScope('write') and #oauth2.hasScope('delete')") def delete() { render([status: 'deleted'] as JSON) } // Require client credentials only @Secured("#oauth2.clientHasRole('ROLE_TRUSTED_CLIENT')") def adminOperation() { render([status: 'admin operation completed'] as JSON) } } ``` -------------------------------- ### Manage OAuth2 Tokens with GormTokenStoreService (Groovy) Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This snippet shows how to use `GormTokenStoreService` to programmatically manage OAuth2 access and refresh tokens. It allows retrieving tokens by value, revoking individual tokens or all tokens for a given client, and finding tokens associated with a specific client or user. This service leverages GORM for token persistence. ```groovy // grails-app/services/myapp/TokenManagementService.groovy package myapp import grails.plugin.springsecurity.oauthprovider.GormTokenStoreService import org.springframework.security.oauth2.common.OAuth2AccessToken import org.springframework.security.oauth2.provider.OAuth2Authentication class TokenManagementService { GormTokenStoreService gormTokenStoreService OAuth2AccessToken getAccessToken(String tokenValue) { return gormTokenStoreService.readAccessToken(tokenValue) } void revokeAccessToken(String tokenValue) { gormTokenStoreService.removeAccessToken(tokenValue) } void revokeRefreshToken(String refreshTokenValue) { gormTokenStoreService.removeRefreshToken(refreshTokenValue) } Collection getClientTokens(String clientId) { return gormTokenStoreService.findTokensByClientId(clientId) } Collection getUserTokens(String clientId, String username) { return gormTokenStoreService.findTokensByClientIdAndUserName(clientId, username) } void revokeAllClientTokens(String clientId) { Collection tokens = gormTokenStoreService.findTokensByClientId(clientId) tokens.each { token -> gormTokenStoreService.removeAccessToken(token.value) if (token.refreshToken) { gormTokenStoreService.removeRefreshToken(token.refreshToken.value) } } } } ``` -------------------------------- ### Configure Client Domain for OAuth2 Provider (Groovy) Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This Groovy code defines the `Client` domain class for the OAuth2 Provider plugin. It includes properties for client credentials, validity periods, authorities, grant types, scopes, and redirect URIs. The `beforeInsert` method handles client secret encoding. ```groovy package test.oauth2 class Client { String clientId String clientSecret Integer accessTokenValiditySeconds Integer refreshTokenValiditySeconds Map additionalInformation static hasMany = [ authorities: String, authorizedGrantTypes: String, resourceIds: String, scopes: String, autoApproveScopes: String, redirectUris: String ] static constraints = { clientId blank: false, unique: true clientSecret nullable: true accessTokenValiditySeconds nullable: true refreshTokenValiditySeconds nullable: true authorities nullable: true authorizedGrantTypes nullable: true resourceIds nullable: true scopes nullable: true autoApproveScopes nullable: true redirectUris nullable: true additionalInformation nullable: true } def beforeInsert() { clientSecret = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(clientSecret) : clientSecret } } ``` -------------------------------- ### POST /oauth/token - Resource Owner Password Credentials Grant Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This endpoint allows clients to obtain an access token by directly submitting the user's username and password. Use with caution due to security implications. ```APIDOC ## POST /oauth/token - Resource Owner Password Credentials Grant Obtain an access token using the resource owner's username and password. This flow should only be used for trusted clients and when other flows are not feasible. ### Description Clients can request an access token by providing the user's credentials (`username` and `password`) along with the `grant_type` set to `password`. The `client_id` is also required, and for confidential clients, authentication via HTTP Basic or request parameters is needed. ### Method `POST` ### Endpoint `/oauth/token` ### Parameters #### Query Parameters - **grant_type** (string) - Required - Must be `password`. - **username** (string) - Required - The resource owner's username. - **password** (string) - Required - The resource owner's password. - **client_id** (string) - Required - The client identifier. - **scope** (string) - Optional - The scope of the access request. #### Request Body This endpoint uses `application/x-www-form-urlencoded` for request data. - **grant_type** (string) - Required - Must be `password`. - **username** (string) - Required - The resource owner's username. - **password** (string) - Required - The resource owner's password. - **client_id** (string) - Required - The client identifier. - **client_secret** (string) - Optional - The client's secret (required for confidential clients, can also be sent via HTTP Basic Auth). - **scope** (string) - Optional - The scope of the access request. ### Request Example **With public client:** ```bash curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=password" \ -d "username=user" \ -d "password=test" \ -d "client_id=public-client" \ -d "scope=read write" ``` **With confidential client (using HTTP Basic Auth):** ```bash curl -X POST http://localhost:8080/oauth/token \ -u "confidential-client:secret-pass-phrase" \ -d "grant_type=password" \ -d "username=user" \ -d "password=test" \ -d "scope=read" ``` ### Response #### Success Response (200) - **access_token** (string) - The obtained access token. - **token_type** (string) - The type of token, usually `bearer`. - **refresh_token** (string) - A token that can be used to obtain a new access token. - **expires_in** (integer) - The lifetime in seconds of the access token. - **scope** (string) - The scope of the access token. #### Response Example ```json { "access_token": "f9e8d7c6-b5a4-3210-9876-543210fedcba", "token_type": "bearer", "refresh_token": "1a2b3c4d-5e6f-7890-abcd-ef0987654321", "expires_in": 43200, "scope": "read write" } ``` ``` -------------------------------- ### Configure OAuth2 Provider Settings and Security Rules in application.groovy Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This snippet shows how to configure Spring Security Core and OAuth2 provider settings within the application.groovy file. It includes user lookup, authority class definitions, access rules for OAuth2 endpoints, filter chain configurations, and mappings for OAuth2 domain classes like Client, AuthorizationCode, AccessToken, RefreshToken, and UserApproval. ```groovy // grails-app/conf/application.groovy // Spring Security Core configuration grails.plugin.springsecurity.userLookup.userDomainClassName = 'test.oauth2.User' grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'test.oauth2.UserRole' grails.plugin.springsecurity.authority.className = 'test.oauth2.Role' // OAuth2 endpoint access rules grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/oauth/authorize', access: "isFullyAuthenticated() and (request.getMethod().equals('GET') or request.getMethod().equals('POST'))"], [pattern: '/oauth/token', access: "isFullyAuthenticated() and request.getMethod().equals('POST')"] ] // Security filter chain configuration grails.plugin.springsecurity.filterChain.chainMap = [ [pattern: '/oauth/token', filters: 'JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter'], [pattern: '/securedOAuth2Resources/**', filters: 'JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-oauth2BasicAuthenticationFilter,-exceptionTranslationFilter'], [pattern: '/**', filters: 'JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter,-oauth2BasicAuthenticationFilter,-oauth2ExceptionTranslationFilter'] ] // OAuth2 Provider domain class mappings grails.plugin.springsecurity.oauthProvider.clientLookup.className = 'test.oauth2.Client' grails.plugin.springsecurity.oauthProvider.authorizationCodeLookup.className = 'test.oauth2.AuthorizationCode' grails.plugin.springsecurity.oauthProvider.accessTokenLookup.className = 'test.oauth2.AccessToken' grails.plugin.springsecurity.oauthProvider.refreshTokenLookup.className = 'test.oauth2.RefreshToken' grails.plugin.springsecurity.oauthProvider.approvalLookup.className = 'test.oauth2.UserApproval' ``` -------------------------------- ### Configure AccessToken Domain for OAuth2 Provider (Groovy) Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This Groovy code defines the `AccessToken` domain class for the OAuth2 Provider plugin. It includes fields for authentication details, username, client ID, token value, expiration, and scopes. It also specifies constraints and mapping configurations. ```groovy package test.oauth2 class AccessToken { String authenticationKey byte[] authentication String username String clientId String value String tokenType Date expiration Map additionalInformation static hasOne = [refreshToken: String] static hasMany = [scope: String] static constraints = { username nullable: true clientId nullable: false, blank: false value nullable: false, blank: false, unique: true tokenType nullable: false, blank: false expiration nullable: false scope nullable: false refreshToken nullable: true authenticationKey nullable: false, blank: false, unique: true authentication nullable: false, minSize: 1, maxSize: 1024 * 4 additionalInformation nullable: true } static mapping = { version false scope lazy: false } } ``` -------------------------------- ### POST /oauth/token - Client Credentials Grant Flow Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This endpoint allows clients to request an access token using their client ID and optionally a client secret. It's suitable for machine-to-machine communication where a user is not involved. ```APIDOC ## POST /oauth/token - Client Credentials Grant Flow Request an access token using client credentials. This flow is suitable for server-to-server interactions. ### Description Obtain an access token by providing the client ID and, for confidential clients, the client secret. The `grant_type` must be set to `client_credentials`. Scopes can also be requested. ### Method `POST` ### Endpoint `/oauth/token` ### Parameters #### Query Parameters - **grant_type** (string) - Required - Must be `client_credentials`. - **client_id** (string) - Required - The client identifier. - **client_secret** (string) - Optional - The client's secret (required for confidential clients). - **scope** (string) - Optional - The scope of the access request. #### Request Body This endpoint uses `application/x-www-form-urlencoded` for request data. - **grant_type** (string) - Required - Must be `client_credentials`. - **client_id** (string) - Required - The client identifier. - **client_secret** (string) - Optional - The client's secret (required for confidential clients). - **scope** (string) - Optional - The scope of the access request. ### Request Example **Public client (no secret required):** ```bash curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=client_credentials" \ -d "client_id=public-client" \ -d "scope=read write" ``` **Confidential client (requires secret):** ```bash curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=client_credentials" \ -d "client_id=confidential-client" \ -d "client_secret=secret-pass-phrase" \ -d "scope=read write trust" # Alternative: HTTP Basic Authentication curl -X POST http://localhost:8080/oauth/token \ -u "confidential-client:secret-pass-phrase" \ -d "grant_type=client_credentials" \ -d "scope=read write" ``` ### Response #### Success Response (200) - **access_token** (string) - The obtained access token. - **token_type** (string) - The type of token, usually `bearer`. - **expires_in** (integer) - The lifetime in seconds of the access token. - **scope** (string) - The scope of the access token. #### Response Example ```json { "access_token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "token_type": "bearer", "expires_in": 43199, "scope": "read write" } ``` ``` -------------------------------- ### Authorization Code Grant Flow Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Implements the standard OAuth2 authorization code grant flow, which involves user interaction and is suitable for web applications. ```APIDOC ## Authorization Code Grant Flow Implements the standard OAuth2 authorization code flow. This is a multi-step process suitable for web applications where user interaction is expected. ### Description This flow involves redirecting the user to an authorization server, where they authenticate and grant permission. The authorization server then redirects back to the client with an authorization code, which the client exchanges for an access token. ### Method `GET` (for authorization request), `POST` (for token exchange) ### Endpoint - Authorization Endpoint: `/oauth/authorize` - Token Endpoint: `/oauth/token` ### Parameters #### Step 1: Authorization Request (GET `/oauth/authorize`) - **response_type** (string) - Required - Must be `code`. - **client_id** (string) - Required - The client identifier. - **redirect_uri** (string) - Required - The URI to redirect the user to after authorization. - **scope** (string) - Optional - The scope of the access request. #### Step 4: Token Exchange (POST `/oauth/token`) #### Query Parameters (for POST `/oauth/token`) - **grant_type** (string) - Required - Must be `authorization_code`. - **code** (string) - Required - The authorization code received in Step 3. - **client_id** (string) - Required - The client identifier. - **client_secret** (string) - Optional - The client's secret (required for confidential clients, can also be sent via HTTP Basic Auth). - **redirect_uri** (string) - Required - The same redirect URI used in Step 1. #### Request Body (for POST `/oauth/token`) This endpoint uses `application/x-www-form-urlencoded` for request data. - **grant_type** (string) - Required - Must be `authorization_code`. - **code** (string) - Required - The authorization code received in Step 3. - **client_id** (string) - Required - The client identifier. - **client_secret** (string) - Optional - The client's secret (required for confidential clients). - **redirect_uri** (string) - Required - The same redirect URI used in Step 1. ### Request Example **Step 1: Direct user to authorization endpoint** ```bash # User navigates to: http://localhost:8080/oauth/authorize?response_type=code&client_id=public-client&redirect_uri=http://localhost:8080/redirect&scope=read+write ``` **Step 2: User logs in and approves access** (Application redirects to user approval page at `/oauth/confirm_access`) **Step 3: User approves, receives authorization code via redirect** (e.g., `http://localhost:8080/redirect?code=a1b2c3`) **Step 4: Exchange authorization code for access token** ```bash curl -X POST http://localhost:8080/oauth/token \ -d "grant_type=authorization_code" \ -d "code=a1b2c3" \ -d "client_id=public-client" \ -d "redirect_uri=http://localhost:8080/redirect" ``` ### Response #### Success Response (200) (for Token Exchange) - **access_token** (string) - The obtained access token. - **token_type** (string) - The type of token, usually `bearer`. - **refresh_token** (string) - A token that can be used to obtain a new access token. - **expires_in** (integer) - The lifetime in seconds of the access token. - **scope** (string) - The scope of the access token. #### Response Example (for Token Exchange) ```json { "access_token": "abc123-def456-789", "token_type": "bearer", "refresh_token": "xyz789-uvw456-123", "expires_in": 43200, "scope": "read write" } ``` ``` -------------------------------- ### Custom OAuth2 Token Enhancer for Additional Claims Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt Provides a Groovy implementation for a custom OAuth2 `TokenEnhancer`. This allows adding custom claims to access tokens, such as user IDs, emails, client types, and issue timestamps. It involves defining a bean in `resources.groovy` and implementing the `enhance` method in a separate class. ```groovy // grails-app/conf/spring/resources.groovy import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken import org.springframework.security.oauth2.provider.OAuth2Authentication beans = { customTokenEnhancer(CustomTokenEnhancer) } // src/main/groovy/myapp/CustomTokenEnhancer.groovy package myapp import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.common.OAuth2AccessToken import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken import org.springframework.security.oauth2.provider.OAuth2Authentication class CustomTokenEnhancer implements TokenEnhancer { @Override OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { def additionalInfo = [:] // Add custom user information if (!authentication.isClientOnly()) { additionalInfo.put('user_id', authentication.principal.id) additionalInfo.put('user_email', authentication.principal.email) } // Add custom client information additionalInfo.put('client_type', authentication.OAuth2Request.clientId.startsWith('public') ? 'public' : 'confidential') additionalInfo.put('issued_at', System.currentTimeMillis()) ((DefaultOAuth2AccessToken) accessToken).additionalInformation = additionalInfo return accessToken } } ``` -------------------------------- ### Customize Default OAuth2 Token Validity and Grant Types Source: https://context7.com/grails-plugins/grails-spring-security-oauth2-provider/llms.txt This snippet demonstrates default OAuth2 configurations, likely within a separate security configuration file. It allows customization of token validity periods (access and refresh tokens), reuse of refresh tokens, and enables/disables various grant types such as authorization code, implicit, refresh token, client credentials, and password. It also includes settings for authorization requirements and approval handling. ```groovy // DefaultOAuth2ProviderSecurityConfig.groovy structure security { oauthProvider { active = true tokenServices { registerTokenEnhancers = true accessTokenValiditySeconds = 60 * 60 * 12 // 12 hours refreshTokenValiditySeconds = 60 * 60 * 24 * 30 // 30 days reuseRefreshToken = false supportRefreshToken = true } // OAuth2 endpoint URLs authorizationEndpointUrl = "/oauth/authorize" tokenEndpointUrl = "/oauth/token" userApprovalEndpointUrl = "/oauth/confirm_access" errorEndpointUrl = "/oauth/error" // Enable or disable grant types grantTypes { authorizationCode = true implicit = true refreshToken = true clientCredentials = true password = true } authorization { requireRegisteredRedirectUri = true requireScope = true } approval { handleRevocationAsExpiry = false auto = UserApprovalSupport.EXPLICIT approvalValiditySeconds = 60 * 60 * 24 * 30 // 30 days } } } ```