Redmine OAuth2 for API applications

Redmine 6.1 and later can authorize API applications with OAuth2 instead of shared keys. This page covers registering applications, the authorization flow, and moving existing integrations safely.

On this page

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

ElementWhat Redmine uses to decide accessStore in the integrationNever store
Registering ownerThe account that registers the OAuth2 application in Redmine, which identifies the application, not its permissionsName of the accountable owner and the registration record reference in your change logRegistration credentials in source code, tickets or shared chat
Client credentialsClient ID and client secret identify the application during the token exchangeClient ID and client secret in a secrets vault, with rotation owner recordedClient secret in configuration files committed to version control
Authorizing userThe user who approves access; the application's API calls run with that user's rightsAuthorizing user identifier and granted scope in the integration's configuration recordA shared administrator login or key used in place of an individual user
Project membership and roleMembership in each project and the role assigned there determine which actions and fields are allowedProject identifiers the integration needs, mapped to the roles of the authorizing userBlanket access assumptions that all projects are visible to the integration
Tracker and workflow limitsTrackers and workflows restrict which statuses, transitions and fields a role may write on issuesTracker and status names the integration writes to, checked against the workflow for that roleWorkarounds that bypass workflow rules by using administrator rights
Resources in scopeIssues, projects, users and time entries are the stable core resources the API exposes, each filtered by the user's permissionsA written list of resources the integration reads or writes, with the reason for eachAccess to user records or time entries beyond what the integration's stated purpose requires
Token lifetime and refreshTokens inherit the authorizing user's access until they expire or are revokedToken expiry and revocation procedure, with the person who can revoke accessRefresh 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.

Moving existing integrations off shared API keys without downtime

The migration succeeds when each integration has its own owner and its own cutover date, not when someone finally switches off the shared key. Start with an inventory of every script, CI job, reporting tool, webhook receiver and spreadsheet that calls the Redmine REST API. For each one, record the key it uses: a shared key, or a personal key belonging to a user who may leave the organization. Also record the projects, trackers and actions (read or write) the integration depends on, because those decide which OAuth2 application registration and grant it will need. Check where each key is stored, including configuration files, CI variables and vault entries, since a key often exists in more places than the team expects.

Group the inventory by owner and by the projects each integration touches. Integrations with the same owner and overlapping projects can often move in the same change window, while integrations that write to customer-facing or regulated projects should wait. Pick one low-risk integration for the pilot, ideally a read-only report. During the pilot, confirm that the new authorization flow obtains and refreshes tokens correctly in your environment, and confirm that the permissions it receives match what the old key allowed. Confirm how Redmine maps granted access to the authorizing user's roles and project memberships, because a mismatch there is easy to miss in a read-only test.

Run the old and new paths in parallel for a defined window. Set the length of that window from your own change process, including how many scheduled runs, month-end jobs and release cycles it must cover, rather than from a figure in this guide. Compare the results of both paths, especially for writes, by checking the records Redmine holds after each run. Use your Redmine, reverse proxy or log pipeline to see which requests still arrive with the shared key. Confirm what your deployment records about API requests, since default logs may not show which key or client made a call. Disable the shared key only after the logs show no remaining use across the full window.

A key used by many scripts is the most common reason cutover slips. Teams cannot find every caller, scheduled jobs run only at intervals, and nobody is sure who owns a forgotten script. Prevent this by naming one owner for each integration in the migration plan. That owner confirms the inventory entry, signs off the cutover, watches the parallel run and decides on rollback. Track each integration as its own item with status, owner and evidence of cutover, so the shared key is disabled only when every item is closed. Where an integration has no clear owner, treat that as a blocker, not as a reason to disable the key early.

Keep the shared key valid until the last integration has moved, and write down what happens if an integration fails after its cutover: who is notified, who can reissue access, and whether the old path can be restored during the window. Test that rollback during the pilot. If your team lacks capacity for the inventory, pilot or parallel comparison, these can be scoped as part of a fixed-scope engagement with written deliverables and an agreed timeline before work starts.

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.

FailureLikely causeCheck to runFix
REST API not enabledAn 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.1OAuth2 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 mismatchThe 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 environmentThe 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 roleThe 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 changeThe 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 redirectA 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.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.