Where to configure the AllowedRedirectUris when using a federated login

  • We are using the Milestone API to retrieve cameras for specific users. To obtain the correct information for the user, the user first logs in to get an access token.
  • The flow is as follows:
    • We redirect the user to the Milestone IDP with the correct parameters.
    • The Milestone IDP redirects to our own IDP (ForgeRock), where the user logs in.
    • ForgeRock then redirects to Milestone, and Milestone redirects to our custom-built application.
  • If we test this locally and provide a redirect URL to localhost, all works fine. However, in a deployed setting, it should redirect to the application itself. This fails with a generic 404 error. In the logs, we can clearly see that the AllowedRedirectUris are configured on http://127.0.0.1.

So the question is, where do we configure the AllowedRedirectUris in Milestone?

Did you use the sample? - https://doc.developer.milestonesys.com/html/index.html?base=samples/protocolsamples/oauthloginflow/readme.html&tree=tree_3.html

I have asked a developer:

We are not sure that we completely understand your setup and flow and why you need a redirect different from localhost.

The redirect URL should be seen from the location of the browser launching the login flow.

An example is the Smart Client login that launches a browser locally for the login. In this case the redirect URL is localhost.

Have you tried to use localhost as redirect even though you are not running locally?

Hy, Thanks for your feedback.

We started from the sample as proof of concept, working with localhost we got the proof of concept working. (running a backend server locally)

but in the real scenario there is no software running on the users machine, just a browser, and the browser can make requests to the backend server using HTTP methods (GET,POST,PUT,…).

The application is run a java server and servers angular to interact with the user.

When the user wants to access data from milestone (trough our application) we need to authenticate that user against the IDP (Identity provider) from milestone using a Oaut2.0 Authorization Code Flow, the main goal is to get a Access token on our backend server so we can request data for that specific user.

the flow is as describe above.

The login url is created by the backend and executed by the browser of the user, but the users browse is redirected trough the IDP flow (that’s how an authorization code flow works) but at the end the the authorization code needs to be swapped to a access token by the backend.

I’ll try to clarify the end step a bit more.

When the login is complete the IDP should drop the user back off at its “original” location.

If this would be localhost, our web application, served by a server, can not intervene anymore.

so the user needs to be dropped off on a webpage that sends the authorization code to the backend, the backend can then request the IDP for an access token and stores the access token for that user so when the user requests data from milestone the server can do the call using the access token from that specific user.

The only part missing at the moment is when we set the redirect url on the intial request to the milestone IDP on something else than localhost, the milestone IDP returns an error page.

In any Identity Provider i know, when using the authorization code flow you have to whitelist the redirect url (in the AllowedRedirectUris), We just can find the location where to do that in milestone.

hope this clarifies things.

I’ll add the error from a milestone log file.

2024-02-09 10:42:56.929+01:00 [   47] INFO      - Invoking IdentityServer endpoint: Duende.IdentityServer.Endpoints.AuthorizeEndpoint for /connect/authorize 
 
 2024-02-09 10:42:56.958+01:00 [   47] ERROR     - Invalid redirect_uri: "https://apps-accpt.portofantwerpbruges.com/apica/security/login/success"
 
 {"ClientId":"VmsClient", "ClientName":"VmsClient", "AllowedRedirectUris":["http:\/\/127.0.0.1"], "SubjectId":"anonymous", "RequestedScopes":"", "PromptMode":"", "Raw":{"response_type":"code","nonce":"acb04d5ea12747f58001818f245f1f89","state":"n-xMHv-wPoo_E3aFGUJjLeiUYNUi-mhDaTLojFU4WCo","code_challenge":"Ib1ebU1ZPbIwoLoPgFuM4OPV5oeRuoERHz7mIX9HGOI","code_challenge_method":"S256","client_id":"VmsClient","scope":"openid profile managementserver offline_access","redirect_uri":"https:\/\/apps-accpt.portofantwerpbruges.com\/apica\/api\/camera\/security\/login\/success","acr_values":"idp:19ec4460-a9e1-4b79-9561-e0b677107d49","culture":"nl-NL","prompt":"login"}} 
 
 2024-02-09 10:42:56.958+01:00 [   47] ERROR     - Request validation failed 
 
 2024-02-09 10:42:56.958+01:00 [   47] INFO      - {"ClientId":"VmsClient", "ClientName":"VmsClient", "AllowedRedirectUris":["http:\/\/127.0.0.1"], "SubjectId":"anonymous", "RequestedScopes":"", "PromptMode":"", "Raw":{"response_type":"code","nonce":"acb04d5ea12747f58001818f245f1f89","state":"n-xMHv-wPoo_E3aFGUJjLeiUYNUi-mhDaTLojFU4WCo","code_challenge":"Ib1ebU1ZPbIwoLoPgFuM4OPV5oeRuoERHz7mIX9HGOI","code_challenge_method":"S256","client_id":"VmsClient","scope":"openid profile managementserver offline_access","redirect_uri":"https:\/\/apps-accpt.portofantwerpbruges.com\/apica\/api\/camera\/security\/login\/success","acr_values":"idp:19ec4460-a9e1-4b79-9561-e0b677107d49","culture":"nl-NL","prompt":"login"}} 
 
 2024-02-09 10:42:56.958+01:00 [   47] INFO      - {"ClientId":"VmsClient", "ClientName":"VmsClient", "Endpoint":"Authorize", "Scopes":"", "Error":"invalid_request", "ErrorDescription":"Invalid redirect_uri", "Category":"Token", "Name":"Token Issued Failure", "EventType":"Failure", "Id":2001, "ActivityId":"8000b528-0001-e400-b63f-84710c7967bb", "TimeStamp":"2024-02-09T09:42:56Z", "ProcessId":5500, "LocalIpAddress":"172.24.2.110:443", "RemoteIpAddress":"172.25.212.88"}

A developer colleague has made a PowerShell sample that shows how you can customize the IDP client and add the needed allowed Redirect Uri’s.

We do not know which IDP client you are using, but you can either update the existing client or create a new using the sample code.

If you are using an existing client, you need to make sure to specify the clients’ scopes and client grant types according to what is already configured on the client.

You should be able to query the client using the rest API as well (not a part of the sample).

# Step 1: Get the access token
$response = Invoke-WebRequest -Uri "http://localhost/idp/connect/token" -Method Post -Body @{
    grant_type = "windows_auth"
    scope = "write:client"
    client_id = "winauthclient"
} -UseDefaultCredentials
$accessTokenContent = $response.Content
$accessToken = ($accessTokenContent | ConvertFrom-Json).access_token
# Step 2: Use the access token to make the PUT request
$clientId = "your_client_id"
$apiUrl = "http://localhost/idp/api/clients/$clientId"
# Construct the client data
$clientData = @{
    ClientName = "your_client_name"
    ClientScopes = @("management", "openid", "offline_access", "profile")
    ClientGrantTypes = @("authorization_code", "refresh_token")
    ClientRedirectUris = @(http://localhost, https://localhost)
}
# Make the request with Invoke-RestMethod
$response = Invoke-RestMethod -Method Put -Uri $apiUrl -Headers @{
    Authorization = "Bearer $accessToken"
} -Body (ConvertTo-Json $clientData) -ContentType "application/json"
# Output the response
$response | Select-Object -ExpandProperty data | Select-Object -Property name, @{Name="Scopes";Expression={$_.scopes -join ','}}

Thank you for your reply. These commands successfully configured an additional OIDC client which we can use.

But as I fail to find documentation about this setup :

  • These commands configure the “management” scope, while in the default OIDC client, there is the “managementserver” scope. What is the difference ? When should we use which scope ?
  • How can I modify this client when I would need to add or change scopes for instance.
  • How can I see/query the existing OIDC clients and scopes on the server.
  • Is there any place in the Management Server GUI where I can see the this OIDC client and it’s configuration ?

We do not have documentation regarding the different OIDC clients and their related scopes and settings. The same goes for UI applications or for documentation on the API related to the handling the OIDC client. It is something that we are looking into though. You should be able to query the clients using the REST API at the IDP "http://localhost/idp/api/clients.

I can see that the example is adding the “management” scope which is not the one to use when calling the server, it should have been “managementserver”. The “managementserver” scope should give access to the API gateway and the management server.

OK, then the next logical question is : How do I add this “managementserver” scope to the OIDC client we created ? (And also : How can I remove the “management” scope ?)

You can use the code snippet provided to modify the client. As long as you provide the same client id the client will be updated with the data given. So in this case change the management scope to managementserver scope and run the script and your client should be updated.

To query the clients you can use this script:

# Get the access token
$response = Invoke-WebRequest -Uri "http://localhost/idp/connect/token" -Method Post -Body @{
    grant_type = "windows_auth"
    scope = "write:client"
    client_id = "winauthclient"
} -UseDefaultCredentials
$accessTokenContent = $response.Content
$accessToken = ($accessTokenContent | ConvertFrom-Json).access_token
 
# Query clients 
$response = Invoke-RestMethod -Method Get -Uri "http://localhost/idp/api/clients" -Headers @{
    Authorization = "Bearer $accessToken"
} 
 
# Output the response
$response | Select-Object -Property ID, ClientId, ClientName, ClientScopes, ClientRedirectUris