Skip to content

Commit a2ce2f8

Browse files
authored
Create local-setup-oauth.md
documentation for oauth in management-api
1 parent edba11d commit a2ce2f8

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
description: Setup OAuth authorization for Umbraco Management API in local and production environments.
3+
---
4+
5+
# Overview
6+
7+
{% hint style="info" %}
8+
9+
This guide is created by a community member and is not managed by Umbraco HQ. Some attributes or features may evolve as the Management API continues to develop.
10+
11+
{% endhint %}
12+
13+
This guide covers how to set up OAuth authorization for the Umbraco Management API for both local development and production environments. Authorization configuration can differ greatly between environments, and understanding these differences is key.
14+
15+
Before proceeding, it is recommended to read the [Management API overview](./README.md). It provides fundamental information about the authorization process and its significance.
16+
17+
This guide will walk through:
18+
19+
1. [Environment Differences and Challenges](#environment-differences-and-challenges)
20+
2. [Configuring appsettings.json](#configuring-appsettingsjson)
21+
3. [Setting up Production-Local Authorization](#setting-up-production-local-authorization)
22+
4. [Creating a Custom Client ID](#creating-a-custom-client-id)
23+
5. [Minimal API Implementation](#minimal-api-implementation)
24+
6. [Configuring Authorization in Production](#configuring-authorization-in-production)
25+
7. [Common Pitfalls and Troubleshooting](#common-pitfalls-and-troubleshooting)
26+
27+
# Environment Differences and Challenges
28+
29+
The Umbraco Management API authorization works seamlessly in non-production environments using tools like Swagger or Postman. However, in production, some key differences and limitations exist:
30+
31+
- **Swagger and Postman Integration**: Only allowed in non-production, making testing easy.
32+
- **Client Restrictions**: In production, only the `umbraco-back-office` client is allowed.
33+
- **OAuth2 Flows:** Requires careful handling to ensure secure setup without Swagger available.
34+
35+
To avoid conflicts and guarantee smooth integration in production, it's crucial to create a custom client and tailor the authorization flow accordingly.
36+
37+
# Configuring appsettings.json
38+
39+
To override the default callback URL for OAuth authorization, update the `appsettings.json` file as follows: (this uses client: umbraco-back-office)
40+
41+
```json
42+
"Umbraco": {
43+
"CMS": {
44+
"Security": {
45+
"AuthorizeCallbackPathName": "/callback"
46+
}
47+
}
48+
}
49+
```
50+
51+
This configuration allows you to specify a custom callback path for OAuth, but note that this will interfere with the default back-office callback path, making back-office not accessible.
52+
53+
# Setting up Production-Local Authorization
54+
55+
In a production environment, Swagger UI is disabled, and only the `umbraco-back-office` client can be used. This requires a more advanced approach.
56+
57+
# Creating a Custom Client ID
58+
59+
To avoid conflicts with the back-office, a new client should be created. Below are the steps to set up a custom client using a Minimal API:
60+
61+
## Extending `OpenIdDictApplicationManagerBase`
62+
63+
Create a new client for production use by extending the `OpenIdDictApplicationManagerBase`.
64+
65+
```csharp
66+
public class CustomApplicationManager : OpenIdDictApplicationManagerBase
67+
{
68+
public CustomApplicationManager(IOpenIddictApplicationManager applicationManager)
69+
: base(applicationManager)
70+
{
71+
}
72+
73+
public async Task EnsureCustomApplicationAsync(string clientId, Uri redirectUri, CancellationToken cancellationToken = default)
74+
{
75+
if (!redirectUri.IsAbsoluteUri)
76+
{
77+
throw new ArgumentException("The provided URL must be an absolute URL.", nameof(redirectUri));
78+
}
79+
80+
var clientDescriptor = new OpenIddictApplicationDescriptor
81+
{
82+
DisplayName = "Custom Application",
83+
ClientId = clientId,
84+
RedirectUris = { redirectUri },
85+
ClientType = OpenIddictConstants.ClientTypes.Public,
86+
Permissions = {
87+
OpenIddictConstants.Permissions.Endpoints.Authorization,
88+
OpenIddictConstants.Permissions.Endpoints.Token,
89+
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
90+
OpenIddictConstants.Permissions.ResponseTypes.Code
91+
}
92+
};
93+
94+
await CreateOrUpdate(clientDescriptor, cancellationToken);
95+
}
96+
}
97+
```
98+
99+
The above code allows you to define a new custom client that does not interfere with the existing `umbraco-back-office` client, ensuring smoother integration and avoiding callback conflicts.
100+
101+
# Minimal API Implementation
102+
103+
To set up a Minimal API that integrates the custom client, follow these steps:
104+
105+
## Creating the Minimal API Application
106+
107+
Below is a complete setup for using Minimal API to create and manage custom OAuth clients for the Umbraco Management API.
108+
109+
```csharp
110+
builder.Services.AddScoped<CustomApplicationManager>(provider =>
111+
{
112+
var applicationManager = provider.GetRequiredService<IOpenIddictApplicationManager>();
113+
return new CustomApplicationManager(applicationManager);
114+
});
115+
116+
app.MapPost("/create-client", async (ClientModel model, CustomApplicationManager applicationManager) =>
117+
{
118+
try
119+
{
120+
if (string.IsNullOrEmpty(model.ClientId))
121+
return Results.BadRequest("Client ID is required.");
122+
123+
if (!Uri.TryCreate(model.RedirectUri, UriKind.Absolute, out var redirectUri))
124+
return Results.BadRequest("Invalid redirect URI.");
125+
126+
await applicationManager.EnsureCustomApplicationAsync(model.ClientId, redirectUri);
127+
return Results.Ok("Client created/updated successfully.");
128+
}
129+
catch (Exception ex)
130+
{
131+
return Results.Problem(ex.Message);
132+
}
133+
}).WithName("CreateClient");
134+
135+
app.MapGet("/login", (Auth auth, IConfiguration config, IBackOfficeApplicationManager backOfficeApplicationManager) =>
136+
{
137+
var baseUrl = config["Umbraco:BaseUrl"];
138+
var authorizationUrl = auth.GetAuthorizationUrl();
139+
return Results.Redirect(baseUrl + authorizationUrl);
140+
});
141+
142+
app.MapGet("/callback", async (Auth auth, HttpContext httpContext, IConfiguration configuration) =>
143+
{
144+
var code = httpContext.Request.Query["code"];
145+
var state = httpContext.Request.Query["state"];
146+
if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(state))
147+
{
148+
return Results.BadRequest("Invalid callback parameters");
149+
}
150+
try
151+
{
152+
var tokenResponse = await auth.HandleCallback(code, state);
153+
//
154+
return Results.Redirect("/dashboard");
155+
}
156+
catch (Exception ex)
157+
{
158+
return Results.BadRequest($"Authentication failed: {ex.Message}");
159+
}
160+
});
161+
162+
public class ClientModel
163+
{
164+
public string ClientId { get; set; }
165+
public string RedirectUri { get; set; }
166+
}
167+
```
168+
169+
This implementation demonstrates how to use Minimal API to manage OAuth clients dynamically, allowing better integration into production workflows.
170+
171+
# Configuring Authorization in Production
172+
173+
To configure authorization using the custom client:
174+
175+
1. Update your `appsettings.json` file:
176+
177+
```json
178+
{
179+
"BaseUrl": "https://your-production-domain",
180+
"ClientId": "newclientId",
181+
"AuthorizationEndpoint": "/umbraco/management/api/v1/security/back-office/authorize",
182+
"TokenEndpoint": "/umbraco/management/api/v1/security/back-office/token",
183+
"RedirectUri": "https://your-production-domain/callback"
184+
}
185+
```
186+
187+
2. Use the custom client manager endpoint (`/create-client`) to create a new client for use in production.
188+
189+
3. Handle token retrieval and secure storage in your application. Store tokens securely to avoid exposure, for instance by using HTTP-only cookies.
190+
191+
# Common Pitfalls and Troubleshooting
192+
193+
## Callback Interference with Back Office
194+
195+
If using the `umbraco-back-office` client causes callback conflicts, ensure that your custom client has a distinct redirect URI and does not overlap with back-office authentication settings.
196+

0 commit comments

Comments
 (0)