4

I'm pretty new to Azure/OAuth2 so apologies if this is a simple problem. My head's spinning though and I'd appreciate some pointers.

I'm developing a command line utility for use in a high performance compute cluster. This utility needs to access a REST API which is secured using Azure's OAuth2 implementation.

I'm struggling to get my head around how my client utility should be getting auth codes. My intended flow looks like this...

  1. User gets a terminal on a random HPC node and invokes client on the command line
  2. Client finds it needs a new access code
  3. Client generates a URL for the user to visit and prints it to terminal
  4. Client starts a server to listen for the code at the redirect URL
  5. User opens a browser on their local machine (NOT the machine the client is running on) and gives credentials
  6. Client receives code via redirect,
  7. Client tears down server and proceeds with the rest of the OAuth2 flow before accessing the API.

I'm falling over between steps 5 and 6. I'm seeing "No reply address is registered for the application" in the browser after providing credentials. I think Azure wants me to specify a reply address in the app registration so it can validate the reply address in the client-generated URL. The problem is, I can't feasibly give one! Here's why...

  1. Terminal only client: Means no GUI browsers on the client machine. I.E. Can't use 'localhost' as a reply address
  2. Thousands of potential client hosts: My client could be invoked on any of the thousands of nodes in our compute cluster. This makes listing all potential redirect URIs in the app's Azure registration unfeasible. I.E. I can't have users consent using a browser on a different machine because then I'd have to insert and maintain a reply address for every host in our cluster!

Is what I'm trying to achieve even possible using Azure? I feel like my flow is either wrong or my use-case unsupported. I've read a bit about a 'device flow' in the OAuth2 spec which looks like it may be useful. However, I haven't seen any indication that Azure supports this.

My next step would be to route all code replies via a proxy with a known, static, URI. This feels like more work than I ought to be doing to get this working though, so wanted to run this past the experts first ;)

Thoughts appreciated!

Thanks,

Mark.

Mark Mellar
  • 271
  • 3
  • 10
  • Did you register your application as a Native Client? Are you using any of our ADAL or MSAL libraries to help you perform authentication? – Shawn Tabrizi Mar 01 '18 at 21:33
  • What is "the Client" in this scenario? – DaniDev Mar 01 '18 at 21:44
  • Thanks for looking Shawn. Yes the app is registered as native, I'm not using either of those libraries however (I'm coding in Go) – Mark Mellar Mar 01 '18 at 21:50
  • DaniDev: I'd say the 'client' was the command line utility, though, as I'm pretty new to OAuth, I'm open to being told I'm wrong ;) – Mark Mellar Mar 01 '18 at 21:51
  • That is what I thought was meant but then your lines 1 and 5 sound like you mean something different? 1.User gets a terminal on a random HPC node and invokes client on the command line 5.User opens a browser on their local machine (NOT the machine the client is running on) and gives credentials If this utility is something that is being invoked by multiple users then it is those users that need to be authenticated not the utility – DaniDev Mar 01 '18 at 22:00
  • 1
    I think what may be throwing you off is that your utility is a client of the WebApi App , BUT, for authentication purposes whatever user/machine (terminal only) is accessing the utility that is the user/client which needs authenticating. – DaniDev Mar 01 '18 at 22:14
  • @DaniDev That makes a lot of sense, thanks! So, I need to figure out how to authenticate the user... then what? Does the user keep some kind of token that they can pass to the utilities they're using, or does the user have to authorize (via Azure) the utility to access the resource on their behalf? I'm getting the feeling I need to go do some more reading. – Mark Mellar Mar 01 '18 at 22:24
  • Just to clarify: Your utility could have its own "hard coded" authentication credentials which would be exchanged without user input, but you still would need to provide a redirectURL served out by your utility – DaniDev Mar 01 '18 at 22:37

2 Answers2

2

It kinda sounds like a case for OAuth Device flow: https://joonasw.net/view/device-code-flow

The flow - a helicopter view

  • App makes HTTP POST to the device code endpoint
  • Gets response with:
    • User code
    • Device code
    • Verification URL
    • Expiry time
    • Polling interval
    • Friendly message
    • Shows message to user so they can open a browser and go to the verification URL
  • App starts polling the token endpoint at the defined polling interval, waits for a 200 OK
  • User opens browser, goes to verification URL, enters the user code
  • User signs in with their account
  • App receives 200 OK with:
    • Access token
    • Refresh token
    • Id token

My blog article has detailed HTTP requests you need to make, but the main point of it is to allow authentication on browserless devices.

juunas
  • 54,244
  • 13
  • 113
  • 149
  • That's fantastic, works like a charm! I'd seen the device flow in the OAuth spec, but couldn't see anything in the Azure docs (still can't find anything on the device endpoint) so assumed it wasn't supported. Your blog helped out a lot! – Mark Mellar Mar 02 '18 at 16:24
  • Good to hear :) – juunas Mar 02 '18 at 17:03
1

For Native Client applications (like the one you are building), you should be using the default redirect URI specified in the documentation.

The redirect_uri of your app, where authentication responses can be sent and received by your app. It must exactly match one of the redirect_uris you registered in the portal, except it must be url encoded. For native & mobile apps, you should use the default value of https://login.microsoftonline.com/common/oauth2/nativeclient.

Hopefully this should resolve your issue!

Shawn Tabrizi
  • 12,206
  • 1
  • 38
  • 69
  • Thanks Shawn, I've been staring at the page you linked for most of today, so thanks for confirming I'm on the right track. I think there's something fundamental I'm not getting here though. – Mark Mellar Mar 01 '18 at 21:57
  • I tried changing my redirect_uri to the specified default and added it as a redirect URL. Visiting the generated /oauth2/authorize URL results in my being redirected to a blank page. I see a code in the redirected URL (progress!). But how am I supposed to route this code back to my client? – Mark Mellar Mar 01 '18 at 22:12
  • You will need capture the Auth Code within your native client to complete the exchange. Nothing around that unfortunately... You might be able to skip the Auth Code flow using the [implicit grant flow](https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-implicit) but it is probably not best practice... Note that in the implicit grant flow, you immediately get the token back from the `authorization` endpoint. – Shawn Tabrizi Mar 01 '18 at 23:14
  • Instead of having the utility expect to receive the code via HTTP, how about I create a simple webapp to redirect to. This webapp would give users a string (derived from the URL args) that they can copy/paste into the stdin of the waiting command line utility. – Mark Mellar Mar 01 '18 at 23:44