0
# Client Credentials Grant
1
2
The Client Credentials Grant is used for service-to-service authentication where no user interaction is required. This flow is typically used for server-to-server communications, background jobs, or microservices.
3
4
## Overview
5
6
This grant type implements the OAuth 2.0 Client Credentials flow, which directly exchanges client credentials for an access token without user involvement. The client authenticates using its own credentials rather than acting on behalf of a user.
7
8
## Core Import
9
10
```javascript
11
const { ClientCredentials } = require('simple-oauth2');
12
```
13
14
## Client Credentials Class
15
16
### Constructor
17
18
```typescript { .api }
19
constructor(options: OAuth2Config): ClientCredentials
20
```
21
22
Creates a new ClientCredentials instance with OAuth 2.0 configuration validation.
23
24
**Parameters:**
25
- `options` - OAuth 2.0 configuration object (see main documentation)
26
27
**Example:**
28
```javascript
29
const client = new ClientCredentials({
30
client: {
31
id: 'your-client-id',
32
secret: 'your-client-secret'
33
},
34
auth: {
35
tokenHost: 'https://oauth-provider.com',
36
tokenPath: '/oauth/token'
37
}
38
});
39
```
40
41
### Get Access Token
42
43
```typescript { .api }
44
getToken(params?: ClientCredentialsParams, httpOptions?: any): Promise<AccessToken>
45
```
46
47
Requests an access token using client credentials.
48
49
**Parameters:**
50
- `params.scope` (string | string[], optional) - Application scopes to request
51
- Additional parameters are automatically serialized for the token request
52
- `httpOptions` (object, optional) - HTTP options passed to underlying request library
53
54
**Returns:** Promise resolving to AccessToken instance
55
56
**Example:**
57
```javascript
58
// Basic token request
59
const accessToken = await client.getToken();
60
61
// Token request with specific scopes
62
const accessToken = await client.getToken({
63
scope: ['read:users', 'write:data']
64
});
65
66
// Token request with custom HTTP options
67
const accessToken = await client.getToken({
68
scope: 'api:access'
69
}, {
70
timeout: 10000,
71
headers: {
72
'User-Agent': 'MyApp/1.0'
73
}
74
});
75
76
console.log('Access token:', accessToken.token.access_token);
77
console.log('Expires at:', accessToken.token.expires_at);
78
```
79
80
### Create Token from Object
81
82
```typescript { .api }
83
createToken(token: any): AccessToken
84
```
85
86
Creates an AccessToken instance from a plain token object (e.g., from storage).
87
88
**Parameters:**
89
- `token` - Plain object representing an access token conforming to RFC 6750
90
91
**Returns:** AccessToken instance with full token management capabilities
92
93
**Example:**
94
```javascript
95
// Restore token from database
96
const storedToken = await database.getToken('client-credentials-token');
97
const accessToken = client.createToken(storedToken);
98
99
// Check if token is still valid
100
if (!accessToken.expired()) {
101
// Use existing token
102
console.log('Using cached token');
103
} else {
104
// Get new token
105
const newToken = await client.getToken();
106
await database.saveToken('client-credentials-token', newToken.token);
107
}
108
```
109
110
## Type Definitions
111
112
```typescript { .api }
113
interface ClientCredentialsParams {
114
scope?: string | string[];
115
[key: string]: any;
116
}
117
```
118
119
## Common Usage Patterns
120
121
### Basic Service Authentication
122
123
```javascript
124
const { ClientCredentials } = require('simple-oauth2');
125
126
const client = new ClientCredentials({
127
client: {
128
id: process.env.CLIENT_ID,
129
secret: process.env.CLIENT_SECRET
130
},
131
auth: {
132
tokenHost: 'https://api.example.com',
133
tokenPath: '/oauth/token'
134
}
135
});
136
137
// Get token for API access
138
const accessToken = await client.getToken({
139
scope: 'api:read api:write'
140
});
141
142
// Use token for API requests
143
const response = await fetch('https://api.example.com/data', {
144
headers: {
145
'Authorization': `Bearer ${accessToken.token.access_token}`,
146
'Content-Type': 'application/json'
147
}
148
});
149
```
150
151
### Token Caching with Automatic Refresh
152
153
```javascript
154
class APIClient {
155
constructor(clientConfig) {
156
this.oauth = new ClientCredentials(clientConfig);
157
this.cachedToken = null;
158
}
159
160
async getValidToken() {
161
// Check if we have a cached token that's not expired
162
if (this.cachedToken && !this.cachedToken.expired(300)) { // 5 min buffer
163
return this.cachedToken;
164
}
165
166
// Get new token
167
this.cachedToken = await this.oauth.getToken({
168
scope: 'api:access'
169
});
170
171
return this.cachedToken;
172
}
173
174
async makeAPIRequest(endpoint, options = {}) {
175
const token = await this.getValidToken();
176
177
return fetch(endpoint, {
178
...options,
179
headers: {
180
...options.headers,
181
'Authorization': `Bearer ${token.token.access_token}`
182
}
183
});
184
}
185
}
186
187
// Usage
188
const apiClient = new APIClient({
189
client: {
190
id: process.env.CLIENT_ID,
191
secret: process.env.CLIENT_SECRET
192
},
193
auth: {
194
tokenHost: 'https://api.example.com'
195
}
196
});
197
198
const userData = await apiClient.makeAPIRequest('https://api.example.com/users');
199
```
200
201
### Microservice Authentication
202
203
```javascript
204
// Microservice A authenticating to Microservice B
205
const serviceAuth = new ClientCredentials({
206
client: {
207
id: 'microservice-a-id',
208
secret: process.env.SERVICE_SECRET
209
},
210
auth: {
211
tokenHost: 'https://auth.company.com',
212
tokenPath: '/oauth/token'
213
},
214
options: {
215
bodyFormat: 'json', // Some services prefer JSON
216
authorizationMethod: 'body' // Some services require credentials in body
217
}
218
});
219
220
async function callMicroserviceB(data) {
221
const token = await serviceAuth.getToken({
222
scope: 'microservice-b:access'
223
});
224
225
return fetch('https://service-b.company.com/api/process', {
226
method: 'POST',
227
headers: {
228
'Authorization': `Bearer ${token.token.access_token}`,
229
'Content-Type': 'application/json'
230
},
231
body: JSON.stringify(data)
232
});
233
}
234
```