user928112
user928112

Reputation: 582

Authenticating requests to an API based on tokens that originate from a different API

I'm building an API (API 1) that acts as an extension of another API (API 2).

API 1 essentially provides additional functionality that does not exist in API 2.

API 2 contains some core methods that are called by API 1, and also happens to serve as the source of truth for user credentials.

What I'm thinking of doing is this: every time a client authenticates with API 1 (i.e. login), I want to "relay" that call to API 2 to retrieve a bearer token and then pass that back to the requesting client. From that point on, I'd like API 1 to be able to accept/validate that bearer token (which originated from API 2) for any subsequent calls to its own controller methods. How would API 1 actually validate the token if it didn't actually create it?

My first thought is to write a custom handler somewhere in API 1 that somehow asks API 2 to validate the incoming token. Does this approach make sense given what I've described above? If so, how do I get started? I don't know too much about implementing custom OAuth or JWT inside a .NET 5 API, so I need pointers on what steps I'd need to take to implement this.

I apologize if this question is too ambiguous; I've been trying to wrap my head around this for days now and am not sure where to even begin researching a solution, much less implement it.

Upvotes: 2

Views: 1503

Answers (1)

Maxim Zabolotskikh
Maxim Zabolotskikh

Reputation: 3367

You definitely can validate the token issued by API2 in API1. If API2 is some commercial product, like e.g. auth0, all you need to do in API1 (assuming it's a .net core app) is to set up the validation URL. API1-app will get all the validation info from there automatically:

services.AddAuthentication().AddJwtBearer("myscheme", options =>
                {
                    // auth0 authentication
                    options.Audience = configuration["Auth0Settings:ApiIdentifier"];
                    options.Authority = configuration["Auth0Settings:Domain"];
                })

If API2 is your own app, you likely didn't implement all the oauth stuff with discovery URLs etc., but you should know the secret and you can validate the token in API1 yourself:

.AddJwtBearer("myscheme", options =>
                {
                    var jwks = GetJwksKeyFromWhereeverYouStoreThem();

                    var audience = configuration["Custom:Audience"];
                    var domain = configuration["Custom:Domain"];
                    options.Audience = audience;
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidIssuer = domain,
                        ValidateAudience = true,
                        ValidAudience = audience,
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKeys = jwks.Keys,
                        RequireSignedTokens = true,
                        RequireExpirationTime = true,
                        ValidateLifetime = true,
                        ClockSkew = TimeSpan.Zero,
                        ValidAlgorithms = new[] { SecurityAlgorithms.YourAlgorithm, },
                    };
                });

And yes, you could proxy the call from API1 to API2 in order to get the token. You would need however to authenticate your API1-app against your API2-app. Depending on what your API2 is, it could involve special grants to issue tokens on behalf of the end-user (you will be passing username and password to API2).

Having said all this, proxying the authentication IMHO is not a good idea. You potentially lose some security already implemented by the API2 by passing your credentials from API1. In the example of auth0 it involves a password grant, which should be used only by trusted applications. Your client should authenticate against the service that issues the bearer. It may seem good at first to proxy the call, but you loose more than you win (all the changes in API2 will influence your API1, you don't get new security features etc. etc.).

You could also add an API gateway to your setup, implemented e.g. with Ocelot. This will take care of authentication and hide your auth logic from your clients. This is IMHO the best way to go, but is often out of scope. Without a gateway the best setup is when one service issues the tokens and validates them and all other services use these tokens and validate them against the first service.

Upvotes: 1

Related Questions