How Redmine OAuth2 for API applications replaces shared keys
An integration, script or service account that calls the Redmine REST API today usually authenticates with a per-user API key or HTTP basic authentication, and that key often ends up copied into several tools and configuration files. Redmine 6.1 and later support OAuth2 authorization for API applications. This page covers how to register an application, how the authorization flow works and how to move existing integrations off shared keys. The core change is that each application becomes a registered client with its own identity in Redmine, so access can be granted, reviewed and withdrawn for that application without touching the key of the person who set it up.
For the integration owner, the main change is in how credentials reach the application. Instead of pasting a personal key into a cron job or pipeline variable, the application obtains access through the authorization flow that Redmine 6.1 provides. The owner should confirm, in the 6.1 documentation, which Redmine user or permissions the application acts under after authorization, since that determines what the integration can read and change. The owner also needs a clear record of which projects and resources the integration touches, because that list becomes the basis for the access review and for the migration plan.
For the Redmine administrator, two responsibilities stay in place. The REST API must be enabled by an administrator, and the REST API documentation covers that setting separately, so enabling OAuth2 does not replace it. The administrator also becomes the gatekeeper for registering applications, deciding who may register them, reviewing what each one is authorized to do and revoking access when an integration is retired. Before rollout, confirm in the 6.1 documentation where registration is managed, which roles can perform it and how an application's access is removed, because these answers define the operating model the team will run.
The users whose access an application acts under need to know which integrations act on their behalf. Migration should start with an inventory of every shared key in use, including keys embedded in scripts, CI jobs and third-party tools that nobody currently owns. Each key should be mapped to an owner and to a registered application, then moved in a planned order with a tested fallback. Shared keys should be revoked only after the replacement has run successfully through the reporting or release cycles that the integration serves. Teams on a 6.x line should also plan this work alongside their upgrade, because 6.1.x receives only bug fixes and security updates while 7.0.x is the fully supported line.
What you need before registering an OAuth2 application
OAuth2 for the Redmine API depends on the Redmine version, the server configuration and the people who own the decisions. Work through these cards before you register anything, so the application is created on a supported base and its access is approved by the right owner.
Redmine version and support line
OAuth2 for API applications is available from Redmine 6.1 onward. Redmine 7.0.x is the fully supported line and receives new features, bug fixes and security updates, while 6.1.x receives only bug fixes and security updates. Confirm which line your organization runs, because 5.1.x and older releases are unsupported and should be upgraded before any new authorization work begins.
REST API enabled by an administrator
The Redmine REST API must be switched on by an administrator before any API client can call it. Check the administration settings for the API option, and confirm that the core resources your application needs, such as issues, projects, users and time entries, are the ones it will read or write. Record who made the change, since it affects every integration on the instance.
Database and Ruby runtime for the target version
The supported database and Ruby runtime depend on the exact Redmine release you target. Redmine 7.0 runs on Rails 8.1 and supports Ruby 3.2, 3.3, 3.4 and 4.0, but it does not support JRuby. Redmine supports PostgreSQL, MySQL 8.0 to 8.4 with transaction isolation set to READ COMMITTED, SQL Server 2012 or higher, and SQLite, which the installation guide does not recommend for multi-user production use. Confirm the matrix for your release before building the host.
HTTPS on the Redmine host
An OAuth2 authorization flow sends credentials and tokens between the user's browser, the application and Redmine, so the Redmine host must be served over HTTPS with a certificate your clients trust. Check the certificate chain, the redirect addresses you will register, and whether any reverse proxy in front of Redmine passes the original scheme and host correctly. Plain HTTP exposes tokens on the network.
Account that registers applications
Decide which Redmine account will create OAuth2 applications and keep that account under named control. The registering account should be a dedicated, least-privileged user with a documented owner, not a shared administrator login. Confirm in the Redmine documentation for your release which permissions are needed to open the application registration screen, and test that the account can complete the registration without broader rights.
Owner who approves projects and roles
Name one business owner who approves which projects and roles each application can reach. Redmine role-based access control determines what a user can see and change, and an application acts on behalf of users within those limits. Ask the owner to sign off on the project list, the role scope and the review date before registration, and confirm the exact OAuth2 settings screen in the documentation for your release.
How the authorization flow works for API applications
The authorization flow starts with registration, and that step determines what the application can ever request. An administrator or user registers the application in Redmine, and Redmine issues client credentials, a client identifier and a secret, which the application uses when it talks to Redmine. Treat the secret like any other production credential: keep it in a secrets store and out of source control. Give each application its own registration so access can be reviewed and revoked separately. Confirm in the Redmine 6.1 or 7.0 documentation for your chosen version where registration happens and which accounts may perform it on your instance.
Next, the application sends the user to Redmine to grant access. The user signs in, sees the application asking for access, and approves or declines the request. Redmine then returns the user to the application, which obtains a token and uses it to call the REST API. The token acts for the person who approved it, so the approval step is a governance decision, not a formality. Decide who will approve access for each integration. For a shared automation, that is usually a named owner with a documented role. For end-user tools, each person approves their own access. Also plan for what happens when the approver leaves the organization or loses project membership.
The application does not gain its own administrative reach. Each call runs within the permissions of the authorizing user and the project roles that user holds. If that user can view issues in a project but cannot edit them, the application cannot edit issues there, whatever it requests. Role-based access control, tracker permissions and workflow transitions still decide what a call can read or change. Before go-live, review the user's membership and role in every project the integration will touch. A single account with broad membership widens what every integration built on it can do, so keep that account's scope as narrow as the integration allows.
Some details are deliberately left out of this page: the grant types Redmine supports, the rules for redirect URIs, and how long access tokens and refresh tokens remain valid. These can differ between releases, so confirm each one against the documentation for the version you run before writing the client. Test the full flow on a staging instance first. Also confirm that an administrator has enabled the REST API, which is required before any API call works, and check whether your version continues to accept per-user API keys for existing integrations during the transition.
How to register the application and switch the integration to OAuth2
This sequence moves one Redmine API integration from a shared API key to OAuth2 access tokens issued to a registered application. It runs in a non-production environment first, so the team can confirm that token-based access works and is scoped correctly while the shared key stays available for rollback.
Confirm the Redmine version and REST API status
The platform team checks that the Redmine instance runs release 6.1 or later, the line from which OAuth2 for API applications is available, and that an administrator has enabled the REST API. Redmine 7.0.x is the fully supported line, and 6.1.x receives only bug fixes and security updates, so record the exact release number in the change record. Confirm every screen name in the following steps against that release, because menu labels can differ between versions. Done when the release number and the REST API setting are written into the change record and the team has agreed which environment the change applies to.
Register the application in Redmine
An administrator creates an OAuth2 application record in Redmine for the integration, using a name that identifies the integration, its owner and its purpose. Record which access the application requests, and keep the registration on the non-production instance during testing. Find the registration screen in the administration area of your release, and confirm its location before you begin, since it may differ from the documentation you read earlier. Done when the application appears in the list of registered applications with a client identifier and client credentials, and the record shows who created it and when.
Record the client credentials in the secrets store
Store the client identifier and client secret in the team's approved secrets manager, with read access limited to the service that runs the integration and to the operators who maintain it. Do not paste the values into tickets, chat threads or configuration files committed to source control. Give the secret a name that shows the environment, the integration and the owner. Done when the integration's deployment can read the secret from the store, and a review of the secret's access list shows only the named service accounts and operators.
Configure the redirect address to match the application
Enter the callback address that the integration exposes for the authorization response in the application registration. The scheme, host, port and path must match the integration's configuration exactly, because Redmine typically rejects an authorization request whose redirect address is not on the registered list. Use the non-production hostname for this environment. Compare the two values side by side before you save. Done when a test request that starts authorization reaches the Redmine sign-in step without a redirect error.
Run the authorization flow with a test user
Sign in as a dedicated test user who has access to a known test project, then complete the authorization request that the integration starts. Confirm that the user sees the consent prompt for the application and approves it. Afterward, check the audit or log trail, using the location your release and logging setup use, for the authorization event, which should identify both the application and the test user. Done when the token exchange completes and the event appears in that trail with the correct application and user.
Point the integration at the token in non-production
Change the non-production integration to send the access token in place of the shared API key, and keep the shared key in the secrets store so you can roll back. Run two checks with the test user's token. A read of an issue that the test user can see should succeed. A request for an issue in a project the test user cannot access should return a 401 or 403 response, depending on how your release reports the denial. Record both results. Done when both checks behave as described and the audit trail attributes the calls to the test user rather than to the shared key.
Which identities, roles and data the application inherits
This table maps each part of an OAuth2 integration to the Redmine object that decides what the application can do, and sets out what the integration should store and never store. Read each row against your own role definitions, tracker settings and workflows, since those are what Redmine enforces on every call. The main takeaway is that the application can act only within the permissions of the authorizing user, so the integration's access is bounded by that person's project membership.
| Element | What Redmine uses to decide access | Store in the integration | Never store |
|---|---|---|---|
| Registering owner | The account that registers the OAuth2 application in Redmine, which identifies the application, not its permissions | Name of the accountable owner and the registration record reference in your change log | Registration credentials in source code, tickets or shared chat |
| Client credentials | Client ID and client secret identify the application during the token exchange | Client ID and client secret in a secrets vault, with rotation owner recorded | Client secret in configuration files committed to version control |
| Authorizing user | The user who approves access; the application's API calls run with that user's rights | Authorizing user identifier and granted scope in the integration's configuration record | A shared administrator login or key used in place of an individual user |
| Project membership and role | Membership in each project and the role assigned there determine which actions and fields are allowed | Project identifiers the integration needs, mapped to the roles of the authorizing user | Blanket access assumptions that all projects are visible to the integration |
| Tracker and workflow limits | Trackers and workflows restrict which statuses, transitions and fields a role may write on issues | Tracker and status names the integration writes to, checked against the workflow for that role | Workarounds that bypass workflow rules by using administrator rights |
| Resources in scope | Issues, projects, users and time entries are the stable core resources the API exposes, each filtered by the user's permissions | A written list of resources the integration reads or writes, with the reason for each | Access to user records or time entries beyond what the integration's stated purpose requires |
| Token lifetime and refresh | Tokens inherit the authorizing user's access until they expire or are revoked | Token expiry and revocation procedure, with the person who can revoke access | Refresh tokens or access tokens in logs, tickets or unencrypted storage |
Security settings to review for OAuth2 API applications
OAuth2 lets an application call the Redmine API with a token that a named user approves, instead of a shared key that works for anyone holding it. That limits the damage from a leaked credential, but it does not protect against a compromised authorizing user, an overprivileged account or an unmanaged application list. The settings below are the ones to review before an integration goes live.
Exact redirect URI matching
Register each application with the exact callback URLs it uses, including scheme, host, port and path. Loose or wildcard-style redirect patterns can let an attacker send an authorization code to an address they control. Review every registered URI for test hosts, old domains and paths that no longer exist, and confirm in your release how the authorization server compares URIs during the flow.
Client secret storage and rotation
Store the client secret in a secrets manager or in an environment variable the application server can read, and keep it out of source code, tickets and shared wiki pages. Assign a named owner and a rotation date to each application. Confirm how your release lets an administrator regenerate a secret and invalidate the old one, then rehearse rotation on a test instance so the integration recovers cleanly.
Least privilege for the authorizing user
A token acts with the permissions of the user who approved it, so that user's role sets what the application can read and change. Use a dedicated integration user limited to the projects and roles the integration needs, and never a shared administrator. Make sure no one uses that account for interactive work, so its activity traces back to a single integration.
Removing unused applications
Applications registered for pilots, retired scripts or former vendors can keep valid access long after anyone uses them. Review the application list on a fixed schedule, compare it with active integrations, and delete entries that have no owner or recent use. Confirm whether your release records last-used times, so the review does not depend on memory.
TLS on every hop
Serve Redmine over HTTPS, and make sure the authorization redirect, the token exchange and every API call use TLS, including traffic between a reverse proxy and the application. Confirm that clients verify certificates instead of disabling checks, and that tokens never appear in URLs or log lines. Test with the same certificate chain your integrations will use in production.
Audit logging and revocation testing
Confirm which logs your Redmine release writes for authorizations, token issuance and API calls, and where they are stored. Forward them to your central log platform and set retention to match your policy. Before go-live, test revocation: revoke an application's access, confirm that its existing tokens stop working, and record how quickly the change takes effect.
Why OAuth2 calls to Redmine fail and how to fix them
This table lists the most common reasons an application's OAuth2 call to Redmine fails, with the likely cause, the check to run and the fix for each. Work through the rows in order, since the REST API setting and the Redmine version are the quickest checks to rule out. Exact settings and menu paths vary by release, so confirm them in the Redmine documentation for your version before you change production.
| Failure | Likely cause | Check to run | Fix |
|---|---|---|---|
| REST API not enabled | An administrator has not enabled the Redmine REST API, so API requests are refused. | Ask an administrator to confirm the REST API setting is on, then repeat a simple API request. | Enable the REST API in administration settings and retest. Follow the Redmine REST API documentation. |
| Redmine older than 6.1 | OAuth2 for API applications is available from Redmine 6.1, so an older instance has no such authorization flow. | Check the Redmine version on the administration information page. | Upgrade to a supported release, with 7.0 as the fully supported line, following the Redmine upgrade guide. |
| Redirect URI mismatch | The registered redirect URI differs from the one sent, in scheme, host, port or path. | Compare the registered value with the redirect_uri in the authorization request, character by character. | Register the exact callback URL the application uses in each environment, then retest the authorization flow. |
| Client secret copied incorrectly or from the wrong environment | The secret has stray spaces or is truncated, or a staging secret is loaded in production. | Confirm the deployed value matches this environment's secret for this application. | Obtain the correct secret from the application record, store it in that environment's secret store and redeploy. |
| User lacks project membership or role | The user who grants consent is not a project member, or their role lacks the permission the action needs. | Sign in as that user and perform the same action in the web interface, then review the role's permissions. | Add the user to the project with a role that grants the needed permission. Keep roles to the minimum the integration requires. |
| Workflow blocks a status change | The tracker's workflow for that role does not allow the transition from the current status to the requested one. | Review the workflow for the tracker, role and current status in administration, then reproduce the change in the web interface. | Adjust the workflow transitions for that role and tracker, or change the integration to request an allowed status. Test on a copy first. |
| Proxy or TLS headers break the redirect | A reverse proxy ends TLS and forwards plain HTTP, so Redmine builds URLs with the wrong scheme or host. | Compare the scheme and host in generated URLs with the public address, and review forwarded headers at the proxy. | Set the public host and HTTPS scheme in the proxy and Redmine configuration, following the Redmine installation guide, then retest. |
Questions buyers ask about Redmine OAuth2 for API applications
How much effort does moving Redmine API integrations to OAuth2 take?
The effort depends on how many integrations you have, how much custom code they contain, how well they are tested, and when you can make changes. Each integration needs its registered application, its authorization flow and its credential handling changed, and each one must be verified against a test instance before the shared key is retired. A team with a few simple scripts will have a very different job from a team with several custom services that call the API from multiple places. Ask any partner to size the work from a written inventory of your integrations rather than from a general estimate.
Effort drivers to list for a quote:
- Number of integrations and the Redmine resources each one reads or writes
- Custom code, third-party plugins and scheduled jobs that hold shared keys
- Test coverage and the availability of a test Redmine instance
- Change windows and sign-off rules for role and permission changes
Can our own team move Redmine API integrations to OAuth2 without a partner?
Yes, if your team has Redmine administration skills and experience maintaining the integrations that call it. The steps on this page give a starting point: confirm your Redmine version supports OAuth2 for API applications, register each application, move each integration to the authorization flow, test it, and then retire the shared keys. Teams that have not previously changed authentication for production integrations often find the testing and credential cutover take longer than the configuration itself. A partner is most useful when the inventory is large, the integrations are business critical, or the team lacks capacity for the testing.
Skills the team should have in place:
- Redmine administration, including roles and the API settings
- Ownership of each integration's code and its deployment
What do we need to provide before the OAuth2 work starts?
Plan to provide named integration owners, a test instance of Redmine that mirrors your production configuration, access to the secrets store where application credentials will be kept, and a decision-maker who signs off on role and permission changes. Integration owners answer questions about what each integration does and who depends on it. The test instance is where authorization flows and cutover steps are verified without affecting users. Secrets store access lets the work replace shared keys without exposing new credentials in configuration files or tickets. Confirm these items with your team early, because missing access is a common reason work stalls.
How is DeployOpen pricing the OAuth2 migration for Redmine?
DeployOpen does not publish a price list. Each engagement is quoted from a written scope that describes the systems, integrations and deliverables agreed before work begins. The main cost components are an assessment of your current integrations and shared keys, configuration and testing of the OAuth2 setup, migration of each integration onto the new flow, and ongoing support after cutover if you choose it. Assessment and testing are usually sized by your inventory, while migration cost follows the number and complexity of integrations. Ask for a quote that separates one-time work from any recurring support so the two can be compared with an internal plan.
Which parts of the OAuth2 migration cost money once and which recur?
The assessment, configuration, testing and migration of each integration are one-time costs tied to the written scope. Recurring costs come from keeping the setup working after cutover, such as applying Redmine upgrades that touch authentication, reviewing registered applications, rotating credentials and supporting new integrations. Hosting and staff time for your own team also recur. When you request a quote, ask which items are one-time, which are retainers, and which depend on your Redmine upgrade plan, since upgrades can change how authentication behaves.
What should we check before retiring the shared API keys in Redmine?
Before retiring a shared key, confirm that every integration that uses it has been moved to OAuth2 and tested against the test instance. Check the role permissions of each registered application so it can read and write only the resources it needs, and confirm that scheduled jobs, plugins and scripts are included in the inventory. Keep the old key available for a short, agreed rollback period, then remove it from the secrets store and from any configuration files. Record who approved each role change and when the key was removed, so the cutover can be reviewed later.
Does the OAuth2 change depend on our Redmine version?
Yes. OAuth2 for API applications is available from Redmine 6.1 onward, so the first step is to confirm which version you run and whether an upgrade is needed first. Redmine 7.0 is the fully supported line that receives new features and security updates, while 6.1.x receives only bug fixes and security updates. Check the current release notes and the upgrade guide with your Redmine maintainers before scheduling the work, because an upgrade and an authentication change in the same window raise the risk of each.
How DeployOpen works on this
DeployOpen scopes Redmine OAuth2 for API applications as a written, fixed-scope engagement covering registration, the authorization flow and the move of existing integrations off shared API keys. Redmine's REST API is enabled by an administrator, so the work starts with confirming the Redmine line, the integrations in use and who owns each application. Ongoing support is available as a retainer.
How we scope
- The written scope names each Redmine instance, each calling application, and the resources each one reads or writes.
- Scope records which applications currently use shared API keys, and which user account each one acts as.
- Scope confirms the Redmine line in use, since OAuth2 for API applications requires Redmine 6.1 or later.
How we build
- Application registration, redirect targets and client credentials are configured in Redmine and documented per application.
- The authorization flow is built and tested against a staging Redmine before any production application changes.
- Each integration moves off its shared key in a planned cutover, keeping the old key until checks pass.
How we hand over
- Handover includes the registered application inventory, token and scope settings, and runbook steps for each integration.
- Upgrade notes explain the support status of your Redmine line, since 7.0.x is the fully supported line.
- Documentation records client registrations, secrets storage locations and rotation steps, with ownership named for each application.
How we support
- Ongoing support is available as a retainer, with the covered tasks written down before work begins.
- Redmine upgrades are planned against the support status of the line you run, reviewed as releases ship.
- Retainers can include reviewing the OAuth2 client inventory when new applications are added to Redmine.

