BlueByte
AADSTS50011Fixed

Microsoft Entra ID: AADSTS50011, 요청에 지정된 redirect URI 가 앱에 등록된 redirect URI 와 일치하지 않음

작성 Haneul Seo2026년 9월 23일 업데이트14 min

안녕하세요, BlueByte입니다. 사용자가 Sign in with Microsoft 를 누르고 익숙한 로그인 화면에서 올바른 암호를 입력했는데, 앱으로 돌아오지 못하고 Microsoft 오류 페이지를 만납니다. AADSTS50011: The redirect URI 'https://app.contoso.com/signin-oidc' specified in the request does not match the redirect URIs configured for the application '11111111-2222-3333-4444-555555555555'. 계정에도 자격 증명에도 문제가 없습니다. 인증은 끝까지 진행됐고 Entra ID 가 거부한 것은 앱으로 돌아오는 마지막 한 단계뿐입니다. 오늘은 이 오류가 나타나는 문구들, 실제로 불일치를 만드는 원인, 추측 대신 실패한 요청을 읽는 방법, 명령줄로 URI 를 추가하는 방법, 그리고 다음 호스트명에서 같은 일이 반복되지 않게 하는 법까지 하나씩 짚어보겠습니다.

AADSTS50011 의 두 문구와 각 문구가 건네주는 두 가지 사실

Microsoft 의 이 오류 코드 문제 해결 문서는 현재 문구를 이렇게 적고 있습니다.

Error AADSTS50011 - The redirect URI <Redirect URI> specified in the request does not
match the redirect URIs configured for the application <AppGUID>. Make sure the redirect
URI sent in the request matches one added to your application in the Azure portal.
Navigate to https://aka.ms/redirectUriMismatchError to learn more about how to fix this.

오래된 라이브러리나 오래된 테넌트에서는 같은 실패가 예전 용어로 나타납니다. AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application 이고, "reply URL" 은 포털이 예전에 같은 항목을 부르던 이름입니다. 오류 코드 참조 문서는 50011 을 내부 이름으로도 올려 두었습니다. InvalidReplyTo - The reply address is missing, misconfigured, or doesn't match reply addresses configured for the app.

어느 문구든 이 글에서 계속 비교할 두 가지 사실을 함께 줍니다. 앱이 보낸 정확한 URI, 그리고 그것을 대조한 애플리케이션 ID 입니다. 페이지를 닫기 전에 둘 다 복사해 두세요.

실제 불일치를 만드는 것들: 대소문자, 끝 슬래시, 스킴, 포트

Entra 는 인증 요청의 redirect_uri 를 등록된 목록과 문자열로 비교하며, 그 규칙은 redirect URI 문서에 그대로 적혀 있습니다. 현장에서 물리는 것은 이런 항목들입니다.

  • 대소문자를 구분합니다. redirect URI 는 대소문자를 구분하며 실행 중인 애플리케이션 URL 경로의 대소문자와 같아야 합니다. .../abc/response-oidc 는 .../ABC/response-oidc 가 아닙니다.
  • 끝 슬래시는 대칭이 아닙니다. 경로 세그먼트 없이 등록한 URI 는 응답 모드가 query 또는 fragment 일 때 끝에 슬래시가 붙어 돌아옵니다. https://contoso.com 은 https://contoso.com/ 로 돌아옵니다. 반면 경로 세그먼트가 있는 URI 에는 슬래시가 붙지 않습니다.
  • 스킴은 https 여야 합니다. 예외는 localhost 뿐입니다. 문서는 http://contoso.com/abc/response-oidc 를 invalid 로, http://localhost·http://localhost/abc·https://localhost 를 valid 로 표시합니다.
  • 포트를 무시하는 곳은 localhost 뿐입니다. http://localhost:1234/MyApp 과 http://localhost:8080/MyApp 은 같은 것으로 취급된다고 문서화돼 있습니다. 다른 호스트에서는 포트가 비교에 포함되므로 https://app.contoso.com:8443/signin-oidc 와 https://app.contoso.com/signin-oidc 는 서로 다른 URI 입니다.
  • 아예 거부되는 문자가 있습니다. ! $ ' ( ) , ; 는 지원되지 않고, 국제화 도메인 이름도 지원되지 않습니다.
  • 쿼리 파라미터는 대상 계정에 따라 다릅니다. 회사·학교 계정으로 로그인하는 등록에서는 허용되고, 개인 Microsoft 계정용으로 구성된 등록에서는 허용되지 않습니다.

IPv6 루프백 [::1] 도 현재 지원되지 않아, 개발 도구가 127.0.0.1 대신 ::1 에 바인딩하는 머신에서 걸립니다. 이걸 외울 필요는 없습니다. 비교가 생각보다 엄격하다는 뜻이니, 눈으로 훑지 말고 문자열끼리 대조하면 됩니다.

나머지 절반: 맞는 URI 를 틀린 플랫폼에, 또는 틀린 객체에

URI 가 등록에 분명히 들어 있는데도 일치하지 않을 수 있습니다. 등록이 목록을 세 개로 나눠 갖고 있기 때문입니다. Microsoft Graph 의 application 리소스에서 이들은 web(서버에서 렌더링하는 앱), spa(단일 페이지 앱 — JavaScript, Angular, React, Blazor WebAssembly, Vue.js), publicClient(모바일·데스크톱)입니다. Microsoft 의 플랫폼 표가 프레임워크별로 어느 목록에 넣어야 하는지 알려주는데, React 앱의 URI 를 Web 아래 넣어 두는 것이 URI 가 눈에 보이는데도 50011 이 나는 흔한 경로입니다.

두 번째 함정은 어느 객체가 그 값을 갖고 있느냐입니다. 문서는 단호합니다. redirect URI 는 반드시 application 객체에만 추가하고, service principal 에는 절대 넣지 마세요. service principal 객체가 application 객체와 동기화될 때 그 값이 제거될 수 있기 때문입니다. 엔터프라이즈 애플리케이션 쪽에 넣은 URI 는 몇 주 동안 잘 동작하다가 조용히 사라지기도 합니다.

등록을 건드리기 전에 보낸 URI 와 등록된 목록을 대조하기

실패한 /authorize 요청에서 앱이 실제로 보낸 URI 를 꺼내고(브라우저 Network 탭에 남아 있습니다), 등록의 모든 목록을 읽습니다.

python3 -c "import sys,urllib.parse as u; q=u.parse_qs(u.urlparse(sys.argv[1]).query); print(q['redirect_uri'][0])" \
  'https://login.microsoftonline.com/contoso.onmicrosoft.com/oauth2/v2.0/authorize?client_id=11111111-2222-3333-4444-555555555555&response_type=code&redirect_uri=https%3A%2F%2Fapp.contoso.com%2Fsignin-oidc'
 
az ad app show --id 11111111-2222-3333-4444-555555555555 \
  --query "{web: web.redirectUris, spa: spa.redirectUris, publicClient: publicClient.redirectUris, audience: signInAudience}"
https://app.contoso.com/signin-oidc
{
  "audience": "AzureADMyOrg",
  "publicClient": [],
  "spa": [],
  "web": [
    "https://app.contoso.com/signin-oidc/"
  ]
}

여기서 눈으로 읽기를 멈추고 diff 에 맡기세요. 끝의 슬래시 하나는 사람 눈이 가장 잘 건너뛰는 종류입니다.

diff <(printf '%s\n' 'https://app.contoso.com/signin-oidc') \
     <(az ad app show --id 11111111-2222-3333-4444-555555555555 --query "web.redirectUris" -o tsv)
1c1
< https://app.contoso.com/signin-oidc
---
> https://app.contoso.com/signin-oidc/

web 이 비어 있고 spa 에 값이 있다면(또는 그 반대라면) 플랫폼 문제입니다. audience 가 AzureADandPersonalMicrosoftAccount 라면 이 등록에서는 쿼리 파라미터와 와일드카드를 쓸 수 없다는 신호입니다.

az ad app update 로 정확한 문자열을 쓰고, SPA 는 Graph PATCH 로

--web-redirect-uris 는 목록에 덧붙이는 것이 아니라 목록 전체를 교체합니다. 그러니 현재 값을 먼저 읽어서 새 값과 함께 다시 써야 합니다.

az ad app show --id 11111111-2222-3333-4444-555555555555 --query "web.redirectUris" -o tsv
https://contoso-stg.azurewebsites.net/signin-oidc

그다음 남길 URI 전부와 새 URI 를 한 명령에 함께 적습니다. 앞 명령의 출력을 그대로 파이프로 넘기지 말고 직접 나열하세요. 줄에서 빠진 URI 는 등록에서 삭제됩니다.

az ad app update --id 11111111-2222-3333-4444-555555555555 \
  --web-redirect-uris https://contoso-stg.azurewebsites.net/signin-oidc \
                      https://app.contoso.com/signin-oidc

CLI 에는 SPA 목록용 플래그가 없으므로 Microsoft Graph 로 application 객체를 직접 고칩니다. Graph URL 에 들어가는 값은 애플리케이션 ID 가 아니라 object ID 입니다.

OBJ=$(az ad app show --id 11111111-2222-3333-4444-555555555555 --query id -o tsv)
az rest --method PATCH \
  --url "https://graph.microsoft.com/v1.0/applications/$OBJ" \
  --headers "Content-Type=application/json" \
  --body '{"spa":{"redirectUris":["https://app.contoso.com/","https://app.contoso.com/auth"]}}'

변경은 즉시 반영되지 않습니다. Microsoft 의 해결 절차는 저장한 뒤 3~5분 기다렸다가 로그인 요청을 다시 보내라고 하고, 로그인 페이지가 다시 보이지 않으면 브라우저의 암호 캐시를 지우거나 InPrivate 창을 쓰라고 안내합니다. 오류에 찍힌 URI 자체가 원하던 값이 아니었다면, 잘못된 값을 등록하지 말고 애플리케이션 코드나 설정을 고치세요.

실제 사례: 스테이징이 새 호스트명 뒤로 옮겨간 날

스테이징 ASP.NET Core 배포가 https://contoso-stg.azurewebsites.net 에서 https://staging.contoso.com 으로 옮겨가자 로그인이 https://staging.contoso.com/signin-oidc 를 지목하는 AADSTS50011 로 실패하기 시작합니다. 직접 확인해 보면 az ad app show 의 web 에는 https://contoso-stg.azurewebsites.net/signin-oidc 하나뿐이고 spa 와 publicClient 는 비어 있으며 signInAudience 는 AzureADMyOrg 입니다. 명령 한 번으로 플랫폼 함정과 계정 유형 제한이 동시에 지워집니다. URI 가 그냥 등록되지 않은 것입니다. az ad app update 한 번으로 두 URI 를 web.redirectUris 에 함께 쓰고, 4분쯤 기다린 뒤 시크릿 창에서 로그인하면 콜백이 https://staging.contoso.com/signin-oidc?code=... 로 돌아옵니다. 짐작하지 말고 확인하세요. az ad app show --query "web.redirectUris" -o tsv 를 다시 돌려 두 줄이 모두 있는지 보고, 일반 창에서 로그아웃·로그인을 한 번 더 해서 캐시된 로그인 화면이 대신 일해 준 게 아님을 확인합니다.

재발을 막기

환경마다 앱 등록을 따로 두세요. 문서가 권하는 방식이 정확히 이것이고, 그래야 개발용 redirect URI 가 운영 앱에 노출되지 않습니다. 호스트명을 늘리기 전에 한도도 알아 두는 편이 좋습니다. signInAudience 가 AzureADMyOrg 또는 AzureADMultipleOrgs 인 등록은 redirect URI 256개, AzureADandPersonalMicrosoftAccount 는 100개, URI 하나당 256자이며, 이 한도는 올릴 수 없습니다.

서브도메인이 쌓일 때 와일드카드가 답처럼 보이지만 아닙니다. https://*.contoso.com 은 일치한 redirect URI 의 쿼리 문자열과 프래그먼트를 잘라내고, 개인 Microsoft 계정으로 로그인하는 등록에서는 지원되지 않으며, 매니페스트 편집기로만 설정할 수 있습니다. 문서가 제시하는 대안은 공유 redirect URI 하나에 브라우저 저장소의 키를 담은 state 파라미터를 더하는 방식입니다. CSRF 방어를 함께 두고, URL 이나 민감한 값을 state 에 직접 싣지 마세요. 로컬 개발에서는 인터페이스 이름 변경이나 방화벽이 로그인을 깨뜨리지 못하도록 localhost 보다 127.0.0.1 을 쓰고, 포트만 다른 localhost URI 를 여러 개 등록하지 마세요. 로그인 서버가 그중 하나를 임의로 고르므로 경로로 구분해야 합니다.

AADSTS900971·AADSTS700016 과의 차이

AADSTS900971: No reply address provided. 는 요청이 redirect URI 를 아예 싣지 않았다는 뜻입니다. 불일치가 아니라 클라이언트 라이브러리나 설정의 누락이고, 비교할 대상 자체가 없습니다. AADSTS700016 - UnauthorizedClient_DoesNotMatchRequest - The application wasn't found in the directory/tenant. 는 그보다 더 앞에서 실패합니다. authorize URL 의 클라이언트 ID 나 테넌트가 틀렸거나 그 테넌트에서 동의된 적이 없어서, Entra 가 redirect URI 검사까지 가지도 못합니다. 700016 이 보이면 URI 를 하나도 보기 전에 클라이언트 ID 와 테넌트부터 고치세요.

다음에 로그인이 마지막 한 단계에서 죽으면 이 순서를 거꾸로 따라가 보세요. 요청이 어떤 URI 를 실었는지, 앱 유형상 어느 플랫폼 목록에 있어야 하는지, diff 가 두 문자열을 같다고 하는지 본 뒤에야 등록을 손대면 됩니다.

관련 질문

포털에서 URI 를 추가했는데도 계속 실패합니다.

흔한 이유가 셋입니다. Microsoft 절차는 저장 후 3~5분을 기다리라고 하니 안 된다고 단정하기 전에 다시 시도해 보세요. 브라우저가 캐시된 로그인 화면을 재생하고 있을 수 있으니 InPrivate 창을 쓰세요. 그리고 플랫폼을 확인하세요. az ad app show 로 URI 가 앱 유형에 맞는 목록(web, spa, publicClient)에 들어갔는지 보면 됩니다.

https://*.contoso.com 같은 와일드카드를 등록해도 되나요?

단일 테넌트에서 회사·학교 계정으로 로그인하는 등록에 한해, 매니페스트 편집기로만 가능하고, 문서는 강하게 권하지 않습니다. 와일드카드 URI 가 일치하면 redirect URI 의 쿼리 문자열과 프래그먼트가 잘려 나가기 때문입니다. 문서가 제시하는 대안은 공유 redirect URI 하나와 state 파라미터이며, CSRF 방어를 함께 둬야 합니다.

포트도 비교 대상인가요?

localhost 를 뺀 모든 곳에서 그렇습니다. localhost 는 포트 부분이 무시되므로 http://localhost:1234/MyApp 과 http://localhost:8080/MyApp 이 같습니다. 다른 호스트에서는 https://app.contoso.com:8443/signin-oidc 와 https://app.contoso.com/signin-oidc 가 서로 다른 URI 입니다.

로컬 개발에 http 를 써도 되나요?

localhost 라면 됩니다. 리디렉션이 기기를 벗어나지 않으므로 http://localhost/myApp 과 https://localhost/myApp 이 모두 허용됩니다. 문서는 이름보다 127.0.0.1 리터럴을 권하지만, 포털의 Redirect URIs 입력란은 http 루프백 주소를 거부하므로 http://127.0.0.1 URI 는 애플리케이션 매니페스트의 replyUrlsWithType 속성으로 추가해야 합니다.

앱 등록 하나에 redirect URI 를 몇 개까지 넣을 수 있나요?

signInAudience 가 AzureADMyOrg 또는 AzureADMultipleOrgs 면 256개, AzureADandPersonalMicrosoftAccount 면 100개이고, URI 하나당 최대 256자입니다. 문서는 보안상 이 한도를 올릴 수 없다고 밝히며, 더 필요하면 state 파라미터 방식을 쓰라고 안내합니다.

참고 자료

Haneul Seo

Infrastructure engineer · 10+ years running Linux fleets

같은 카테고리 다른 글

5.7.26Fixed

Gmail이 550-5.7.26으로 거부: 도메인의 DMARC 정책 때문에 인증되지 않은 메일이 수신 거부됨

Gmail이 우리 도메인이 직접 게시한 DMARC 정책을 집행한 결과입니다. 메시지가 header From: 도메인 기준으로 SPF·DKIM 정렬을 모두 통과하지 못했고, p=quarantine이나 p=reject 정책이 이를 하드 바운스로 바꿉니다. Authentication-Results 헤더가 어느 검사가 실패했는지 알려주고, SPF·DMARC·DKIM 레코드를 향한 dig 세 번이 원인을 지목합니다. SPF나 DKIM으로 인증하라는 비슷한 문구의 바운스는 정책이 아니라 Gmail의 기본 발신자 요구사항에 걸린 다른 문제입니다.

Gmail / Google Workspace
535 5.7.139Workaround

Exchange Online: 535 5.7.139 Authentication unsuccessful, SmtpClientAuthentication is disabled

smtp.office365.com 으로 메일을 보내던 스캐너·스크립트·앱이 535 5.7.139 로 멈추는 이유는 SMTP AUTH 프로토콜이 테넌트 전체, 해당 메일박스, 또는 Basic 인증을 막는 인증 정책·보안 기본값 중 어딘가에서 꺼져 있기 때문입니다. 문구(Tenant, Mailbox, 'did not meet the criteria')를 읽고 Get-TransportConfig·Get-CASMailbox·Get-AuthenticationPolicy 로 확인한 뒤, 테넌트 전체가 아니라 필요한 메일박스 하나만 엽니다. Basic SMTP AUTH 는 다리일 뿐입니다. Microsoft 는 2026년 12월 말 기존 테넌트에서 기본 비활성화하므로 발신자를 OAuth·High Volume Email·릴레이 커넥터로 옮겨야 합니다.

Exchange Online (Microsoft 365)
Error code: 5003Fixed

Zoom: "Unable to connect" 오류 코드 5003 — 브라우저는 되는데 데스크톱 앱만 Zoom 에 못 붙을 때

오류 5003 은 같은 PC 의 웹 클라이언트는 정상 입장하는데 Zoom 데스크톱 앱이 Zoom 서버와의 연결을 끝내지 못하는 상태입니다. 앱은 브라우저보다 더 많은 것을 필요로 합니다. Zoom 방화벽 문서는 미팅용 TCP 443/8801/8802 와 UDP 3478/3479/8801–8810, 인증서 검증용 CA 호스트 목록을 들고, zoom.us 와 *.zoom.us 를 프록시·SSL 검사에서 제외하라고 권고합니다. 포트 테스트, curl issuer 확인, 앱 내장 Network Connectivity Tool(Ctrl+Alt+Shift+D / Cmd+Option+Shift+D)로 어느 계층이 끊겼는지 보고 그 계층을 고치며, 재설치는 옆자리는 되는데 한 대만 실패할 때 씁니다.

Zoom
Slack cannot connect. / Last updated less than a minute ago…Fixed

Slack: 회사 프록시 뒤에서 뜨는 "Slack cannot connect"와 회색 "Last updated…" 띠

Slack은 채널을 평범한 HTTPS로 불러오지만 새 메시지는 443 포트로 Slack이 이름을 밝힌 wss-*.slack.com 호스트 셋(primary·backup·mobile)에 붙는 지속 WebSocket으로 받습니다. 프록시나 방화벽이 HTTP 쪽은 통과시키고 upgrade는 막으면 — 대개 wss 호스트에 SSL 복호화가 켜져 있거나 허용 목록이 slack.com에서 끝나기 때문에 — 브라우저는 멀쩡해 보이는데 앱은 회색 "Last updated…" 띠나 "Slack cannot connect."를 띄웁니다. 문제의 PC에서 curl 프로브 두 개로 어느 계층이 막혔는지 보고, wss 호스트 세 개를 복호화에서 예외 처리하고, my.slack.com/help/urls의 도메인을 전부 허용한 뒤 my.slack.com/help/test로 확인합니다.

Slack
locked for editingFixed

Word: 문서가 "locked for editing by another user"라며 열리지 않음

Word가 문서의 잠금(owner file)을 발견해 다른 누군가가 열어 두었다고 판단하고 읽기 전용 사본만 제안합니다. 대개는 아무도 열지 않았습니다: 크래시가 잠금을 남겼거나, 숨은 Word 프로세스가 여전히 파일을 쥐고 있는 것입니다. 어느 쪽인지 확인하고 Word 인스턴스를 모두 닫은 뒤 남겨진 ~$ owner file을 삭제하면 문서가 다시 편집 가능하게 열립니다.

Microsoft Word
sync error (red X)Fixed

OneDrive: 동기화 멈춤 — 일시 중지 또는 아이콘의 빨간 X

OneDrive 아이콘의 빨간 원 안 흰색 X나 일시 중지 상태는 동기화 루프가 멈췄다는 뜻입니다 — 파일은 로컬과 클라우드에 안전하지만 둘 사이를 오가지 않습니다. 활동 목록을 읽어 클라이언트 문제인지 특정 파일 문제인지 가른 뒤 OneDrive를 재시작하고, 그래도 안 되면 리셋하세요. 리셋은 동기화 연결을 다시 세울 뿐 파일을 삭제하지 않습니다.

OneDrive