Can Authorization be done using api calls only, and not involve the user's browser?

For the authorization step when using the SkyApi, I see there is an "Authorization 'Code Flow" and an "Implicit Flow". Both ways involve interaction with the users browser. Is there a way to authorize strictly using api calls?

Comments

  • Mina Mistry
    Mina Mistry Blackbaud Employee
    Seventh Anniversary Kudos 2 Name Dropper Participant

    Hi @Brian Gaski

    For some quick background - SKY APIs operate in the context of a user identity in order to allow our customers to control the surface area of what the user identity can see/do (because customers, not Blackbaud, define security roles and permissions for users). That identity can be a human user, or a service account created explicitly for the purpose of the integration. In either case, we treat the consenting identity as the source of the truth for the permissions we enforce.

    To address the server to server use case, we have a headless/unattended sample on github that can make API requests without having to get an OAuth token via the typical interactive UI prompt. A server to server app can make calls as long as there is a one-time UI prompt typically done in some sort of setup or config experience for an integration. After that one-time OAuth interactive prompt, the integration would store the refresh token securely and there would be no need for any additional user interaction. This process is also described in this community post and is one approach to achieve this use case.

    Another option to be aware of is the use of a tool like Postman to go through the initial OAuth flow to get an access token (and refresh token). Postman can be configured to essentially "impersonate" the OAuth application (client ID/secret) for the purposes of acquiring the initial token. This only works if the developer is also an application user. There are several community posts about this approach too, such as this or this.

    Hope this helps, let us know if you have any other questions.

    Thanks.

  • @Mina Mistry
    Worth pointing out this relies on manual intervention if the refresh token expires or somehow gets rejected (effectively going through this process again to get a starting token). Pretty nasty stuff in a server to server setup!

  • @Mina Mistry

    Is this the only server-to-server solution? It feels like there is a lot of room for failure to store the refresh token in json. This feels like a cheap workaround.

    I'm a bit shocked that this is the only solution.

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 Raiser's Edge NXT Fall 2025 Product Update Briefing Badge

    @Derrick Planz
    wouldn't call it a “cheap” workaround as I have seen any RESTful API does authentication token in this same manner. It is just one of many ways to do things and is what Blackbaud selected to do for security.

    For us user/developer, we can only work within the parameters set for us by the API provider.

    I did the postman method to get inital auth token (expires in 60minutes) and refresh token (expires in 365 days), stored them both in a secure location within my sharepoint environment. I have an automation that uses the refresh token every 59 minutes to get new set of auth token and new refresh token (good for a new 365 days).

    Another method is to store the auth token and refresh token and only when needed, call the refresh token API to get new auth token for use. This is not ideal since if you didn't make a call in 365 days, then even the refresh token expires and can't be used.

    If you do not like having automation to refresh token every 59 min nor want to risk refresh token expiring, another mid-ground way is to do daily/weekly/monthly check on the refresh token to see if it is expiring in the coming day/week/month and refresh it only then.

    Even though the multiple system “outage” situation in the past months, I have not had issue where refresh token does not work to get a new set of auth token/refresh token. the refresh automation has been working for over 7 months now.

  • @Alex Wong
    Hey Alex! Appreciate the response. I think this solution feels like forcing a square peg in a round hole. Yes, I've used and built RESTful APIs that use this `authorization_code` flow. However, that was for scenarios where there was a UI and the API was there for data retrieval to support the UI.

    The scenario being described is a machine-to-machine scenario. OAuth2 has support for this scenario. It's called the `client_credentials` flow. It appears that the Sky API does not support this flow. That's very disappointing, and I'd say it feels rather short sighted. Maybe not for all of the Sky API, but for Merchant Services, which is a payment processor, only supporting `authorization_code` feels like a miss. I'm curious if there are plans to add support for the `client_credentials` flow?

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 Raiser's Edge NXT Fall 2025 Product Update Briefing Badge

    @Nick Trentacoste
    I don't work for Blackbaud, just a client that uses SKY API. So I can't help answer if there are plans to add certain support or not.

    @Ben Wong might be able to shine some light here from Blackbaud perspective.

    You can also make the suggestion in IdeaBank.

  • Ben Wong
    Ben Wong Blackbaud Employee
    Tenth Anniversary Kudos 3 Name Dropper Participant

    @Nick Trentacoste @Alex Wong we don't currently have plans to support the OAuth 2.0 client credentials grant type in SKY API.

    While the authorization code flow isn't ideal for your scenario, we know that there are a lot of developers who have been successful using it with the Payments API using the headless data sync example. We also extended the lifespan of refresh tokens and introduced the ability to preserve the refresh token value so that it can be used across multiple independent threads.

    Having said that, I'm always interested in how we can make things easier without compromising security,

  • @Ben Wong
    Hey Ben. Thanks for the response. Disappointing to hear that there are no plans to support client_credentials grant type. And I'm not sure I'd agree that it's a less secure option. In any case, can you provide any information as to why the only grant type is authorization_code? What was the use case for transacting a credit card and requiring a user to have an account with Blackbaud AND further grant permission? If I were to use Stripe for example, there would be no such requirement?

  • Ben Wong
    Ben Wong Blackbaud Employee
    Tenth Anniversary Kudos 3 Name Dropper Participant

    @Nick Trentacoste Up until April last year, SKY API supported implicit flow in addition to authorization code flow. However, we deprecated implicit flow (now considered legacy) and introduced PKCE as a more secure method for public clients. Blackbaud products have a security model based on user permissions which works well for user interactive authorization.

    Our supported grant types have met our requirements so far, for all SKY APIs. I understand it's not ideal for scenarios where users aren't involved, but Payments API developers have been able to workaround it and still be successful. That's why it hasn't been a priority to introduce support for other grant types. However, we'll continue to evaluate OAuth 2.0 grant types and make improvements like how we introduced PKCE last year.

  • @Brian Gaski Just my 2 cents - to add to my several other 2 cents' on this topic - that I too think it's less than ideal that machine-to-machine auth isn't supported by SKY API. Having to insert a human in the flow creates a bundle of unnecessary complexity for very little in the way of additional security (imho). And many other mature, security-conscious products permit it, such as Netsuite. But Blackbaud appears to be unmoved in this stance despite many posts requesting this flow.

    Steve Cinquegrana | CEO and Principal Developer | Protégé Solutions