Skip to content

Commit 9afc81b

Browse files
committed
pulling from the example remote app
1 parent c0a868b commit 9afc81b

File tree

2 files changed

+38
-162
lines changed

2 files changed

+38
-162
lines changed

astro/src/content/docs/get-started/use-cases/api-consents-platform.mdx

Lines changed: 32 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import InlineUIElement from 'src/components/InlineUIElement.astro';
1010
import UserAuthorizeDiagram from 'src/diagrams/docs/get-started/use-cases/api-consents/user-authorize.astro';
1111
import ApplicationAPIRequestDiagram from 'src/diagrams/docs/get-started/use-cases/api-consents/application-api-request.astro';
1212
import APIConsentsPlatformDescription from 'src/content/docs/get-started/use-cases/_api-consents-platform-description.mdx';
13+
import {RemoteCode} from '@fusionauth/astro-components';
1314

1415
## Overview
1516

@@ -132,45 +133,19 @@ Next, associate every API with one or more scopes. If a request comes in with an
132133

133134
Here are two routes that offer up banking information and check scopes.
134135

135-
TODO pull from remote
136-
```javascript
137-
router.get('/read-balance', hasScope('accounts.read'), function (req, res, next) {
138-
// add real implementation
139-
res.json({ balance: 42 });
140-
});
141-
142-
router.post('/make-transfer', hasScope('transfers.write'), function (req, res, next) {
143-
// add real implementation
144-
const amount = req.query.newbalance;
145-
146-
// update balance
147-
148-
res.json({ message: "ok"});
149-
});
150-
```
136+
<RemoteCode lang="javascript"
137+
url="https://raw.githubusercontent.com/FusionAuth/fusionauth-example-api-consents-platform/refs/heads/main/changebank-apis/routes/index.js"
138+
title="Example Changebank API routes"
139+
tags="routes"
140+
/>
151141

152142
The `hasScope` method looks like this:
153143

154-
TODO pull from remote
155-
```javascript
156-
const jose = require('jose');
157-
158-
function hasScope(scope) {
159-
return (req, res, next) => {
160-
const decodedToken = jose.decodeJwt(req.verifiedToken);
161-
let scopes = []
162-
if (decodedToken.scope) {
163-
// need to check array, not string, to avoid partial matches
164-
scopes = decodedToken.scope.split(" ");
165-
}
166-
if (scopes.includes(scope)) return next();
167-
res.status(403);
168-
res.send({ error: `You do not have permissions to do this.` });
169-
}
170-
}
171-
172-
module.exports = hasScope;
173-
```
144+
<RemoteCode lang="javascript"
145+
url="https://raw.githubusercontent.com/FusionAuth/fusionauth-example-api-consents-platform/refs/heads/main/changebank-apis/services/hasScope.js"
146+
title="The hasScope logic"
147+
tags="hasScope"
148+
/>
174149

175150
You could check claims and signatures at your API gateway rather than in your code, but the process for handling scopes is the same:
176151

@@ -215,135 +190,31 @@ These scopes will be optional, which means the user can choose to allow or disal
215190
* `investments.read`: Investment portfolio information
216191
* `creditScore.read`: Access credit score information
217192

218-
MoneyScope should fully function without the APIs or data corresponding to these scopes.
193+
MoneyScope should fully function without the APIs or data corresponding to these scopes.
219194

220-
Configure the scopes for an application to look like this:
195+
You can use the admin UI to configure scopes for your application.
221196

222197
![Configured scopes for the example scenario.](/img/docs/get-started/use-cases/api-consents-scopes.png)
223198

224-
While the above configuration was manual, you can also do this with [our SDKs](/docs/sdks). Here's sample code to do so:
225-
226-
TODO remote
227-
```javascript
228-
import {FusionAuthClient} from '@fusionauth/typescript-client';
229-
import 'dotenv/config'
230-
231-
const FUSIONAUTH_API_KEY = process.env.FUSIONAUTH_API_KEY;
232-
const BASE_URL = process.env.BASE_URL;
233-
const CLIENT_ID = process.env.CLIENT_ID;
234-
const CLIENT_SECRET = process.env.CLIENT_SECRET;
235-
236-
const client = new FusionAuthClient(FUSIONAUTH_API_KEY, BASE_URL);
237-
238-
async function createApplication() {
239-
try {
240-
const response = await client.createApplication(CLIENT_ID, {
241-
application: {
242-
name: 'MoneyScope',
243-
registrationConfiguration: {
244-
enabled: true,
245-
type: 'basic'
246-
},
247-
oauthConfiguration: {
248-
clientSecret: CLIENT_SECRET,
249-
authorizedRedirectURLs: [
250-
"http://localhost:8080/oauth-redirect"
251-
],
252-
enabledGrants: [
253-
'authorization_code',
254-
'refresh_token'
255-
],
256-
generateRefreshTokens: true,
257-
consentMode: 'AlwaysPrompt',
258-
relationship: 'ThirdParty',
259-
providedScopePolicy: {
260-
profile: {
261-
required: true
262-
},
263-
email: {
264-
required: true
265-
}
266-
}
267-
}
268-
}
269-
});
270-
271-
console.log('Application created:', response.response);
272-
return response.response.application.id;
273-
} catch (error) {
274-
console.error('Error creating application:', error);
275-
}
276-
}
277-
278-
async function createScopes(applicationId) {
279-
280-
const analyticsScopes = [
281-
{
282-
name: "accounts.read",
283-
description: "Basic account information and balances",
284-
required: true,
285-
consent: "Read basic account and balance information",
286-
},
287-
{
288-
name: "profile.read",
289-
description: "User profile and contact information",
290-
required: true,
291-
consent: "Read user profile information",
292-
},
293-
{
294-
name: "transactions.read",
295-
description: "Transaction history and details",
296-
required: true,
297-
consent: "Read transaction history",
298-
},
299-
{
300-
name: "investments.read",
301-
description: "Investment portfolio information",
302-
required: false,
303-
consent: "Read investment profile information",
304-
},
305-
{
306-
name: "creditScore.read",
307-
description: "Access credit score information",
308-
required: false,
309-
consent: "Read credit score information",
310-
}
311-
];
312-
313-
314-
try {
315-
for (const scope of analyticsScopes) {
316-
const req = {
317-
scope: {
318-
name: scope.name,
319-
required: scope.required,
320-
defaultConsentMessage: scope.consent,
321-
defaultConsentDetail: "",
322-
description: scope.description
323-
}
324-
};
325-
const use_created_scope_id = "";
326-
const response = await client.createOAuthScope(applicationId, use_created_scope_id, req);
327-
328-
console.log('Scope created:', response);
329-
}
330-
331-
} catch (error) {
332-
console.error('Error creating scope:', JSON.stringify(error));
333-
}
334-
}
335-
336-
(async () => {
337-
const applicationId = await createApplication();
338-
if (applicationId) {
339-
await createScopes(applicationId);
340-
}
341-
})();
342-
```
199+
You can also do this with [our SDKs](/docs/sdks). Here's sample code to create the application:
200+
201+
<RemoteCode lang="javascript"
202+
url="https://raw.githubusercontent.com/FusionAuth/fusionauth-example-api-consents-platform/refs/heads/main/create-application/create-application.js"
203+
title="Using the TypeScript SDK to create the application"
204+
tags="createApplication"
205+
/>
206+
207+
Here's sample code to add needed scopes:
343208

344-
Either approach works. You could also use the [FusionAuth Terraform provider](/docs/operate/deploy/terraform).
209+
<RemoteCode lang="javascript"
210+
url="https://raw.githubusercontent.com/FusionAuth/fusionauth-example-api-consents-platform/refs/heads/main/create-application/create-application.js"
211+
title="Using the TypeScript SDK to create the application"
212+
tags="createScopes"
213+
/>
345214

346-
While this is not done, if you need to support multiple languages, you can [localize the displayed consent messages](/docs/customize/look-and-feel/localization#oauth-scope-consent-prompt). This allows every user can see the consent screen in their preferred language.
215+
You could also use the [FusionAuth Terraform provider](/docs/operate/deploy/terraform) to manage the application and scopes.
216+
217+
If you need to support multiple languages, you can [localize the displayed consent messages](/docs/customize/look-and-feel/localization#oauth-scope-consent-prompt). This allows every user can see the consent screen in their preferred language.
347218

348219
#### Communicate With The Third-Party Developer
349220

@@ -380,8 +251,6 @@ You can read more about [the other parameters for the authorization code grant](
380251

381252
Should this URL be available to anyone or do users have to log in to MoneyScope before they can authorize the application to access their data held by Changebank? Third-party developers could entirely delegate authentication to the Changebank application. Or they could run their own login system and have Changebank login be an authorization process. Choose this option if there is useful functionality in an application even without the access to the Changebank APIs. In that case, there'd be a button to connect with Changebank within the MoneyScope.
382253

383-
TODO change name of `Analytics application` and remove backticks around it and take new screenshot
384-
385254
After this is done, you should test the MoneyScope application and make sure it works as advertised. Things to test for:
386255

387256
* Scopes are in the URL, and therefore can be edited by a malicious end user. Make sure the third party developer's application handles when scopes are not exactly as they expect.
@@ -399,7 +268,7 @@ Here's a diagram of the user authorization flow:
399268

400269
Here's an example of the consent screen the MoneyScope user will see.
401270

402-
![Configured scopes for the example scenario.](/img/docs/get-started/use-cases/api-consents-consent-screen.png) TODO
271+
![Configured scopes for the example scenario.](/img/docs/get-started/use-cases/api-consents-consent-screen.png)
403272

404273
MoneyScope stores the Changebank access and refresh tokens. Then, when it needs it, it makes requests of the Changebank APIs. Depending on the timeframe, it may need to refresh the access token before it calls the APIs.
405274

@@ -462,4 +331,5 @@ All of these have a platform with valuable data behind APIs and want to allow AP
462331
* [The Authorization endpoint](/docs/lifecycle/authenticate-users/oauth/endpoints#authorize)
463332
* [API gateways integration documentation](/docs/extend/examples/api-gateways/)
464333
* [Custom OAuth scopes blog post](/blog/custom-scopes-in-third-party-applications)
334+
* [Example application GitHub repository](https://github.com/fusionauth/fusionauth-example-api-consents-platform)
465335

astro/src/content/json/exampleapps.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,12 @@
629629
"description": "An express/JavaScript application used for a walkthrough of a FusionAuth setup",
630630
"language": "javascript"
631631
},
632+
{
633+
"url": "https://github.com/fusionauth/fusionauth-example-api-consents-platform",
634+
"name": "API Consents Platform",
635+
"description": "Example repo for a third-party application platform with scopes and consent management.",
636+
"language": "javascript"
637+
},
632638
{
633639
"url": "https://github.com/FusionAuth/fusionauth-example-mock-testing-vs-dev-server",
634640
"name": "Why Mocking Sucks - FusionAuth",

0 commit comments

Comments
 (0)