Sr. Content Developer at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
154833 stories
·
33 followers

DuckDuckGo makes its ‘no-AI’ search engine easier to access as its traffic booms

1 Share
Alternative search engine DuckDuckGo launches 'no AI' web extensions for Chrome and Firefox users.
Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete

Microsoft to unveil new AI models and Windows improvements at Build

1 Share
Text reads “BUILD” written in blocky, pixelated letters with Microsoft’s brand colors.

Microsoft is heading to San Francisco this week in a bid to win back developers at its Build conference. I've been attending Build since the days when Microsoft called it the Professional Developers Conference, and I can't remember a more pivotal moment. As Microsoft continues to reshuffle its entire business around AI, it's moving Build into a smaller, more intimate venue. Trust in Windows and GitHub is at an all-time low, and this is Microsoft's chance to reconnect with developers and outline the future.

Sources tell me that we'll hear about new AI models in Windows, a new reasoning model from Microsoft AI, and a Copilot "super app." But …

Read the full story at The Verge.

Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete

Event Moment: Dona Sarkar on Why Coding Agents Are Leading the AI Era

1 Share

Dona Sarkar explains why coding agents succeed first in AI adoption thanks to structured data, clear validation, and measurable outcomes.

The post Event Moment: Dona Sarkar on Why Coding Agents Are Leading the AI Era appeared first on Cloud Wars.

Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete

Keep the News in the Wayback Machine

1 Share

For nearly 30 years, the Internet Archive’s Wayback Machine has helped preserve the public record.

It has captured more than 1 trillion web pages, documented history in real time, and ensured that journalists, researchers, historians, librarians, and the public can continue to access reporting long after stories are published. From breaking news and investigative journalism to local reporting and public statements, the Wayback Machine has become essential infrastructure for the public’s ability to preserve online news and culture.

Now, that preservation work is under threat.

As reported by Nieman Lab and WIRED, some publishers are blocking the Wayback Machine from preserving their reporting. As a result, some of the most important journalism being produced today may no longer be independently archived for future generations. For details on the publisher blocking, check out our FAQ: Publishers Blocking the Wayback Machine.

In response to these blocks, Fight for the Future has launched an open letter calling on major media organizations to work with the Internet Archive to ensure the news remains preserved and accessible in the Wayback Machine.

Sign the open letter here: https://www.savethearchive.com/NewsLeaders

The letter argues that preserving journalism is not only about access today, but about protecting the historical record itself:

“The freedom of journalists isn’t only the freedom to write, it’s also the freedom to have your work read and remembered for generations to come.”

At a moment when misinformation spreads rapidly, links disappear, websites change, and pressure to alter or erase reporting continues to grow, independent web preservation matters more than ever. The Wayback Machine helps make journalism more resilient by ensuring published reporting can still be referenced, verified, and studied years later.

The campaign also highlights a growing contradiction: while many publishers rely on the Wayback Machine for reporting, research, and fact-checking, some are simultaneously preventing their own journalism from being preserved.

The Internet Archive has long worked collaboratively with publishers and respects requests around access and preservation. The Wayback Machine has been designed for preservation: helping ensure that the historical record of the web is not lost.

If you believe journalism should remain accessible to historians, researchers, educators, and future generations, we encourage you to add your name to the letter.

Sign the open letter here: https://www.savethearchive.com/NewsLeaders

Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete

Stop Pasting Tokens: OAuth2 Login for JetBrains IDE Plugins

1 Share

The moment a plugin needs account data, a simple API call turns into an authentication problem. The bad shortcut is familiar: ask the user to create a personal access token (PAT), make them paste it into settings, and hope it never leaks.

For a JetBrains IDE plugin, use this flow instead: the user clicks the Login button, the browser opens, the provider handles sign-in, the IDE receives a callback, and the plugin stores the token.

At a high level, the plugin will:

  1. Open the provider’s authorization page in the browser.
  2. Receive the OAuth2 callback inside the IDE.
  3. Validate the returned state.
  4. Exchange the authorization code with PKCE.
  5. Store the access token in PasswordSafe.

This post uses GitHub as the OAuth2 provider, but the same shape works elsewhere. Scopes, URLs, token responses, and refresh rules will change.

Sample code: https://github.com/JetBrains/intellij-sdk-docs/tree/main/code_samples/oauth2

The Mental Model

OAuth2 is easier to reason about as hotel key cards.
At check-in, you do not get a master key. You get a card for your room, maybe the elevator or gym. When your stay ends, the card stops working.

That is the useful bit: allowed access, but limited and temporary. An OAuth2 access token works the same way. The user signs in with the provider, and the plugin gets a token for the API access the user approved. The plugin never needs the user’s password.

That approach is better than asking people to paste a long-lived secret into settings. Users stay in the browser login flow they already trust, while the provider keeps control of scopes, expiration, and revocation.

So the goal is simple: get the plugin a limited token without making the user paste one manually. The catch is that a desktop plugin cannot protect a traditional client secret.

Why PKCE Is Part of the Story

In a web app, the server can keep a client secret on the backend. A desktop plugin cannot do that. Anything bundled into the plugin can be inspected.

That is where PKCE comes in. PKCE stands for Proof Key for Code Exchange, and it ties the returned authorization code to the login request that created it.

Before opening the browser, the plugin creates a random code_verifier and sends GitHub a derived code_challenge. Later, when GitHub redirects back with a temporary code, the plugin sends the original verifier to the token endpoint.

GitHub compares the verifier with the earlier challenge. If they do not match, no token. That means the returned code is not enough on its own, which is exactly what we want for a desktop plugin.

The Flow

Here is the full flow:

  1. The user clicks Login with GitHub.
  2. The plugin creates state, code_verifier, and code_challenge.
  3. The plugin opens GitHub’s authorization URL in the browser.
  4. GitHub redirects back to the IDE with state and a temporary code.
  5. The plugin validates state.
  6. The plugin exchanges the code and verifier for an access token.
  7. The plugin stores the token in PasswordSafe and calls the GitHub API.

Where the Flow Lives in Code

The sample code lives in code_samples/oauth2. The flow above is split across four small pieces:

  • plugin.xml registers the settings UI and the local callback handler.
  • AuthConfigurable gives the user the login and logout buttons.
  • AuthRestService handles the request that GitHub sends back to the IDE’s built-in HTTP server.
  • AuthService creates the OAuth2 request, exchanges the code, stores the token, and calls the API.

That split is the main thing to notice. OAuth2 feels messy when everything is described as one big mechanism. In code, it is much easier to follow when each class owns one part of the trip.

Register the UI and Callback

The plugin descriptor registers two things:

  • the settings page
  • the local HTTP callback handler
<extensions defaultExtensionNs="com.intellij">
  <applicationConfigurable
      instance="org.intellij.sdk.oauth2.AuthConfigurable"
      id="org.intellij.sdk.oauth2.AuthConfigurable"
      displayName="My Plugin Auth"/>

  <httpRequestHandler implementation="org.intellij.sdk.oauth2.AuthRestService"/>
</extensions>

applicationConfigurable adds the settings page. httpRequestHandler registers a handler with the IDE’s built-in HTTP server, so a request to /api/myplugin can be routed to AuthRestService. That gives GitHub a local redirect target after browser authorization.

Keep the Settings UI Boring

AuthConfigurable is the settings UI. In the sample, it extends BoundConfigurable, uses the Kotlin UI DSL, and its job is small:

  • if disconnected, show Login with GitHub
  • if connected, show the username and Logout

The panel observes AuthService.state, and the view is a small state switch:

private fun createView(state: AuthState) = panel {
  when (state) {
    is AuthState.Connected -> row("Username") {
      label(state.username ?: "Unknown")
      button("Logout") { authService.logout() }
    }

    is AuthState.Disconnected -> row {
      button("Login with GitHub") { authService.login() }
    }
  }
}

Receive the Browser Redirect

After approval, GitHub redirects back to the IDE’s built-in HTTP server. The callback is handled with the IntelliJ Platform RestService:

http://localhost:<built-in-server-port>/api/myplugin

AuthRestService reads state and code, finds the pending login request, completes it, and returns a small HTML response:

val parameters = urlDecoder.parameters()
val state = parameters["state"]?.firstOrNull()
    ?: return "No authorization state found"
val code = parameters["code"]?.firstOrNull()
    ?: return "No authorization code found"
val callback = service<AuthService>().callbacks.remove(state)
    ?: return "No active OAuth request found"

callback.complete(code)
sendResponse(
  request,
  context,
  response("text/html", Unpooled.wrappedBuffer(HTML_RESPONSE.toByteArray()))
)
return null

After that, AuthService continues the flow by exchanging the code for a token.

Run the Flow

AuthService creates the login request, waits for the callback, and exchanges the returned code:

private suspend fun requestToken(): String {
  val state = UUID.randomUUID().toString()
  val codeVerifier = UUID.randomUUID().toString().padStart(43, '0')
  val callback = CompletableDeferred<String>().also { callbacks[state] = it }

  try {
    BrowserUtil.browse(authorizationUrl(state, codeVerifier))
    return exchangeCodeForToken(callback.await(), codeVerifier)
  } finally {
    callbacks.remove(state)?.cancel()
  }
}

CompletableDeferred is the bridge between the HTTP callback and the coroutine waiting in requestToken(). requestToken() waits on callback.await(), and AuthRestService completes that same object when GitHub redirects back with the code.

The padStart(43, '0') is there because GitHub expects the PKCE verifier to meet the minimum verifier length. Some providers are less strict and may accept a UUID as-is, but GitHub needs the verifier to be at least 43 characters long.

The authorization URL carries both safety checks: state and the PKCE challenge.

private fun authorizationUrl(state: String, codeVerifier: String) = url(
  AUTHORIZATION_URL,
  "client_id" to CLIENT_ID,
  "scope" to SCOPES,
  "state" to state,
  "redirect_uri" to redirectUri,
  "code_challenge" to codeChallenge(codeVerifier),
  "code_challenge_method" to "S256",
)

The challenge is derived from the code verifier:

private fun codeChallenge(codeVerifier: String) =
  DigestUtil.sha256().digest(codeVerifier.toByteArray())
    .let { Base64.getUrlEncoder().withoutPadding().encodeToString(it) }

The actual token exchange is a POST to GitHub’s token endpoint:

private suspend fun exchangeCodeForToken(code: String, codeVerifier: String) =
  withContext(Dispatchers.IO) {
    parseAccessToken(post(tokenUrl(code, codeVerifier), null).readString())
  }

The token request sends back the temporary code and the original verifier:

private fun tokenUrl(code: String, codeVerifier: String) = url(
  ACCESS_TOKEN_URL,
  "client_id" to CLIENT_ID,
  "client_secret" to CLIENT_SECRET,
  "code" to code,
  "redirect_uri" to redirectUri,
  "code_verifier" to codeVerifier,
)

The sample includes a GitHub client secret because GitHub’s OAuth app flow expects one. For a desktop plugin, do not treat that value as secret. PKCE is the useful check here: the returned code is useless without the original verifier.

Store the Token in PasswordSafe

Once the provider returns an access token, store it in PasswordSafe. Regular persistent settings are fine for preferences, but not for access tokens.

The sample uses one credential key:

private val credentials =
  CredentialAttributes(generateServiceName("MyPluginAuth", "OAuthToken"))

On startup, the service restores an existing token if one was saved earlier:

init {
  coroutineScope.launch {
    val token = PasswordSafe.instance.getPassword(credentials) ?: return@launch
    _state.value = AuthState.Connected(fetchUserProfile(token))
  }
}

Storing and clearing go through the same helper:

private fun storeToken(token: String?) =
  PasswordSafe.instance.setPassword(credentials, token)

For a real plugin, use a stable service name. If you support multiple accounts, store one credential per provider account.

Platform sources: PasswordSafe, CredentialStore, and CredentialAttributes.

Calling the API

After login, the rest of the plugin should not care how OAuth2 worked. The sample uses the external org.kohsuke:github-api library and passes the token into GitHubBuilder to fetch the current GitHub username:

private suspend fun fetchUserProfile(token: String): String? =
  withContext(Dispatchers.IO) {
    runCatching { GitHubBuilder().withOAuthToken(token).build().myself.login }
      .onFailure { thisLogger().warn("Failed to fetch user profile", it) }
      .getOrNull()
  }

Keep that boundary in larger plugins too. API code should not know how browser login works.

Wrapping Up

OAuth2 in a plugin is mostly about putting the responsibilities in the right place.

Let the provider handle sign-in. Let the browser handle the user-facing login. Let the IDE receive the callback. Let AuthService deal with the token. And once the token is stored in PasswordSafe, the rest of your plugin can stop caring how the user authenticated.

If you are building something similar, or if you hit an edge case with a provider, bring it to the JetBrains Platform forum.
Good luck!

Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete

We Asked 20 Developers Why They Really Got Into Tech. It Wasn’t the Money.

1 Share

Ask anyone outside the industry why people go into software engineering and they’ll say: good money, remote work. Talk to the developers themselves and you get a different story.

For most of the 20 of our Infobip colleagues we interviewed, it started with genuine curiosity – a need to understand how things work, then build their own. Some caught the bug in childhood, others through gaming. But the thread running through nearly every story is the same: they fell in love with the craft long before they ever thought about the salary.

Josip Antoliš, Senior Principal Engineer, captures this sentiment:

It felt like playing with Lego, just for older kids. It was really about building and experimenting.

If money is the only reason you want to become a developer, you won’t make it

Money is part of the equation, and some developers are honest about it – job security and solid pay were what first pointed them toward the field. There’s nothing wrong with that. But most will tell you it only gets you so far.

Engineering is demanding, constantly evolving, and unforgiving to those who are just going through the motions. The developers we spoke to largely agreed: without a genuine curiosity for the craft, the motivation eventually runs dry, no matter what’s in your bank account.

Olga Koroleva, Staff Software Engineer, explains:

For me, it was not money driven. I just naturally like learning new things.

Not everyone had a master plan. For some of the developers we spoke to, the path into software was less a calling and more a series of small, accidental steps like following friends into a computer science program, or stumbling onto coding in their twenties and realizing they had a knack for logical thinking and breaking problems apart.

What matters less, it turns out, is how you got in. What keeps people thriving is the willingness to keep learning and adapting in a field that never really stands still.

Among younger developers in particular, gaming played a surprisingly direct role – less a hobby, more an early window into how software actually works.

Edvin Teskeredžić, Senior AI Software Engineer, remembers his Counter-Strike days:

We used to play a lot of Counter-Strike, and to play together we had to set up servers. Later we started modifying the game, and only later realized we were actually programming.

In the end, whatever brought them to the field, most engineers find a way to grow into it. As Denis Kranjčec, Staff Engineer, puts it:

I started programming 40 years ago, and money was fine, but it was not the only thing.

The best things about being a developer

When asked what they love most about the job, the answers kept circling back to the same themes.

  • Cracking a hard problem in a clean, elegant way
  • Shipping something that actually makes life easier for people – knowing your code is quietly doing its job out in the world
  • Those rarer moments when a tangle of complex systems finally clicks into place, and what was chaos becomes something that just works

Creativity and problem-solving remain central themes. As Teskeredžić puts it:

I like solving practical problems and applying creative solutions.

Beyond the work itself, the setup matters too – remote work, autonomy, and long uninterrupted stretches to actually think. But as Olga Koroleva puts it, what really keeps people around is simpler than any perk:

The best part is staying curious.

The not-so-good part of a developer’s career

Ask about the downsides and the answers get a lot shorter. One word came up more than any other: meetings. Pointless ones, mostly. The kind that could’ve been an email.

Beyond that, developers highlighted several systemic frustrations that disrupt deep focus:

  • Constant context-switching takes a significant mental toll.
  • Bureaucracy and tedious reporting often fracture the time dedicated to core engineering tasks.
  • Navigating undocumented legacy code and parsing ambiguous logs slows development velocity.

There’s also the relentless pace of change. Kristina Valjak, Engineering Lead, puts it plainly:

The speed of change means you constantly have to learn. You have to sacrifice things. It is not a job you leave at the door.

And then there’s the physical reality: long hours at a screen, tight deadlines, pressure that doesn’t let up. Even in teams doing interesting work, that combination can wear you down.

Would they choose this career again? Absolutely.

When asked if they’d do it all over again, there was barely a pause. Absolutely. 100 percent.

More pros than cons. Almost without exception, these developers would make the same choice and most believe tech still offers something few other industries can match: genuine stability and room to keep growing.

Ivona Škorjanc, Software Engineer, remains highly optimistic:

I would still choose it. It is exciting and I see myself growing in it.

A few said they’d have invested more in the fundamentals early on – the theory, the computer science basics that tend to get skipped in the rush to learn frameworks and ship code. But that’s a minor footnote to a bigger conclusion: this field is hard, and most of them wouldn’t trade it for anything.

Teskeredžić offers a final, inspiring perspective on the profession:

To me, engineers are like real-world wizards. Advanced technology is like magic, and if you can be a wizard for a career, why not.

Even the ones who occasionally miss working with their hands come back to the same answer: they’d choose this path again.

Special thanks to our fellow colleagues at Infobip, the publisher of ShiftMag!

The post We Asked 20 Developers Why They Really Got Into Tech. It Wasn’t the Money. appeared first on ShiftMag.

Read the whole story
alvinashcraft
1 hour ago
reply
Pennsylvania, USA
Share this story
Delete
Next Page of Stories