Skip to content

OAuth client

For apps that complete the OAuth redirect flow server-side (confidential or public/PKCE clients), register the OAuth client:

builder.Services.AddArrowLabsOAuthClient(options =>
{
options.BaseUrl = "https://api.arrowlabs.co.uk";
options.ClientId = "your-client-id";
options.ClientSecret = "your-client-secret"; // omit for public (PKCE-only) clients
});

Inject IArrowLabsOAuthClient where you need it.

app.MapGet("/login", (IArrowLabsOAuthClient oauth, HttpContext ctx) =>
{
var pkce = Pkce.Generate();
var state = Guid.NewGuid().ToString("N");
// Stash the verifier + state in the user's session for the callback.
ctx.Session.SetString("pkce_verifier", pkce.Verifier);
ctx.Session.SetString("oauth_state", state);
var url = oauth.BuildAuthorizationUrl(
codeChallenge: pkce.Challenge,
redirectUri: "https://app.example.com/callback",
state: state);
return Results.Redirect(url);
});

2. Handle the callback (exchange the code)

Section titled “2. Handle the callback (exchange the code)”
app.MapGet("/callback", async (string code, string state, IArrowLabsOAuthClient oauth, HttpContext ctx) =>
{
if (state != ctx.Session.GetString("oauth_state"))
return Results.BadRequest("state mismatch");
var result = await oauth.ExchangeCodeAsync(
code,
redirectUri: "https://app.example.com/callback",
codeVerifier: ctx.Session.GetString("pkce_verifier"));
return result switch
{
TokenResult.Success s => Results.Ok(new { s.AccessToken, s.ExpiresIn, s.RefreshToken }),
TokenResult.Failure f => Results.BadRequest(new { f.Error, f.ErrorDescription }),
_ => Results.StatusCode(500),
};
});
// Rotate tokens (the refresh token rotates on every use):
var refreshed = await oauth.RefreshTokensAsync(currentRefreshToken);
// Revoke a refresh token (e.g. on sign-out). Idempotent:
var revoked = await oauth.RevokeTokenAsync(currentRefreshToken);

Both token operations return the same TokenResult union (Success / Failure); transport failures surface as Failure("network_error", …), so there’s a single error path — no try/catch for expected outcomes.

Validating the resulting access tokens in your resource API is a separate concern — see Getting started for AddArrowLabsAuth.