This guide assumes you were on v2.3 or v2.4 of the old-named gem. The basic steps are:
- Update your code to account for the rename
- Update your code to account for breaking changes
All gem users will likely need to follow these steps.
- In general, searching project-wide for
azure_activedirectory_v2
and replacing withentra_id
and, likewise, for the hyphenatedazure-activedirectory-v2
and replacing withentra-id
, will cover a lot of use cases README.md
always included examples with environment variables that were named as illustrations only; these have changed from e.g.AZURE_CLIENT_ID
toENTRA_CLIENT_ID
just for internal consistency, but while renaming your own related environment variables or constants (should you use any) may help with code base understanding and consistency, it's not essential. Those names are part of your code base, not part of code in this gem.
Rename the strategy in your configuration block:
config.omniauth(
:azure_activedirectory_v2,
# ...
)
...becomes:
config.omniauth(
:entra_id,
# ...
)
Depending on how you handle callbacks from OmniAuth, you might need to update routes or controllers handling shared routes to account for the name change. The old callback URL of:
https://example.com/v1/auth/azure_activedirectory_v2/callback
...is now:
https://example.com/v1/auth/entra/callback
Change things like this:
omniauth_authorize_url('resource_name_eg_user', 'azure_activedirectory_v2', scope: '...')
...to this:
omniauth_authorize_url('resource_name_eg_user', 'entra_id', scope: '...')
This change is for UIDs and is the main reason for creating a V3 gem, whether or not it included the Entra name change.
- The UID returned by OmniAuth for a user previously depended upon the
oid
(object ID) returned by Microsoft. As noted in #33 and fixed in #34, this might not be unique and tenant ID (tid
) is supposed to be considered too. - Out-of-box, Entra ID will do this. If you were an Azure ActiveDirectory V2 (old-name gem, version 2.x) user, then you will have been receiving different UIDs based only on the
oid
from Microsoft. - The change of OID might break the connection between a previously-registered and logged in user and a new login as usually, you need to store the OmniAuth UID somewhere alongside or within your User records when a user is "connected to" an external OAuth service such as Entra ID.
You have two options, should the issue affect you (and it almost certainly will).
- If you can determine the tenant IDs for all users in your database, you can just migrate the UIDs. The new UID is just a simple concatenation of tenant ID and object ID, so treating the UID as a string, add the tenant ID as a prefix without any other changes in your migration and things should work fine thereafter.
- Otherwise, you should lazy-migrate:
- As usual, in your OAuth callback handler,
request.env['omniauth.auth'].uid
gives the UID - but now that's the "new" Entra gem's value which includes tenant ID. - If you can find a user with that ID, then all good - they've been migrated already or got connected to Entra after you started using the updated gem
- Otherwise, check
request.env['omniauth.auth'].extra.dig('raw_info', 'oid')
- this gives the value that the old Azure ActiveDirectory V2 gem used as UID - Look up the user with this ID. If you find them, great; remember to migrate their record by updating their stored auth ID to the new
request.env['omniauth.auth'].uid
value. - For better security add something like an indexed boolean column indicating whether or not the user has been thus migrated and only perform old OID lookups on users which have not yet been migrated.
- If the user can't be found by either means, then they've not been connected to your system yet. Your existing handling path for such a condition applies.
- As usual, in your OAuth callback handler,
If your user records contain users that have 'connected' to more than one kind of OAuth provider, then as well as the third party's UID being stored for future logins, you'll most likely have stored the OmniAuth provider name too so that the UID can be looked up in a provider's context (there's no guarantee, of course, that UIDs are unique between providers since they're entirely independent entities with their own strategies for allocating unique IDs).
In that case, you will need to migrate records from the old azure_activedirectory_v2
name to entra_id
. Zero-downtime deployment of this change would be very hard since your codebase would need to update from the Azure ActiveDirectory V2 gem to the Entra ID gem with the migration running simultaneously, so if you need to do such a migration, then you probably should plan for a small maintenance window. At the scheduled time, go into maintenance mode, migrate, deploy, and restore normal service. Even without this, though, the 'worst that can happen' (in theory!) would be temporary user login failures. Either the Entra gem will be causing you to look for a user with an entra_id
provider but the migration to set this hasn't run yet, or the other way round, with the old gem looking for the old provider name but it's already updated.
Suppose you support multiple providers and your User table stores their chosen provider in a column auth_provider
, with their UID in auth_uid
. An (irreversible) database migration might do this:
def up
add_column :users, :migrated_to_entra, :boolean
User
.where(auth_provider: 'azure_activedirectory_v2')
.update_all(
auth_provider: 'entra_id',
migrated_to_entra: false
)
end
def down
raise ActiveRecord::IrreversibleMigration
end
This means the migrated_to_entra
column is only ever false
for existing users that were linked using the V2 gem. Everything else will be at NULL
. Now you lazy-move those users to the new UID format in the code you use to look up a user in your OmniAuth OAuth 2 callback handler, e.g. via a method such as this:
# Here, "raw_info" comes from e.g.:
#
# request.env['omniauth.auth'].extra&.dig('raw_info') || {}
#
def find_user_for_omniauth(auth_provider:, auth_uid:, raw_info:)
found_user = User.find_by(
auth_provider: auth_provider,
auth_uid: auth_uid
)
if found_user.nil? && auth_provider == 'entra_id'
found = User.find_by(
auth_provider: 'entra_id',
auth_uid: raw_info['oid'],
migrated_to_entra: false
)
if found
found.update_columns(
auth_uid: auth_uid,
migrated_to_entra: true
)
end
end
return found_user
end
Once there are no rows with a migrated_to_entra
value of false
for active users, you will be able to drop the column and remove the lazy migration code.
- If you refer to
OmniAuth::Strategies::AzureActivedirectoryV2
at all, then this becomesOmniAuth::Strategies::EntraId
(note lower case "d"). base_azure_url
option renamed to justbase_url
with corresponding rename ofOmniAuth::Strategies::AzureActivedirectoryV2::BASE_AZURE_URL
toOmniAuth::Strategies::EntraId::BASE_URL
.