Open Closed

AD logic issue via Flutter App #10676


User avatar
0
viswajwalith created

We are encountering an issue with trying to use Microsoft AD login flow specifically from the Flutter mobile application, while the same flow is working correctly on the web.

✅ Current Behavior Web: Microsoft AD login and token exchange are working as expected. Mobile: Failing during the authorization code exchange step. 🔍 Issue Details The request is being made to: https://authserver.xxx.com/connect/token

However, on mobile, the server responds with a 400 Bad Request and the following error: unsupported_grant_type 📦 Request Payload (Mobile) grant_type: azure_ad_token client_id: XXX_MobileApp scope: openid profile email offline_access

The Azure AD token is successfully generated on the client side and appears valid (issuer, audience, expiry, etc.).

📄 Relevant Logs #0 AppLogger.i #1 AuthService.loginWithAuthorizationCode 💡 🔑 azure_ad_token CUSTOM GRANT PAYLOAD 💡 👉 grant_type: azure_ad_token 💡 👉 client_id: XXX_MobileApp 💡 👉 scope: openid profile email offline_access 💡 🔍 TOKEN HEADER: {"typ":"JWT","alg":"RS256"} 💡 🔍 TOKEN aud: efce9b27-40cf-4bc0-a9e9-90c412cd6e6f 💡 🔍 TOKEN iss: https://login.microsoftonline.com/... 💡 🔍 TOKEN exp: 2026-05-19 14:12:14 💡 🔍 TOKEN isExpired: false 💡 🌐 Initiating Authorization Code Exchange 💡 Auth Code Exchange response code: 400 AppException: Microsoft AD authorization code exchange failed on the server side detail: {"error":"unsupported_grant_type"} ❓ Clarifications Required

Is azure_ad_token supported as a grant type in the ABP Auth Server configuration?

If not, what is the correct grant type expected for mobile-based Microsoft SSO?

Are there any differences in configuration between web and mobile clients (e.g., client settings, allowed grant types, or scopes)?

Does the mobile client require a different flow (e.g., authorization_code or client_credentials) instead of a custom grant?

Since the same flow is working on the web, it seems there might be a configuration or grant-type mismatch specific to the mobile client.

Please let us know if you need any additional details or provide some pointers.

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

3 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • azure_ad_token is not a grant type supported by ABP’s Auth Server (OpenIddict) out of the box. When /connect/token returns unsupported_grant_type, it means the authorization server doesn’t have that grant enabled/implemented.
    • For mobile-based Microsoft (Azure AD) SSO, the expected OAuth/OIDC approach is typically:
      1. The mobile app signs in against Azure AD using Authorization Code Flow with PKCE and receives an authorization code from Azure AD (not an ABP AuthServer code).
      2. Then your backend either:
        • uses Azure AD as an external login provider (recommended), where the user signs in via the normal ABP UI endpoints (browser-based), or
        • you implement a custom OpenIddict extension grant on the ABP AuthServer to exchange an Azure AD token for an ABP access token (advanced scenario).

    What to do in ABP (recommended / standard)

    1. Configure Azure AD as an external OpenID Connect provider in your ABP AuthServer / Web (tiered: in the AuthServer/IdentityServer project), using AddOpenIdConnect (or AddMicrosoftIdentityWebApp).
    2. In the mobile app, open the ABP AuthServer’s login (hosted UI) in a system browser (or in-app browser with proper redirect handling). This keeps ABP in control of the OpenID Connect flow and cookie/external login pipeline.

    This is why it “works on web”: the web flow is usually going through the interactive external login pipeline, not a custom /connect/token exchange with grant_type=azure_ad_token.

    If you insist on “Azure AD token -> ABP token” (custom grant)

    If your Flutter app already gets an Azure AD token and you want to exchange it at https://authserver.../connect/token, then you must do both:

    1. Implement a custom OpenIddict extension grant on the AuthServer (so the server understands grant_type=azure_ad_token and validates the incoming Azure AD token).
    2. Allow that grant type for the specific OpenIddict client (XXX_MobileApp) in your AuthServer’s data seed (client permissions). Otherwise you’ll get either unsupported_grant_type or unauthorized_client.

    In ABP/OpenIddict, allowed grant types are configured per client during seeding (e.g., adding OpenIddictConstants.GrantTypes.AuthorizationCode, RefreshToken, etc.). Custom grants must also be included there, and the client may need to be re-created/re-seeded if it already exists.

    Web vs Mobile differences (why only mobile fails)

    • Your web client is likely using a client configured for authorization_code (and the external login UI), which ABP supports by default.
    • Your mobile client is using grant_type=azure_ad_token, but:
      • ABP/OpenIddict doesn’t support it by default (server-side missing), and/or
      • the mobile OpenIddict client (XXX_MobileApp) does not have permission for that grant (client-side missing in OpenIddict application configuration).

    Sources

    • https://abp.io/docs/latest/modules/openiddict
    • https://abp.io/community/articles/how-to-use-the-azure-active-directory-authentication-for-mvc-razor-page-applications-4603b9cf
    • https://abp.io/community/articles/lyk87w5l

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    viswajwalith created

    FYI... We are not using OpenIdConnect yet in the solution and using the below code in AuthServer

    context.Services.AddAuthentication().AddMicrosoftAccount(MicrosoftAccountDefaults.AuthenticationScheme, options => { //Personal Microsoft accounts as an example. options.AuthorizationEndpoint = configuration["AzureAd:Instance"] + configuration["AzureAd:TenantId"] + "/oauth2/v2.0/authorize"; options.TokenEndpoint = configuration["AzureAd:Instance"] + configuration["AzureAd:TenantId"] + "/oauth2/v2.0/token"; options.ClientId = configuration["AzureAd:ClientId"]; options.ClientSecret = configuration["AzureAd:ClientSecret"]; });

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    azure_ad_token is not a standard OAuth/OIDC grant type, and ABP/OpenIddict does not register it out of the box. The unsupported_grant_type error you see is returned by the OpenIddict server middleware itself — the request never even reaches ABP's TokenController, because OpenIddict rejects any grant that has not been registered on the server and granted to the client.

    The reason web works but mobile does not is unrelated to the grant type: AddMicrosoftAccount(...) is a cookie-based external login handler used by the browser interactive flow (/Account/Login → redirect to Microsoft → /signin-microsoft callback → /connect/authorize/connect/token with grant_type=authorization_code). It does not register anything on the /connect/token pipeline. So your web client succeeds with the standard authorization_code grant, while your mobile client tries a custom grant that no one ever wired up.

    Flutter should use Authorization Code + PKCE against the ABP AuthServer

    Do not let the Flutter app talk to Azure AD directly. Instead, open a system browser from Flutter pointing at the ABP AuthServer login page, let the user click "Login with Microsoft" (which goes through your existing AddMicrosoftAccount setup), and exchange the resulting authorization code for an ABP access token + refresh token.

    Server-side: no changes needed. The Pro mobile client already has authorization_code + refresh_token granted by default in OpenIddictDataSeedContributor. Just make sure the redirect URI of XXX_MobileApp matches your Flutter app's custom scheme.

    Flutter side, using the flutter_appauth package:

    import 'package:flutter_appauth/flutter_appauth.dart';
    
    const appAuth = FlutterAppAuth();
    
    final result = await appAuth.authorizeAndExchangeCode(
      AuthorizationTokenRequest(
        'XXX_MobileApp',
        'com.yourcompany.yourapp:/oauthredirect', // must match the redirect URI seeded for XXX_MobileApp
        issuer: 'https://authserver.xxx.com',
        scopes: ['openid', 'profile', 'email', 'offline_access'],
      ),
    );
    
    final abpAccessToken = result.accessToken;
    final abpRefreshToken = result.refreshToken;
    

    This reuses the exact same Microsoft external login flow that already works on web, and refresh token rotation comes for free.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 16, 2026, 14:50
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.